

Why only Web? Because barcode scanning requires a platform-dependent library. We have libraries for all platforms, but in this article, we’ll only be creating a Web application.
Getting Started






<script defer type="text/javascript" src="datasymbol-sdk-hlp.min.js"></script> <script type="text/javascript" src="ds_create_scanner.js"></script>
Now everything is ready. Let’s continue.
How It Works

in the browser inspector, you’ll see:# flutter build web

A single canvas element takes up the entire browser window. The Flutter framework generates code that renders all its widgets inside this canvas. So how can we easily embed our Barcode Scanner here?

First, let’s populate the "ds_create_scanner.js" file. The rest of the document includes JavaScript and Dart code with embedded comments explaining functions like CreateScanner, embedScanner, and the logic behind rendering and positioning the scanner overlay.
Complete Code of "ds_create_scanner.js" file
var _scannerVariables = { elemScannerDiv: null, DEF_BARCODE_TYPE: ['Code128', 'Code39', 'EAN13', 'UPCA', 'QRCode'], camDevices: null, bDSMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), bIsIOS: ['iPad', 'iPhone', 'iPod'].includes(navigator.platform) || // iPad on iOS detection (navigator.userAgent.includes("Mac") && "ontouchend" in document), camName: ['0, facing back', 'facing back:0', 'back camera'], }; //returns camera idx function SelectBestCamera( camArr, cams ) { var _result = -1; camArr.forEach(function (c) { c.label = c.label.toLowerCase(); }); cams.forEach(function (c) { c = c.toLowerCase(); }); for( var i=0; i < camArr.length; ++i ) { for( var j=0; j < cams.length; ++j ) { if( camArr[i].label.includes(cams[j]) ) return i; } } return _result; } function onDSBarcode (barcodeResult) { for (var i = 0; i < barcodeResult.length; ++i) { var sBarcode = DSScanner.bin2String(barcodeResult[i]); var dr = barcodeResult[i]; dr.strdata = sBarcode; if (typeof _scannerVariables['onBarcode'] === "function") _scannerVariables['onBarcode'](dr); } }; function onDSError(err) { if (typeof _scannerVariables['onError'] === "function") _scannerVariables['onError'](err); } function CreateScanner() { var scannerSettings = { scanner: { key: '', frameTimeout: 100, barcodeTimeout: 1000, beep: true, }, viewport: { id: 'datasymbol-barcode-viewport', width: _scannerVariables.bDSMobile ? null : 640, //null means 100% width }, camera: { resx: 640, resy: 480, }, barcode: { barcodeTypes: _scannerVariables.DEF_BARCODE_TYPE, bQRCodeFindMicro: false, frameTime: 1000, }, }; if( _scannerVariables.camDevices && _scannerVariables.camDevices.length > 0 ) { if( _scannerVariables.bDSMobile || _scannerVariables.bIsIOS ) { var camIdx = SelectBestCamera( _scannerVariables.camDevices, _scannerVariables.camName ); if( camIdx >= 0 ) scannerSettings.camera.id = _scannerVariables.camDevices[camIdx].id; else scannerSettings.camera.facingMode = 'environment'; } //non mobile, select first camera else { scannerSettings.camera.id = _scannerVariables.camDevices[0].id scannerSettings.camera.label = _scannerVariables.camDevices[0].label; } } DSScanner.addEventListener('onBarcode', onDSBarcode); DSScanner.addEventListener('onScannerReady', function () { DSScanner.StartScanner(); }); DSScanner.Create(scannerSettings); } function embedScanner( x, y, width, height ) { _scannerVariables.elemScannerDiv = document.createElement('div'); _scannerVariables.elemScannerDiv.id = 'div-datasymbol-barcode-viewport'; _scannerVariables.elemScannerDiv.style.cssText = 'position:absolute;left:'+x+'px;top:'+y+'px;width:'+width+'px;height:'+height+'px;z-index:100;'; _scannerVariables.elemScannerDiv.innerHTML = ` <div id="datasymbol-barcode-viewport" style='display:block;width:100%;height:480px;font: bold 2em Tahoma;'></div> `; document.body.appendChild(_scannerVariables.elemScannerDiv); DSScanner.addEventListener('onError', onDSError); DSScanner.getVideoDevices(function (devices) { if(devices.length > 0) { _scannerVariables.camDevices = devices.slice(); CreateScanner(); } else { onDSError( {name: 'NotFoundError', message: 'Camera Not Connected'} ); } }, true); // CreateScanner(); } function updateScannerPos(x, y, width, height) { if( _scannerVariables.elemScannerDiv ) { _scannerVariables.elemScannerDiv.style.left = x + 'px'; _scannerVariables.elemScannerDiv.style.top = y + 'px'; _scannerVariables.elemScannerDiv.style.width = width + 'px'; _scannerVariables.elemScannerDiv.style.height = height + 'px'; } } function addScannerCallback(funcName, dsFuncCallback) { if(funcName && funcName.length !=0 && dsFuncCallback != null && (typeof dsFuncCallback === "function") ) _scannerVariables[funcName] = dsFuncCallback; }


