How to Build a Cross-Platform QR Code Scanner with Capacitor
Capacitor is an open source native runtime created by the Ionic team for building Web Native apps. We can use it to create cross-platform iOS, Android, and Progressive Web Apps with JavaScript, HTML, and CSS.1 As an alternative to Cordova, Capacitor delivers the same cross-platform benefits, but with a more modern approach to app development, taking advantage of the latest Web APIs and native platform capabilities.2
In this article, we are going to talk about how to use the capacitor barcode reader plugin to build a QR code scanner using Dynamsoft Barcode Reader (DBR) along with Dynamsoft Camera Enhancer (DCE).
A screenshot of a demo app running on Android:
Links related to Dynamsoft Barcode Reader
Build a QR Code Scanner using Capacitor
Integrate Capacitor with an existing web app
Capacitor can be integrated with existing web apps to add native functionality.
Here, we create a react app first.
npx create-react-app qr-code-scanner
After the app is created, drop Capacitor into it.
cd qr-code-scanner
npm install @capacitor/cli @capacitor/core
npx cap init
Then, we can create projects for Android and iOS.
npm install @capacitor/ios @capacitor/android
npx cap add ios
npx cap add android
Use the following commands to update files after the app is changed:
npm run build
npx cap sync
Use plugins to bring QR code scanning functionality to the app
Plugins in Capacitor enable JavaScript to interface directly with Native APIs.3 A plugin has been created to make it easy to use Dynamsoft Barcode Reader and Dynamsoft Camera Enhancer in a Capacitor app to scan QR codes. Since Dynamsoft Barcode Reader has Android, iOS and JavaScript editions, the plugin also supports Android, iOS and Web. We can test the app on the web browsers first and then make modifications to make it compatible with native platforms.
-
Install the plugin to the web app we just made
npm install capacitor-plugin-dynamsoft-barcode-reader
-
Initialize the plugin when the page is loaded. You may need to apply for a trial license to use DBR from here
let [initialized,setInitialized] = useState(false); useEffect(() => { async function init() { let options = {"license": "license key"} let result = await DBR.initialize(options); if (result) { if (result.success == true) { setInitialized(true); } } } init(); }, []);
-
Add a
Start Scanning
button inApp.js
to use the plugin. The button will be disabled if the plugin is not initialized+ import { DBR } from 'capacitor-plugin-dynamsoft-barcode-reader'; + async function startScan() { + await DBR.startScan(); + } return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> + <button id="scan" onClick={startScan} disabled={!initialized}> + Start Scanning + </button> </header> </div> );
Start the development server to see the results:
npm run start
-
Add a listener to receive the scan results
await DBR.startScan(); + DBR.addListener('onFrameRead', (retObj) => { + onFrameRead(retObj); + });
The
onFrameRead
function handles the results of one frame.import { Toast } from '@capacitor/toast'; async function onFrameRead(retObj){ let results = retObj["results"]; var message = ""; for (let index = 0; index < results.length; index++) { if (index>0){ message = message + "\n"; } const result = results[index]; message = message + result["barcodeFormat"]+": "+result["barcodeText"]; } await Toast.show({ text: message, }); }
The Toast plugin is used to make a toast message. It has to be installed via the following command:
npm install @capacitor/toast npx cap sync
PWA Elements is also needed to enable Toast on the web side, see the guide for more info.
-
Add a
Close
button to stop the scanAdded JSX content:
<div id="controlContainer"> <button className="scanner-control close" onClick={stopScan}> Close </button> </div>
Added function:
async function stopScan(){ try{ await DBR.stopScan(); }catch(e){ alert(e.message); } }
-
Add a
Toggle Torch
button to enable torch/flashlightAdded JSX content:
<button className="scanner-control toggleTorch" onClick={toggleTorch}> Toggle Torch </button>
Added function:
var torchOn = false; //global variable async function toggleTorch(){ try{ let desiredState = true; if (torchOn){ desiredState = false; } await DBR.toggleTorch({"on":desiredState}); torchOn = desiredState; }catch(e){ alert(e.message); } }
Please note that on the web side, only Chrome 59+ on desktop and Android supports flashlight.
The CSS of the Toggle Torch
and Close
button:
.scanner-control{
position: absolute;
z-index: 999;
}
.toggleTorch {
right: 0;
bottom: 0;
height: 25px;
}
.close {
right: 0;
bottom: 25px;
height: 25px;
}
Native Mobile Quicks
On Android and iOS, the plugin uses a native view to show camera preview via Dynamsoft Camera Enhancer. There are several aspects to which we have to pay attention.
-
Add camera permission
Camera permission is required to use the camera.
On Android, DCE handles this for us. We don’t need to do extra configurations.
On iOS, we have to add the following to the
Info.plist
:<key>NSCameraUsageDescription</key> <string>For barcode scanning</string> <key>NSMicrophoneUsageDescription</key> <string>For barcode scanning</string>
-
Display WebView above the CameraView.
Because the native CameraView is in parallel to the WebView, in order to show the CameraView while not blocking the web controls, we have to put the CameraView behind the WebView and make the WebView transparent.
The plugin does this for us. We only need to set the background color of web elements to be transparent.
In
App.js
, add the following code to hide the element with background and display the scanner controls.function showControlAndhideBackground(){ document.getElementsByClassName("App-header")[0].style.display="none"; document.getElementById("controlContainer").style.display="inherit"; } function hideControlAndRevealBackground(){ document.getElementsByClassName("App-header")[0].style.display="flex"; document.getElementById("controlContainer").style.display="none"; }
Use them in the
startScan
andstopScan
functions:async function startScan() { + showControlAndhideBackground(); await DBR.startScan(); DBR.addListener('onFrameRead', (retObj) => { onFrameRead(retObj); }); } async function stopScan(){ try{ await DBR.stopScan(); + hideControlAndRevealBackground(); }catch(e){ alert(e.message); } }
Now, we can build the web app and run it on Android or iOS devices.
For example, here is how to run the app on Android.
npm run build
npx cap open android
Android Studio will be used to open the project. We can debug and release the app with Android Studio.
Modify the runtime settings to scan QR code
Dynamsoft Barcode Reader can read more than 17 barcode formats (EAN13, UPCA, PDF417, QR code, etc). We can modify its settings to scan QR code only.
A JSON template can be used to update the runtime settings of DBR. The following template designates the barcode format to QR code:
{"ImageParameter":{"BarcodeFormatIds":["BF_QR_CODE"],"Description":"","Name":"Settings"},"Version":"3.0"}
We can use initRuntimeSettingsWithString
to update the runtime settings with a template:
let template = "{\"ImageParameter\":{\"BarcodeFormatIds\":[\"BF_QR_CODE\"],\"Description\":\"\",\"Name\":\"Settings\"},\"Version\":\"3.0\"}";
await DBR.initRuntimeSettingsWithString({template: template})
You can learn more about DBR’s runtime settings here.
Ionic React Example
You can learn about how to use the plugin in React in a declarative way by checking out this article: Ionic React QR Code Scanner with Capacitor.
Source Code
https://github.com/xulihang/capacitor-qr-code-scanner