Flutter, being a fast growing platform for building cross platform applications (Web, iOS, Android) has things to explore every other day. Recently I was working to build a fairly simply application for a client that uses the camera to read QR Code and then via a web service validate the QR Code. You would find the details below.
Starting with the dependencies that I used that have to be updated in the pubspec.yaml
file under the dependencies
.
barcode_scan: ^3.0.1
dio: ^3.0.9
intl: ^0.16.1
barcode_scan
will be used for reading the bar codes and dio
is for webservices. intl
is a dependency of dio
.
After doing the above, give permission for Internet and Camera from the Android Manifest file. The file can be found at android/app/src/main/AndroidManifest.xml
. Right before the closing tag of </manifest>
add the following lines:
<uses-permission android:name=\"android.permission.CAMERA\" />
<uses-permission android:name=\"android.permission.INTERNET\"/>
Firstly start by a new StatefulWidget
which I called as the InvoiceScannerScreen
. The following libraries have to be imported.
import \'package:flutter/material.dart\'; import \'package:flutter/services.dart\'; import \'dart:async\'; import \'dart:io\' show Platform; import \'package:barcode_scan/barcode_scan.dart\'; import \'package:dio/dio.dart\';
Then we start by declaring some variables that will be used as properties and some updated as per the scan results.
This will contain the result after a scan. The property which we use will be RawContent
ScanResult scanResult;
The following are some properties we set for the camera during a scan.
final _flashOnController = TextEditingController(text: \"Flash on\"); final _flashOffController = TextEditingController(text: \"Flash off\"); final _cancelController = TextEditingController(text: \"Cancel\"); var _aspectTolerance = 0.0; var _numberOfCameras = 0; var _selectedCamera = -1; var _useAutoFocus = true; var _autoEnableFlash = false;
The below is a variable that will store the result of the API assuming that it will be a string value.
var _apiResult = \"\"; var _QRValue = \"\";
This final variable defines the possible barcode types during a scan. As of now, the only one enabled is the qr code. The list can be found under the BarcodeFormat
enum.
static final _possibleFormats = BarcodeFormat.values.toList().where((element) => element == BarcodeFormat.qr);
//..removeWhere((e) => e == BarcodeFormat.unknown);
List<BarcodeFormat> selectedFormats = [..._possibleFormats];
Initiating the state by detecting the number of cameras on the device.
@override initState() { super.initState(); Future.delayed(Duration.zero, () async { _numberOfCameras = await BarcodeScanner.numberOfCameras; setState(() {}); }); }
Inside of your build
method past the following scaffold
return Scaffold( appBar: AppBar( title: Text(\'Barcode Scanner Example\'), actions: <Widget>[ IconButton( icon: Icon(Icons.camera), tooltip: \"Scan\", onPressed: scan, ) ], ), body: ListView( scrollDirection: Axis.vertical, shrinkWrap: true, children: <Widget>[ FlatButton( child: Text(\'Scan QR Code\'), onPressed: scan, ), //The QR Code Text(QRValue), //The response got from the result Text(_apiResult) ] ), );
The above scaffold has a FlatButton
that calls the scan
function where most of the actual work is done. Here is the scan
function:
Future scan() async { try { var options = ScanOptions( strings: { \"cancel\": _cancelController.text, \"flash_on\": _flashOnController.text, \"flash_off\": _flashOffController.text, }, restrictFormat: selectedFormats, useCamera: _selectedCamera, autoEnableFlash: _autoEnableFlash, android: AndroidOptions( aspectTolerance: _aspectTolerance, useAutoFocus: _useAutoFocus, ), ); var result = await BarcodeScanner.scan(options: options); setState(() => scanResult = result); //Call the API to validate the Code var resp = await verifyValue(scanResult.rawContent); setState(() { _apiResult = resp; _QRValue = scanResult.rawContent;}); } on PlatformException catch (e) { var result = ScanResult( type: ResultType.Error, format: BarcodeFormat.unknown, ); if (e.code == BarcodeScanner.cameraAccessDenied) { setState(() { result.rawContent = \'The user did not grant the camera permission!\'; }); } else { result.rawContent = \'Unknown error: $e\'; } setState(() { scanResult = result; }); } }
You may notice that there is another function call right before the ending of the try statement. That call is made to call an API by passing the value that was just read from the scanner.
verifyValue(scanResult.rawContent);
This function makes a POST call on the provided API using the dio
library. The body of the function is as follows.
dynamic verifyValue(String QRValue) async{ Response resp = Response(); var dio = Dio(); resp = await dio.post( \'<yourapi>\', data: { \"QRValue\": QRValue }); return resp.data; }
This should allow you to scan the QR code. For iOS reference, please refer to the documentation provided by the barcode_scan
.
Thanks for reading the article.
Leave a Reply