If you are using React Native, you can quickly create a camera app with React Native Camera. In addition, React Native Camera component supports barcode scanning, face detection, and text recognition. This article shares how to replace the default barcode reading function with Dynamsoft Barcode Reader for Android.
How to Build a Camera App with React Native Camera
Follow the tutorial to create a new React Native project:
npm install -g react-native-cli react-native init AwesomeProject cd AwesomeProject
Install React Native Camera module:
npm install react-native-camera –save react-native link react-native-camera
Read the documentation to get the code snippet of using RNCamera in App.js.
Build and run the Android camera app:
react-native run-android
You may get the error ‘Could not find play-services-basement.aar’:
Referring to StackOverflow, move jcenter() to the last place in repositories.
How to Integrate Dynamsoft Barcode Reader into React Native Camera
According to the sample code shown in the documentation, by default, we can use Google Mobile Vision to scan barcodes on Android:
<RNCamera <…> onGoogleVisionBarcodesDetected={({ barcodes }) => { console.log(barcodes) }} />
Let’s anatomize the source code and make Dynamsoft Barcode Reader work with the component.
How to return barcode results to JavaScript
Get started with ‘onGoogleVisionBarcodesDetected’.
This is an event used to pass native barcode results from Java to JavaScript. The following code shows how to pack barcode types and values into an event:
@Override public void dispatch(RCTEventEmitter rctEventEmitter) { rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData()); } private WritableMap serializeEventData() { WritableArray barcodesList = Arguments.createArray(); for (int i = 0; i < mBarcodes.size(); i++) { Barcode barcode = mBarcodes.valueAt(i); WritableMap serializedBarcode = Arguments.createMap(); serializedBarcode.putString("data", barcode.displayValue); serializedBarcode.putString("type", BarcodeFormatUtils.get(barcode.format)); barcodesList.pushMap(serializedBarcode); } WritableMap event = Arguments.createMap(); event.putString("type", "barcode"); event.putArray("barcodes", barcodesList); event.putInt("target", getViewTag()); return event; }
How to detect barcodes?
When we set ‘onGoogleVisionBarcodesDetected’ to receive the callback, another property ‘googleVisionBarcodeDetectorEnabled’ will be true in RMCamera.js:
_convertNativeProps(props: PropsType) { const newProps = mapValues(props, this._convertProp); if (props.onBarCodeRead) { newProps.barCodeScannerEnabled = true; } if (props.onGoogleVisionBarcodesDetected) { newProps.googleVisionBarcodeDetectorEnabled = true; }
With @ReactProp annotation, the native setter will be called in CameraViewManager.java:
@ReactProp(name = "googleVisionBarcodeDetectorEnabled") public void setGoogleVisionBarcodeDetecting(RNCameraView view, boolean googleBarcodeDetectorEnabled) { view.setShouldGoogleDetectBarcodes(googleBarcodeDetectorEnabled); }
Hereafter, the instance of the barcode reader will be created in RNCameraView.java:
public void setShouldGoogleDetectBarcodes(boolean shouldDetectBarcodes) { if (shouldDetectBarcodes && mGoogleBarcodeDetector == null) { setupBarcodeDetector(); } this.mShouldGoogleDetectBarcodes = shouldDetectBarcodes; setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText); }
When we start the camera preview, the barcode reader will work if it has been initialized in RNCameraView.java:
@Override public void onFramePreview(CameraView cameraView, byte[] data, int width, int height, int rotation) { boolean willCallGoogleBarcodeTask = mShouldGoogleDetectBarcodes && !googleBarcodeDetectorTaskLock && cameraView instanceof BarcodeDetectorAsyncTaskDelegate; if (willCallGoogleBarcodeTask) { googleBarcodeDetectorTaskLock = true; BarcodeDetectorAsyncTaskDelegate delegate = (BarcodeDetectorAsyncTaskDelegate) cameraView; new BarcodeDetectorAsyncTask(delegate, mGoogleBarcodeDetector, data, width, height, correctRotation).execute(); }
The BarcodeDetectorAsyncTask.java extends AsyncTask. The barcode decoding API runs in the background:
@Override protected SparseArray<Barcode> doInBackground(Void... ignored) { if (isCancelled() || mDelegate == null || mBarcodeDetector == null || !mBarcodeDetector.isOperational()) { return null; } RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation); return mBarcodeDetector.detect(frame); } @Override protected void onPostExecute(SparseArray<Barcode> barcodes) { super.onPostExecute(barcodes); if (barcodes == null) { mDelegate.onBarcodeDetectionError(mBarcodeDetector); } else { if (barcodes.size() > 0) { mDelegate.onBarcodesDetected(barcodes, mWidth, mHeight, mRotation); } mDelegate.onBarcodeDetectingTaskCompleted(); } }
What should we do with Dynamsoft Barcode Reader?
For Dynamsoft Barcode Reader, the detection method and the returned result type are different. Create DynamsoftBarcodeDetectorAsyncTaskDelegate.java:
package org.reactnative.camera.tasks; import com.dynamsoft.barcode.TextResult; public interface DynamsoftBarcodeDetectorAsyncTaskDelegate { void onDynamsoftBarCodeDetected(TextResult[] barcodes, int width, int height); void onDynamsoftBarCodeDetectingTaskCompleted(); }
And DynamsoftBarcodeDetectorAsyncTask.java:
@Override protected TextResult[] doInBackground(Void... ignored) { if (isCancelled() || mDelegate == null) { return null; } TextResult[] results = null; try { mBarcodeReader.decodeBuffer(mImageData, mWidth, mHeight, mWidth, EnumImagePixelFormat.IPF_NV21, ""); results = mBarcodeReader.getAllTextResults(); } catch (Exception e) { e.printStackTrace(); } return results; } @Override protected void onPostExecute(TextResult[] results) { super.onPostExecute(results); if (results != null) { mDelegate.onDynamsoftBarCodeDetected(results, mWidth, mHeight); } mDelegate.onDynamsoftBarCodeDetectingTaskCompleted(); }
Define and use the event onDynamsoftVisionBarcodesDetected:
import React, { Component } from 'react'; import {StyleSheet, Text, View, Dimensions } from 'react-native'; import { RNCamera } from 'react-native-camera'; export default class App extends Component { constructor() { super(); this.state = { barcodeResult: 'No barcode detected.' }; } render() { return ( <RNCamera ref={(ref) => { this.camera = ref; }} style={styles.preview} type={RNCamera.Constants.Type.back} flashMode={RNCamera.Constants.FlashMode.on} permissionDialogTitle={'Permission to use camera'} permissionDialogMessage={'We need your permission to use your camera phone'} onDynamsoftVisionBarcodesDetected={({ barcodes }) => { if (barcodes) { if (barcodes.length == 0) { this.setState({barcodeResult: 'No barcode detected.'}) } else { let text = ''; for (let i in barcodes) { let type = barcodes[i]['type']; let data = barcodes[i]['data']; text += 'Type: ' + type + ', Value: ' + data; } this.setState({barcodeResult: text}) } } else { this.setState({barcodeResult: 'No barcode detected.'}) } }} > <View style={styles.textBg}> <Text style={styles.scanText}>{this.state.barcodeResult}</Text> </View> </RNCamera> ); } } const deviceHeight = Dimensions.get('window').height; const deviceWidth = Dimensions.get('window').width; const styles = StyleSheet.create({ textBg: { width: deviceWidth, height: 100, marginTop: deviceHeight - 100 }, preview: { flex: 1, alignItems: 'center', justifyContent: 'space-between' }, scanText: { color: 'white', textAlign: 'center', fontSize: 20 } });
How to run the app?
When I tried to install the module from the local path, I got the error:
error: bundling failed: Error: Unable to resolve module `react-native-camera` from `F:\react-native-camera\Example\App.js`: Module `react-native-camera` does not exist in the Haste module map
So far, I have not found any workaround for installing Node.js module locally. The only solution is to install react-native-camera to node_modules first:
npm install react-native-camera –save
Then, overwrite the module with my code.
Run the app:
Source Code
https://github.com/yushulx/react-native-camera
The post How to Integrate Dynamsoft Barcode Reader into React Native Camera appeared first on Code Pool.