diff --git a/programming/react-native/user-guide/barcode-reader.md b/programming/react-native/user-guide/barcode-reader.md index 6f47e92e..4f969048 100644 --- a/programming/react-native/user-guide/barcode-reader.md +++ b/programming/react-native/user-guide/barcode-reader.md @@ -70,9 +70,9 @@ In this guide, we will explore the Barcode Reader module of the Dynamsoft Captur ## Build Your Barcode Scanner App -Now you will learn how to create a simple barcode scanner using Dynamsoft Capture Vision SDK. +Let's now walk through the steps needed in order to create a simple barcode scanning React Native project using the Dynamsoft Capture Vision SDK. ->Note: You can get the full source code of a similar project: [Barcode Reader Simple Sample](https://github.com/Dynamsoft/capture-vision-react-native-samples/tree/main/BarcodeReaderSimpleSample) +>Note: If you would like the full source code of the sample that we will walk through, please visit: [Barcode Reader Simple Sample](https://github.com/Dynamsoft/capture-vision-react-native-samples/tree/main/BarcodeReaderSimpleSample) ### Set up Development Environment @@ -86,11 +86,25 @@ Create a new React Native project. npx react-native init SimpleBarcodeScanner ``` ->Note: This sample uses React 17.0.2 and React Native 0.67.2. +>Note: This sample uses React 18.3.1 and React Native 0.75.2. We recommend using the latest of these libraries to make the process as easy as possible. ### Include the Library -Add the SDK to your new project. Once the SDK is added, you will see a reference to it in the **package.json**. +First thing we need to do is to add the SDK to the new project. There are two ways in which you can add the SDK + +#### via package.json + +All you need to do is to open the **package.json** which already should be populated with all the core packages needed to run a React Native project. Once that is open, simply add the `dynamsoft-capture-vision-react-native` package to the dependencies as such + +```json +"dynamsoft-capture-vision-react-native": "^1.1.17", +``` + +Once you're done, save the file and run `npm install` or `yarn install` (depending on your preferred package manager) in the project's root directory. + +#### via command-line + +You can also install the package directly from the command-line as such - **yarn** @@ -104,7 +118,7 @@ Add the SDK to your new project. Once the SDK is added, you will see a reference npm install dynamsoft-capture-vision-react-native ``` -For iOS, you can install the necessary native frameworks from cocoapods by running the `pod install` command as below: +For iOS, you must install the necessary native frameworks from cocoapods by running the `pod install` command as below: ```bash cd ios @@ -116,122 +130,148 @@ pod install ### Configure the Barcode Reader -In `App.js`, import the following components: +Now that the pckage is added, it's time to start building the barcode reader component using the DCV API. So the first thing that we will do is create a file named *BarcodeScanner.tsx* which will represent the component that we are going to create and use in the main *App.tsx*. -```js +#### Imports + +Let's first start by importing all of the modules that we need + +```ts import React from 'react'; -import {Text} from 'react-native'; import { - DCVBarcodeReader, - DCVCameraView, - EnumBarcodeFormat + DCVCameraView, + BarcodeResult, + EnumTorchState, + DCVBarcodeReader, } from 'dynamsoft-capture-vision-react-native'; +import {Button, Modal, StyleSheet, Text, TouchableOpacity, View} from 'react-native'; +import { + EnumBarcodeFormat, + EnumDBRPresetTemplate, +} from 'dynamsoft-capture-vision-react-native/js/BarcodeSettings'; +// @ts-ignore +import {TorchButton} from 'dynamsoft-capture-vision-react-native/js/CameraSettings'; ``` -Next in `App.js`, let's define the `state` to your component. In the `state`, add a `results` variable, initialized to `null`. In the following steps, we will store the newly decoded barcodes to `results`. +>Note: Certain modules such as `EnumBarcodeFormat` and `TorchButton` from dynamsoft-capture-vision-react-native need to be imported from the specific folders that they reside in. -```js -class App extends React.Component { - state = { - results: null - }; -} -export default App; -``` +#### Creating the BarcodeScanner.tsx -Next is the `componentDidMount` implementation. First up is adding the code to start barcode decoding: +Next up, we will walk through each of the functions and objects in *BarcodeScanner.tsx* and how they are used in the BarcodeScanner class. Before we start implementing the BarcodeScanner class, let's define a couple of functions and the *option* struct which will go right after the import section -```js -class App extends React.Component { - ... - componentDidMount() { - (async () => { - // Initialize the license so that you can use full feature of the Barcode Reader module. - try { - await DCVBarcodeReader.initLicense("DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9"); - } catch (e) { - console.log(e); - } - // Create a barcode reader instance. - this.reader = await DCVBarcodeReader.createInstance(); - - // Add a result listener. The result listener will handle callback when barcode result is returned. - this.reader.addResultListener((results) => { - // Update the newly detected barcode results to the state. - this.setState({results}); - }); - - // Enable video barcode scanning. - // If the camera is opened, the barcode reader will start the barcode decoding thread when you triggered the startScanning. - // The barcode reader will scan the barcodes continuously before you trigger stopScanning. - this.reader.startScanning(); - })(); +```ts +const mergeResultsText = (results: BarcodeResult[]) => { + let str = ''; + if (results && results.length > 0) { + for (let i = 0; i < results.length; i++) { + str += + results[i].barcodeFormatString + ': ' + results[i].barcodeText + ' \n'; } - ... -} + } else { + str = 'No barcode detected.'; + } + return str; +}; + +const initSettingForVideo = async (reader: DCVBarcodeReader) => { + await reader.resetRuntimeSettings(); + + await reader.updateRuntimeSettings(EnumDBRPresetTemplate.VIDEO_READ_RATE_FIRST); + + let settings = await reader.getRuntimeSettings(); + + // Set the expected barcode count to 0 when you are not sure how many barcodes you are scanning. + // Set the expected barcode count to 1 can maximize the barcode decoding speed. + //settings.expectedBarcodesCount = 0; + + // Set the barcode format to read. + settings.barcodeFormatIds = + EnumBarcodeFormat.BF_ONED | + EnumBarcodeFormat.BF_QR_CODE | + EnumBarcodeFormat.BF_PDF417; + + // Apply the new runtime settings to the barcode reader. + await reader.updateRuntimeSettings(settings); +}; ``` -After implementing `componentDidMount`, `componentWillUnmount` will then include code to stop the barcode decoding and remove the result listener. +- *mergeResultsText*: The purpose of this function is pretty simple - should there be multiple barcode results (meaning there are multiple barcodes in the frame or on the image), this function concatenates them all, with each result being on a separate line. This way, the user sees all of the barcode results at once in the results area. + +- *initSettingForVideo*: This function configures the Barcode Reader settings when the user is live video decoding, which is the core use case of this sample. By default, the sample uses the VIDEO_READ_RATE_FIRST preset template. Afterwards, we define the barcode format(s) that we want the SDK to pick up. This can be changed to which set of formats you want the app to support. + +Next in `App.tsx`, let's now implement the main BarcodeScanner class. Similar to the section above, we will post the entire code block of this class below and break down each of the functions that make it up. + +```ts +class BarcodeScanner extends React.Component { + reader: DCVBarcodeReader | null = null; + state = { + resultsText: '', + isVisible: false, + modalText: '', + }; + + async componentDidMount() { + // Create a barcode reader instance. + this.reader = await DCVBarcodeReader.createInstance(); + + await initSettingForVideo(this.reader); + + this.reader.addResultListener((results: BarcodeResult[]) => { + // Update the newly detected barcode results to the state. + if (!this.ifDecodingFile) { + this.setState({resultsText: mergeResultsText(results)}); + } + }); + + // Enable video barcode scanning. + // If the camera is opened, the barcode reader will start the barcode decoding thread when you triggered the startScanning. + // The barcode reader will scan the barcodes continuously before you trigger stopScanning. + this.reader.startScanning(); + } + + async componentWillUnmount() { + // Stop the barcode decoding thread when your component is unmount. + await this.reader?.stopScanning(); + // Remove the result listener when your component is unmount. + this.reader?.removeAllResultListeners(); + } -```js -class App extends React.Component { - ... - async componentWillUnmount() { - // Stop the barcode decoding thread when your component is unmount. - await this.reader.stopScanning(); - // Remove the result listener when your component is unmount. - this.reader.removeAllResultListeners(); - } - ... } ``` -### Rendering the UI +- *componentDidMount*: This is where the majority of the work goes. First, we start by creating the Barcode Reader instance, followed by configuring the settings via the *initSettingForVideo* method. Each Barcode Reader instance must have an attached results listener to deal with any incoming results - and that is done via the *addResultListener* method. Once all that setup is done, we call the *startScanning* method to open the camera and start barcode reading. Lastly, we set up the navigation options for the open camera page so that the user can go back to the home screen or open the photo library if needed. -Lastly, let's create the `DCVCameraView` UI component in the `render` function. +- *componentWillUnmount*: Now we need to configure what happens when the component unmounts. The main things that we need to do here is to call stopScanning followed by detaching any result listeners from the Barcode Reader instance to make sure that the resources are released properly. -```jsx -class App extends React.Component { - ... - render() { - // Add code to fetch barcode text and format from the BarcodeResult - let results = this.state.results; - let resultBoxText = ""; - if (results && results.length>0){ - for (let i=0;i{this.scanner = ref}} - overlayVisible={true} - > - {/*Add a text box to display the barcode result.*/} - {results && results.length > 0 ? resultBoxText : "No Barcode Detected"} - - ); - } -} + torchState={EnumTorchState.OFF}> + {this.state.resultsText} + + ); + } ``` +While the snippet above does show a very basic version of the UI, it is indeed cuztomizable and so you can add React Native elements in there to make it look how you want it. In this simple snippet, we configure the `DCVCameraView` properties, but we do not set a scan region (which you can learn to do [here](#customizing-the-scan-region)). If no region is set, the entire video frame will be the scan region by default. The other elements that are included in there are used to display the barcode result(s) as they come in. + ### Configure Camera Permissions -You need to set the "Privacy - Camera Usage Description" field in the `Info.plist` file for iOS. If this property is not set, the iOS application will fail at runtime. In order to set this property, you might need to use Xcode and open the corresponding `.xcworkspace` located in the `ios` folder. Once open, you can edit the `Info.plist` to include this property. +You need to set the *Privacy - Camera Usage Description* field in the `Info.plist` file for iOS. If this property is not set, the iOS application will fail at runtime. In order to set this property, you might need to use Xcode and open the corresponding `.xcworkspace` located in the `ios` folder. Once open, you can edit the `Info.plist` to include this property. + +>Note: If there is no *.xcworkspace* in the ios folder, make sure to run `pod install` in the ios folder so that native iOS cocoapods are installed and that will create the *.xcworkspace* file. ### Run the Project @@ -243,6 +283,10 @@ In the command line interface (Powershell recommended), go to your project folde npx react-native run-android ``` +>Note: If you would like to make sure that the project is deployed to a physical Android device that is connected to your computer, you should use the following command: `npx react-native run-android --deviceId=` +> +>To find the device ID of your connected Android phone, you will need to use the *adb* library. Once you have *adb* installed and configured, you simply need to run `adb devices` in the terminal to output a list of the Android devices connected to your machine as well as their corresponding IDs. + #### Run iOS on macOS In the terminal, go to the project folder in your project: @@ -255,9 +299,9 @@ npx react-native run-ios > >- The application needs to run on a physical device rather than a simulator as it requires the use of the camera. If you try running it on a simulator, you will most likely run into a number of errors/failures. >- On iOS, in order to run the React Native app on a physical device you will need to install the [`ios-deploy`](https://www.npmjs.com/package/ios-deploy) library. Afterwards, you can run the react native app from the terminal as such `npx react-native run-ios --device` assuming it's the only device connected to the Mac. ->- Alternatively on iOS, you can simply open the `xcworkspace` of the project found in the `ios` folder using Xcode and run the sample on your connected iOS device from there. The advantage that this offers is that it is easier to deal with the developer signatures for deployment in there. +>- Alternatively on iOS, you can simply open the `.xcworkspace` of the project found in the `ios` folder using Xcode and run the sample on your connected iOS device from there. The advantage that this offers is that it is easier to deal with the developer signatures for deployment in there. ->Note: You can get the full source code of a similar project: [Barcode Reader Simple Sample](https://github.com/Dynamsoft/capture-vision-react-native-samples/tree/main/BarcodeReaderSimpleSample) +>Note: You can get the full source code of the project above: [Barcode Reader Simple Sample](https://github.com/Dynamsoft/capture-vision-react-native-samples/tree/main/BarcodeReaderSimpleSample) ## Customizing the Barcode Reader @@ -265,15 +309,15 @@ There are several ways in which you can customize the Barcode Reader - but what ### Using the settings templates -Dynamsoft barcode reader offers several preset templates for different popular scenarios. To prioritize speed over accuracy, then you will want to use one of the speed templates, choosing the corresponding template for images or video, respectively. And vice versa if you're looking to prioritize read rate and accuracy over speed. For the full set of templates, please refer to [`EnumPresetTemplate`](../api-reference/enum-dbr-preset-template.md). Here is a quick example: +Dynamsoft Barcode Reader offers several preset templates for different popular scenarios. To prioritize speed over accuracy, then you will want to use one of the speed templates, choosing the corresponding template for images or video, respectively. And vice versa if you're looking to prioritize read rate and accuracy over speed. For the full set of templates, please refer to [`EnumPresetTemplate`](../api-reference/enum-dbr-preset-template.md). Here is a quick example: -```js +```ts componentDidMount() { - ... - (async () => { - await this.reader.updateRuntimeSettings(EnumDBRPresetTemplate.VIDEO_SPEED_FIRST); - })(); - ... + ... + (async () => { + await reader.updateRuntimeSettings(EnumDBRPresetTemplate.VIDEO_SPEED_FIRST); + })(); + ... } ``` @@ -283,17 +327,17 @@ The SDK also supports a more granular control over the individual runtime settin ```js componentDidMount() { - (async () => { - // Get the current runtime settings of the barcode reader. - let settings = await this.reader.getRuntimeSettings(); - // Set the expected barcode count to 0 when you are not sure how many barcodes you are scanning. - // Set the expected barcode count to 1 can maximize the barcode decoding speed. - settings.expectedBarcodesCount = 0; - // Set the barcode formats to read. - settings.barcodeFormatIds = EnumBarcodeFormat.BF_ONED | EnumBarcodeFormat.BF_QR_CODE | EnumBarcodeFormat.BF_PDF417 | EnumBarcodeFormat.BF_DATAMATRIX; - // Apply the new settings to the barcode reader. - await this.reader.updateRuntimeSettings(settings); - })(); + (async () => { + // Get the current runtime settings of the barcode reader. + let settings = await this.reader.getRuntimeSettings(); + // Set the expected barcode count to 0 when you are not sure how many barcodes you are scanning. + // Set the expected barcode count to 1 can maximize the barcode decoding speed. + settings.expectedBarcodesCount = 0; + // Set the barcode formats to read. + settings.barcodeFormatIds = EnumBarcodeFormat.BF_ONED | EnumBarcodeFormat.BF_QR_CODE | EnumBarcodeFormat.BF_PDF417 | EnumBarcodeFormat.BF_DATAMATRIX; + // Apply the new settings to the barcode reader. + await reader.updateRuntimeSettings(settings); + })(); } ``` @@ -301,36 +345,36 @@ componentDidMount() { You can also limit the scan region of the SDK so that it doesn't exhaust resources trying to read from the entire image or frame. In order to do this, we will need to use the [`Region`](../api-reference/interface-region.md) interface as well as the [`DCVCameraView`](../api-reference/camera-view.md) component. -First, the region must be defined using the `Region` interface. In this example, we demonstrate how the region is first defined in the `render()` function and then assigned to the `scanRegion` parameter of the `DCVCameraView` component: +First, the region must be defined using the `Region` interface. In this example, we demonstrate how the region is first defined in the `render()` function and then assigned to the `scanRegion` parameter of the `DCVCameraView` component. Please note that in order to show the region, `scanRegionVisible` must be set to true: ```jsx class App extends React.Component { render() { - let barcode_text = ""; - // Define the scan region. - let region = { - regionTop: 30, - regionLeft: 15, - regionBottom: 70, - regionRight: 85, - regionMeasuredByPercentage: true - } - ... - return ( - {this.scanner = ref}} - overlayVisible={true} - scanRegionVisible={true} - scanRegion={region} - > - ... - - ); + // Define the scan region. + let region = { + regionTop: 30, + regionLeft: 15, + regionBottom: 70, + regionRight: 85, + regionMeasuredByPercentage: true + } + + return ( + + {this.state.resultsText} + + ); + } } ```