"main.dart"
Open the "/lib/main.dart" file of your Flutter project and copy the code provided in the document. It handles:
- The creation of the Flutter UI.
- Interfacing with JavaScript functions (embedScanner, updateScannerPos, addScannerCallback).
- Handling events from the scanner.
- Dynamically positioning and resizing the Barcode Scanner overlay using GlobalKey and Flutter’s rendering pipeline.
- Descriptions of methods and types for interaction between Dart and JavaScript code.
Complete Code of "main.dart" file
import 'dart:math'; import 'package:flutter/material.dart'; import 'dart:js_interop'; extension type DSBarcodeError(JSObject _) implements JSObject { external String name; external String message; } extension type DSBarcodeResultCoord(JSObject _) implements JSObject { external int x; external int y; } extension type DSBarcodeResult(JSObject _) implements JSObject { external int bt; external String type; external JSInt8Array data; external String strdata; external JSArray<DSBarcodeResultCoord> points; external bool barcodeAtPoint; external bool previouslyDecoded; } @JS() external void embedScanner(int x, int y, int width, int height); @JS() external void updateScannerPos(int x, int y, int width, int height); @JS() external void addScannerCallback(JSString funcName, JSFunction dsFuncCallback); void main() { runApp( MyApp() ); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver { final GlobalKey _key = GlobalKey(); bool _firstStart = true; String _strBarcode = ''; //DataSymbol.com Barcode Scanner callback function. Fired when a barcode event occurs. void onDSBarcode (DSBarcodeResult dr) { _strBarcode = dr.strdata; setState( (){} ); } //DataSymbol.com Barcode Scanner callback function. Fired when a scanner error event occurs. void onDSError (DSBarcodeError err) { _strBarcode = '${err.name}, ${err.message}'; setState( (){} ); } Rectangle<int> getBarcodeViewBox() { final RenderBox renderBox = _key.currentContext!.findRenderObject() as RenderBox; final position = renderBox.localToGlobal(Offset.zero); return Rectangle( position.dx.toInt(), position.dy.toInt(), renderBox.size.width.toInt(), renderBox.size.height.toInt() ); } @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeMetrics() { WidgetsBinding.instance.addPostFrameCallback( (timestamp){ Rectangle rc = getBarcodeViewBox(); updateScannerPos( rc.left.toInt(), rc.top.toInt(), rc.width.toInt(), rc.height.toInt() ); }); } void startUpFunction() async { if( _firstStart ) { //Embed and Start DataSymbol.com Barcode Scanner addScannerCallback('onError'.toJS, onDSError.toJS); addScannerCallback('onBarcode'.toJS, onDSBarcode.toJS); Rectangle rc = getBarcodeViewBox(); embedScanner(rc.left.toInt(), rc.top.toInt(), rc.width.toInt(), rc.height.toInt()); } _firstStart = false; } @override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) => startUpFunction()); return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text('Barcode:'), Text( _strBarcode, style: Theme.of(context).textTheme.headlineMedium, ), SizedBox(// Container( key: _key, width: 640, height: 480, //color: Colors.grey[300], child: Text( 'Barcode Scanner Loading ...', ), ), ], ), ), ); } }
A live demo of DataSymbol.com Barcode Scanner in Flutter App is available online:
OnLine demo
A complete Flutter project with the Barcode Scanner can be downloaded here:
Download