| @@ -53,9 +53,17 @@ When a QR code is recognized, the text identified will be set in 'qrText'. | |||||
| ```dart | ```dart | ||||
| class _QRViewExampleState extends State<QRViewExample> { | class _QRViewExampleState extends State<QRViewExample> { | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | ||||
| var qrText = ""; | |||||
| Barcode result; | |||||
| QRViewController controller; | QRViewController controller; | ||||
| /// Overriding reassemble and pausing the camera | |||||
| /// ensures us that hot reload won't give a black screen | |||||
| @override | |||||
| void reassemble() { | |||||
| super.reassemble(); | |||||
| controller.pauseCamera(); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| @@ -82,7 +90,9 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| Expanded( | Expanded( | ||||
| flex: 1, | flex: 1, | ||||
| child: Center( | child: Center( | ||||
| child: Text('Scan result: $qrText'), | |||||
| child: (result != null) ? | |||||
| Text('Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') | |||||
| : Text('Scan a code'), | |||||
| ), | ), | ||||
| ) | ) | ||||
| ], | ], | ||||
| @@ -1,6 +1,7 @@ | |||||
| package net.touchcapture.qr.flutterqr | package net.touchcapture.qr.flutterqr | ||||
| import android.Manifest | import android.Manifest | ||||
| import android.app.Activity | |||||
| import android.content.pm.PackageManager | import android.content.pm.PackageManager | ||||
| import android.os.Build | import android.os.Build | ||||
| import androidx.annotation.NonNull | import androidx.annotation.NonNull | ||||
| @@ -29,22 +30,24 @@ class FlutterQrPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { | |||||
| } | } | ||||
| private fun onAttachedToV1(registrar: PluginRegistry.Registrar) { | private fun onAttachedToV1(registrar: PluginRegistry.Registrar) { | ||||
| Shared.activity = registrar.activity() | |||||
| registrar.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) | registrar.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) | ||||
| checkAndRequestPermission(null) | checkAndRequestPermission(null) | ||||
| onAttachedToEngines(registrar.platformViewRegistry(), registrar.messenger()) | |||||
| onAttachedToEngines(registrar.platformViewRegistry(), registrar.messenger(), registrar.activity()) | |||||
| } | } | ||||
| /** Plugin registration embedding v2 */ | /** Plugin registration embedding v2 */ | ||||
| override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||||
| onAttachedToEngines(flutterPluginBinding.platformViewRegistry, flutterPluginBinding.binaryMessenger) | |||||
| onAttachedToEngines(flutterPluginBinding.platformViewRegistry, flutterPluginBinding.binaryMessenger, Shared.activity) | |||||
| } | } | ||||
| override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { | ||||
| } | } | ||||
| /** Plugin start for both embedding v1 & v2 */ | /** Plugin start for both embedding v1 & v2 */ | ||||
| private fun onAttachedToEngines(platformViewRegistry: PlatformViewRegistry, messenger: BinaryMessenger) { | |||||
| private fun onAttachedToEngines(platformViewRegistry: PlatformViewRegistry, messenger: BinaryMessenger, activity: Activity?) { | |||||
| if (activity != null) { | |||||
| Shared.activity = activity | |||||
| } | |||||
| platformViewRegistry | platformViewRegistry | ||||
| .registerViewFactory( | .registerViewFactory( | ||||
| "net.touchcapture.qr.flutterqr/qrview", QRViewFactory(messenger)) | "net.touchcapture.qr.flutterqr/qrview", QRViewFactory(messenger)) | ||||
| @@ -116,7 +116,8 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) | |||||
| barcode.decodeContinuous( | barcode.decodeContinuous( | ||||
| object : BarcodeCallback { | object : BarcodeCallback { | ||||
| override fun barcodeResult(result: BarcodeResult) { | override fun barcodeResult(result: BarcodeResult) { | ||||
| channel.invokeMethod("onRecognizeQR", result.text) | |||||
| val code = mapOf("code" to result.text, "type" to result.barcodeFormat.name) | |||||
| channel.invokeMethod("onRecognizeQR", code) | |||||
| } | } | ||||
| override fun possibleResultPoints(resultPoints: List<ResultPoint>) {} | override fun possibleResultPoints(resultPoints: List<ResultPoint>) {} | ||||
| @@ -41,12 +41,20 @@ class QRViewExample extends StatefulWidget { | |||||
| } | } | ||||
| class _QRViewExampleState extends State<QRViewExample> { | class _QRViewExampleState extends State<QRViewExample> { | ||||
| var qrText = ''; | |||||
| Barcode result; | |||||
| var flashState = flashOn; | var flashState = flashOn; | ||||
| var cameraState = frontCamera; | var cameraState = frontCamera; | ||||
| QRViewController controller; | QRViewController controller; | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | ||||
| /// Overriding reassemble and pausing the camera | |||||
| /// ensures us that hot reload won't give a black screen | |||||
| @override | |||||
| void reassemble() { | |||||
| super.reassemble(); | |||||
| controller.pauseCamera(); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| @@ -60,7 +68,10 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| child: Column( | child: Column( | ||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Text('This is the result of scan: $qrText'), | |||||
| if (result != null) | |||||
| Text('Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') | |||||
| else | |||||
| Text('Scan a code'), | |||||
| Row( | Row( | ||||
| mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
| crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
| @@ -177,7 +188,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| this.controller = controller; | this.controller = controller; | ||||
| controller.scannedDataStream.listen((scanData) { | controller.scannedDataStream.listen((scanData) { | ||||
| setState(() { | setState(() { | ||||
| qrText = scanData; | |||||
| result = scanData; | |||||
| }); | }); | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -189,6 +200,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| } | } | ||||
| } | } | ||||
| ``` | ``` | ||||
| @@ -1,3 +1,4 @@ | |||||
| import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:qr_code_scanner/qr_code_scanner.dart'; | import 'package:qr_code_scanner/qr_code_scanner.dart'; | ||||
| @@ -18,12 +19,18 @@ class QRViewExample extends StatefulWidget { | |||||
| } | } | ||||
| class _QRViewExampleState extends State<QRViewExample> { | class _QRViewExampleState extends State<QRViewExample> { | ||||
| var qrText = ''; | |||||
| Barcode result; | |||||
| var flashState = flashOn; | var flashState = flashOn; | ||||
| var cameraState = frontCamera; | var cameraState = frontCamera; | ||||
| QRViewController controller; | QRViewController controller; | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | ||||
| @override | |||||
| void reassemble() { | |||||
| super.reassemble(); | |||||
| controller.pauseCamera(); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| @@ -37,7 +44,11 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| child: Column( | child: Column( | ||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Text('This is the result of scan: $qrText'), | |||||
| if (result != null) | |||||
| Text( | |||||
| 'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') | |||||
| else | |||||
| Text('Scan a code'), | |||||
| Row( | Row( | ||||
| mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
| crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
| @@ -154,7 +165,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| this.controller = controller; | this.controller = controller; | ||||
| controller.scannedDataStream.listen((scanData) { | controller.scannedDataStream.listen((scanData) { | ||||
| setState(() { | setState(() { | ||||
| qrText = scanData; | |||||
| result = scanData; | |||||
| }); | }); | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -26,8 +26,37 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| try scanner?.startScanning(resultBlock: { [weak self] codes in | try scanner?.startScanning(resultBlock: { [weak self] codes in | ||||
| if let codes = codes { | if let codes = codes { | ||||
| for code in codes { | for code in codes { | ||||
| var typeString: String; | |||||
| switch(code.type) { | |||||
| case AVMetadataObject.ObjectType.aztec: | |||||
| typeString = "AZTEC" | |||||
| case AVMetadataObject.ObjectType.code39: | |||||
| typeString = "CODE_39" | |||||
| case AVMetadataObject.ObjectType.code93: | |||||
| typeString = "CODE_93" | |||||
| case AVMetadataObject.ObjectType.code128: | |||||
| typeString = "CODE_128" | |||||
| case AVMetadataObject.ObjectType.dataMatrix: | |||||
| typeString = "DATA_MATRIX" | |||||
| case AVMetadataObject.ObjectType.ean8: | |||||
| typeString = "EAN_8" | |||||
| case AVMetadataObject.ObjectType.ean13: | |||||
| typeString = "EAN_13" | |||||
| case AVMetadataObject.ObjectType.itf14: | |||||
| typeString = "ITF" | |||||
| case AVMetadataObject.ObjectType.pdf417: | |||||
| typeString = "PDF_417" | |||||
| case AVMetadataObject.ObjectType.qr: | |||||
| typeString = "QR_CODE" | |||||
| case AVMetadataObject.ObjectType.upce: | |||||
| typeString = "UPC_E" | |||||
| default: | |||||
| return | |||||
| } | |||||
| guard let stringValue = code.stringValue else { continue } | guard let stringValue = code.stringValue else { continue } | ||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: stringValue) | |||||
| let result = ["code": stringValue, "type": typeString] | |||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | |||||
| } | } | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -6,6 +6,86 @@ import 'package:flutter/services.dart'; | |||||
| typedef QRViewCreatedCallback = void Function(QRViewController); | typedef QRViewCreatedCallback = void Function(QRViewController); | ||||
| enum BarcodeFormat { | |||||
| /// Aztec 2D barcode format. | |||||
| aztec, | |||||
| /// CODABAR 1D format. | |||||
| codabar, | |||||
| /// Code 39 1D format. | |||||
| code39, | |||||
| /// Code 93 1D format. | |||||
| code93, | |||||
| /// Code 128 1D format. | |||||
| code128, | |||||
| /// Data Matrix 2D barcode format. | |||||
| dataMatrix, | |||||
| /// EAN-8 1D format. | |||||
| ean8, | |||||
| /// EAN-13 1D format. | |||||
| ean13, | |||||
| /// ITF (Interleaved Two of Five) 1D format. | |||||
| itf, | |||||
| /// MaxiCode 2D barcode format. | |||||
| maxicode, | |||||
| /// PDF417 format. | |||||
| pdf417, | |||||
| /// QR Code 2D barcode format. | |||||
| qrcode, | |||||
| /// RSS 14 | |||||
| rss14, | |||||
| /// RSS EXPANDED | |||||
| rssExpanded, | |||||
| /// UPC-A 1D format. | |||||
| upcA, | |||||
| /// UPC-E 1D format. | |||||
| upcE, | |||||
| /// UPC/EAN extension format. Not a stand-alone format. | |||||
| upcEanExtension | |||||
| } | |||||
| const _formatNames = <String, BarcodeFormat>{ | |||||
| 'AZTEC': BarcodeFormat.aztec, | |||||
| 'CODABAR': BarcodeFormat.codabar, | |||||
| 'CODE_39': BarcodeFormat.code39, | |||||
| 'CODE_93': BarcodeFormat.code93, | |||||
| 'CODE_128': BarcodeFormat.code128, | |||||
| 'DATA_MATRIX': BarcodeFormat.dataMatrix, | |||||
| 'EAN_8': BarcodeFormat.ean8, | |||||
| 'EAN_13': BarcodeFormat.ean13, | |||||
| 'ITF': BarcodeFormat.itf, | |||||
| 'MAXICODE': BarcodeFormat.maxicode, | |||||
| 'PDF_417': BarcodeFormat.pdf417, | |||||
| 'QR_CODE': BarcodeFormat.qrcode, | |||||
| 'RSS_14': BarcodeFormat.rss14, | |||||
| 'RSS_EXPANDED': BarcodeFormat.rssExpanded, | |||||
| 'UPC_A': BarcodeFormat.upcA, | |||||
| 'UPC_E': BarcodeFormat.upcE, | |||||
| 'UPC_EAN_EXTENSION': BarcodeFormat.upcEanExtension, | |||||
| }; | |||||
| class Barcode { | |||||
| Barcode(this.code, this.format); | |||||
| final String code; | |||||
| final BarcodeFormat format; | |||||
| } | |||||
| class QRView extends StatefulWidget { | class QRView extends StatefulWidget { | ||||
| const QRView({ | const QRView({ | ||||
| @required Key key, | @required Key key, | ||||
| @@ -106,7 +186,16 @@ class QRViewController { | |||||
| switch (call.method) { | switch (call.method) { | ||||
| case scanMethodCall: | case scanMethodCall: | ||||
| if (call.arguments != null) { | if (call.arguments != null) { | ||||
| _scanUpdateController.sink.add(call.arguments.toString()); | |||||
| final args = call.arguments as Map; | |||||
| final code = args['code'] as String; | |||||
| final rawType = args['type'] as String; | |||||
| final format = _formatNames[rawType]; | |||||
| if (format != null) { | |||||
| final barcode = Barcode(code, format); | |||||
| _scanUpdateController.sink.add(barcode); | |||||
| } else { | |||||
| throw Exception('Unexpected barcode type $rawType'); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -117,10 +206,10 @@ class QRViewController { | |||||
| final MethodChannel _channel; | final MethodChannel _channel; | ||||
| final StreamController<String> _scanUpdateController = | |||||
| StreamController<String>(); | |||||
| final StreamController<Barcode> _scanUpdateController = | |||||
| StreamController<Barcode>(); | |||||
| Stream<String> get scannedDataStream => _scanUpdateController.stream; | |||||
| Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; | |||||
| void flipCamera() { | void flipCamera() { | ||||
| _channel.invokeMethod('flipCamera'); | _channel.invokeMethod('flipCamera'); | ||||