From 8b7c23053b4f2cd077694707d2347c5283d67e75 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 18 Feb 2021 20:07:29 +0100 Subject: [PATCH 01/22] Release of v0.3.5 --- CHANGELOG.md | 7 +++++++ pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28af3f6..847a080 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.3.5 +#### Bug fixes +* Fixed QRView opening zoomed in on some devices by adding small delay to updateDimensions(). (#250) +* Changed upc-a to EAN13 on iOS. (#262) +* Fixed null-pointer on BarcodeFormat array on iOS. (#262) +* Added LifecycleEventHandler to dispose(). (#265) + ## 0.3.4 #### Bug fixes * Fixed No barcode view found on Android when calling controller.dispose() (#257) diff --git a/pubspec.yaml b/pubspec.yaml index c0efa52..2532a38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: qr_code_scanner description: QR code scanner that can be embedded inside flutter. It uses zxing in Android and MTBBarcode scanner in iOS. -version: 0.3.4 +version: 0.3.5 homepage: https://juliuscanute.com repository: https://github.com/juliuscanute/qr_code_scanner From 9e4394395cdb37562d40e325288306e38a02582e Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 18 Feb 2021 20:08:41 +0100 Subject: [PATCH 02/22] Release of v0.3.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 847a080..e1de6da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## 0.3.5 #### Bug fixes * Fixed QRView opening zoomed in on some devices by adding small delay to updateDimensions(). (#250) -* Changed upc-a to EAN13 on iOS. (#262) +* Changed upc-A to EAN13 on iOS. (#262) * Fixed null-pointer on BarcodeFormat array on iOS. (#262) * Added LifecycleEventHandler to dispose(). (#265) From f60e7affae42fc63fe05ff3b6a43d15e2370cc30 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Sun, 14 Mar 2021 19:24:19 +0100 Subject: [PATCH 03/22] Add support for null-safety (#278) --- example/lib/main.dart | 16 ++--- example/pubspec.yaml | 2 +- lib/src/lifecycle_event_handler.dart | 8 +-- lib/src/qr_code_scanner.dart | 87 ++++++++++++++------------- lib/src/qr_scanner_overlay_shape.dart | 6 +- lib/src/types/barcode.dart | 4 +- lib/src/types/barcode_format.dart | 2 +- lib/src/types/camera_exception.dart | 2 +- pubspec.yaml | 4 +- 9 files changed, 65 insertions(+), 66 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 8c837a8..8e7054e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,17 +7,13 @@ import 'package:qr_code_scanner/qr_code_scanner.dart'; void main() => runApp(MaterialApp(home: QRViewExample())); class QRViewExample extends StatefulWidget { - const QRViewExample({ - Key key, - }) : super(key: key); - @override State createState() => _QRViewExampleState(); } class _QRViewExampleState extends State { - Barcode result; - QRViewController controller; + Barcode? result; + QRViewController? controller; final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); // In order to get hot reload to work we need to pause the camera if the platform @@ -26,9 +22,9 @@ class _QRViewExampleState extends State { void reassemble() { super.reassemble(); if (Platform.isAndroid) { - controller.pauseCamera(); + controller!.pauseCamera(); } - controller.resumeCamera(); + controller!.resumeCamera(); } @override @@ -46,7 +42,7 @@ class _QRViewExampleState extends State { children: [ if (result != null) Text( - 'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') + 'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}') else Text('Scan a code'), Row( @@ -79,7 +75,7 @@ class _QRViewExampleState extends State { builder: (context, snapshot) { if (snapshot.data != null) { return Text( - 'Camera facing ${describeEnum(snapshot.data)}'); + 'Camera facing ${describeEnum(snapshot.data!)}'); } else { return Text('loading'); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 929acf1..3913710 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_qr plugin. publish_to: 'none' environment: - sdk: ">=2.6.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: diff --git a/lib/src/lifecycle_event_handler.dart b/lib/src/lifecycle_event_handler.dart index f6da736..f2bfe15 100644 --- a/lib/src/lifecycle_event_handler.dart +++ b/lib/src/lifecycle_event_handler.dart @@ -7,22 +7,22 @@ class LifecycleEventHandler extends WidgetsBindingObserver { this.suspendingCallBack, }); - final AsyncCallback resumeCallBack; - final AsyncCallback suspendingCallBack; + final AsyncCallback? resumeCallBack; + final AsyncCallback? suspendingCallBack; @override Future didChangeAppLifecycleState(AppLifecycleState state) async { switch (state) { case AppLifecycleState.resumed: if (resumeCallBack != null) { - await resumeCallBack(); + await resumeCallBack!(); } break; case AppLifecycleState.inactive: case AppLifecycleState.paused: case AppLifecycleState.detached: if (suspendingCallBack != null) { - await suspendingCallBack(); + await suspendingCallBack!(); } break; } diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 67ee443..6e25f13 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -14,29 +14,27 @@ import 'types/camera_exception.dart'; import 'types/features.dart'; typedef QRViewCreatedCallback = void Function(QRViewController); -typedef PermissionSetCallback = void Function(QRViewController, bool); +typedef PermissionSetCallback = void Function(QRViewController, bool?); /// The [QRView] is the view where the camera /// and the barcode scanner gets displayed. class QRView extends StatefulWidget { const QRView({ - @required Key key, - @required this.onQRViewCreated, + required Key key, + required this.onQRViewCreated, this.overlay, this.overlayMargin = EdgeInsets.zero, this.cameraFacing = CameraFacing.back, this.onPermissionSet, this.formatsAllowed, - }) : assert(key != null), - assert(onQRViewCreated != null), - super(key: key); + }) : super(key: key); /// [onQRViewCreated] gets called when the view is created final QRViewCreatedCallback onQRViewCreated; /// Use [overlay] to provide an overlay for the view. /// This can be used to create a certain scan area. - final QrScannerOverlayShape overlay; + final QrScannerOverlayShape? overlay; /// Use [overlayMargin] to provide a margin to [overlay] final EdgeInsetsGeometry overlayMargin; @@ -48,10 +46,10 @@ class QRView extends StatefulWidget { final CameraFacing cameraFacing; /// Calls the provided [onPermissionSet] callback when the permission is set. - final PermissionSetCallback onPermissionSet; + final PermissionSetCallback? onPermissionSet; /// Use [formatsAllowed] to specify which formats needs to be scanned. - final List formatsAllowed; + final List? formatsAllowed; @override State createState() => _QRViewState(); @@ -59,7 +57,7 @@ class QRView extends StatefulWidget { class _QRViewState extends State { var _channel; - var _observer; + late var _observer; @override void initState() { @@ -68,11 +66,12 @@ class _QRViewState extends State { resumeCallBack: () async => { if (_channel != null) { - QRViewController.updateDimensions(widget.key, _channel, + QRViewController.updateDimensions( + widget.key as GlobalKey>, _channel, overlay: widget.overlay) } }); - WidgetsBinding.instance.addObserver(_observer); + WidgetsBinding.instance!.addObserver(_observer); } @override @@ -90,12 +89,13 @@ class _QRViewState extends State { @override void dispose() { super.dispose(); - WidgetsBinding.instance.removeObserver(_observer); + WidgetsBinding.instance!.removeObserver(_observer); } bool onNotification(notification) { Future.microtask(() => { - QRViewController.updateDimensions(widget.key, _channel, + QRViewController.updateDimensions( + widget.key as GlobalKey>, _channel, overlay: widget.overlay) }); @@ -109,7 +109,7 @@ class _QRViewState extends State { Container( padding: widget.overlayMargin, decoration: ShapeDecoration( - shape: widget.overlay, + shape: widget.overlay!, ), ) ], @@ -149,13 +149,15 @@ class _QRViewState extends State { // Start scan after creation of the view final controller = QRViewController._( - _channel, widget.key, widget.onPermissionSet, widget.cameraFacing) - .._startScan(widget.key, widget.overlay, widget.formatsAllowed); + _channel, + widget.key as GlobalKey>?, + widget.onPermissionSet, + widget.cameraFacing) + .._startScan(widget.key as GlobalKey>, + widget.overlay, widget.formatsAllowed); // Initialize the controller for controlling the QRView - if (widget.onQRViewCreated != null) { - widget.onQRViewCreated(controller); - } + widget.onQRViewCreated(controller); } } @@ -164,18 +166,18 @@ class _QrCameraSettings { this.cameraFacing, }); - final CameraFacing cameraFacing; + final CameraFacing? cameraFacing; Map toMap() { return { - 'cameraFacing': cameraFacing.index, + 'cameraFacing': cameraFacing!.index, }; } } class QRViewController { - QRViewController._(MethodChannel channel, GlobalKey qrKey, - PermissionSetCallback onPermissionSet, CameraFacing cameraFacing) + QRViewController._(MethodChannel channel, GlobalKey? qrKey, + PermissionSetCallback? onPermissionSet, CameraFacing cameraFacing) : _channel = channel, _cameraFacing = cameraFacing { _channel.setMethodCallHandler((call) async { @@ -183,10 +185,10 @@ class QRViewController { case 'onRecognizeQR': if (call.arguments != null) { final args = call.arguments as Map; - final code = args['code'] as String; - final rawType = args['type'] as String; + final code = args['code'] as String?; + final rawType = args['type'] as String?; // Raw bytes are only supported by Android. - final rawBytes = args['rawBytes'] as List; + final rawBytes = args['rawBytes'] as List?; final format = BarcodeTypesExtension.fromString(rawType); if (format != null) { final barcode = Barcode(code, format, rawBytes); @@ -205,7 +207,7 @@ class QRViewController { _hasPermissions = false; } if (onPermissionSet != null) { - onPermissionSet(this, call.arguments as bool); + onPermissionSet(this, call.arguments as bool?); } } break; @@ -213,27 +215,27 @@ class QRViewController { }); } - final MethodChannel _channel; + late final MethodChannel _channel; final CameraFacing _cameraFacing; final StreamController _scanUpdateController = StreamController(); Stream get scannedDataStream => _scanUpdateController.stream; - SystemFeatures _features; - bool _hasPermissions; + SystemFeatures? _features; + bool? _hasPermissions; - SystemFeatures get systemFeatures => _features; - bool get hasPermissions => _hasPermissions; + SystemFeatures? get systemFeatures => _features; + bool? get hasPermissions => _hasPermissions; /// Starts the barcode scanner - Future _startScan(GlobalKey key, QrScannerOverlayShape overlay, - List barcodeFormats) async { + Future _startScan(GlobalKey key, QrScannerOverlayShape? overlay, + List? barcodeFormats) async { // We need to update the dimension before the scan is started. try { await QRViewController.updateDimensions(key, _channel, overlay: overlay); return await _channel.invokeMethod( - 'startScan', barcodeFormats?.map((e) => e.asInt())?.toList() ?? []); + 'startScan', barcodeFormats?.map((e) => e.asInt()).toList() ?? []); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -242,7 +244,7 @@ class QRViewController { /// Gets information about which camera is active. Future getCameraInfo() async { try { - var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int; + var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int?; if (cameraFacing == -1) return _cameraFacing; return CameraFacing .values[await _channel.invokeMethod('getCameraInfo') as int]; @@ -262,7 +264,7 @@ class QRViewController { } /// Get flashlight status - Future getFlashStatus() async { + Future getFlashStatus() async { try { return await _channel.invokeMethod('getFlashInfo'); } on PlatformException catch (e) { @@ -273,7 +275,7 @@ class QRViewController { /// Toggles the flashlight between available modes Future toggleFlash() async { try { - await _channel.invokeMethod('toggleFlash') as bool; + await _channel.invokeMethod('toggleFlash') as bool?; } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -310,7 +312,8 @@ class QRViewController { Future getSystemFeatures() async { try { var features = - await _channel.invokeMapMethod('getSystemFeatures'); + await (_channel.invokeMapMethod('getSystemFeatures') + as FutureOr>); return SystemFeatures.fromJson(features); } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -325,11 +328,11 @@ class QRViewController { /// Updates the view dimensions for iOS. static Future updateDimensions(GlobalKey key, MethodChannel channel, - {QrScannerOverlayShape overlay}) async { + {QrScannerOverlayShape? overlay}) async { if (defaultTargetPlatform == TargetPlatform.iOS) { // Add small delay to ensure the renderbox is loaded await Future.delayed(Duration(milliseconds: 100)); - final RenderBox renderBox = key.currentContext.findRenderObject(); + final renderBox = key.currentContext!.findRenderObject() as RenderBox; try { await channel.invokeMethod('setDimensions', { 'width': renderBox.size.width, diff --git a/lib/src/qr_scanner_overlay_shape.dart b/lib/src/qr_scanner_overlay_shape.dart index 77c1a14..d890788 100644 --- a/lib/src/qr_scanner_overlay_shape.dart +++ b/lib/src/qr_scanner_overlay_shape.dart @@ -29,14 +29,14 @@ class QrScannerOverlayShape extends ShapeBorder { EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10); @override - Path getInnerPath(Rect rect, {TextDirection textDirection}) { + Path getInnerPath(Rect rect, {TextDirection? textDirection}) { return Path() ..fillType = PathFillType.evenOdd ..addPath(getOuterPath(rect), Offset.zero); } @override - Path getOuterPath(Rect rect, {TextDirection textDirection}) { + Path getOuterPath(Rect rect, {TextDirection? textDirection}) { Path _getLeftTopPath(Rect rect) { return Path() ..moveTo(rect.left, rect.bottom) @@ -60,7 +60,7 @@ class QrScannerOverlayShape extends ShapeBorder { } @override - void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { + void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { final width = rect.width; final borderWidthSize = width / 2; final height = rect.height; diff --git a/lib/src/types/barcode.dart b/lib/src/types/barcode.dart index 9bfffdb..091c79a 100644 --- a/lib/src/types/barcode.dart +++ b/lib/src/types/barcode.dart @@ -8,9 +8,9 @@ import 'barcode_format.dart'; class Barcode { Barcode(this.code, this.format, this.rawBytes); - final String code; + final String? code; final BarcodeFormat format; /// Raw bytes are only supported by Android. - final List rawBytes; + final List? rawBytes; } diff --git a/lib/src/types/barcode_format.dart b/lib/src/types/barcode_format.dart index 4d93fd5..e32756b 100644 --- a/lib/src/types/barcode_format.dart +++ b/lib/src/types/barcode_format.dart @@ -61,7 +61,7 @@ extension BarcodeTypesExtension on BarcodeFormat { return index; } - static BarcodeFormat fromString(String format) { + static BarcodeFormat? fromString(String? format) { switch (format) { case 'AZTEC': return BarcodeFormat.aztec; diff --git a/lib/src/types/camera_exception.dart b/lib/src/types/camera_exception.dart index 740f4b6..0abb639 100644 --- a/lib/src/types/camera_exception.dart +++ b/lib/src/types/camera_exception.dart @@ -7,7 +7,7 @@ class CameraException implements Exception { String code; /// Textual description of the error. - String description; + String? description; @override String toString() => 'CameraException($code, $description)'; diff --git a/pubspec.yaml b/pubspec.yaml index 2532a38..bdddd05 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://juliuscanute.com repository: https://github.com/juliuscanute/qr_code_scanner environment: - sdk: ">=2.6.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' flutter: ">=1.10.0" dependencies: @@ -13,7 +13,7 @@ dependencies: sdk: flutter dev_dependencies: - pedantic: ^1.9.2 + pedantic: ^1.11.0 flutter: plugin: From 92e8abedce1aced25f16c98edf64d694b40e5cde Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Sun, 14 Mar 2021 19:37:29 +0100 Subject: [PATCH 04/22] Updated barcode_format.dart to null-safety. --- lib/src/qr_code_scanner.dart | 6 ++-- lib/src/qr_scanner_overlay_shape.dart | 7 ++--- lib/src/types/barcode_format.dart | 45 +++++---------------------- 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 6e25f13..23b7589 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -185,12 +185,12 @@ class QRViewController { case 'onRecognizeQR': if (call.arguments != null) { final args = call.arguments as Map; - final code = args['code'] as String?; - final rawType = args['type'] as String?; + final code = args['code'] as String; + final rawType = args['type'] as String; // Raw bytes are only supported by Android. final rawBytes = args['rawBytes'] as List?; final format = BarcodeTypesExtension.fromString(rawType); - if (format != null) { + if (format != BarcodeFormat.unknown) { final barcode = Barcode(code, format, rawBytes); _scanUpdateController.sink.add(barcode); } else { diff --git a/lib/src/qr_scanner_overlay_shape.dart b/lib/src/qr_scanner_overlay_shape.dart index d890788..dcb5906 100644 --- a/lib/src/qr_scanner_overlay_shape.dart +++ b/lib/src/qr_scanner_overlay_shape.dart @@ -11,10 +11,7 @@ class QrScannerOverlayShape extends ShapeBorder { this.borderLength = 40, this.cutOutSize = 250, this.cutOutBottomOffset = 0, - }) : assert( - cutOutSize != null ?? - cutOutSize != null ?? - borderLength <= cutOutSize / 2 + borderWidth * 2, + }) : assert( borderLength <= cutOutSize / 2 + borderWidth * 2, "Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}"); final Color borderColor; @@ -68,7 +65,7 @@ class QrScannerOverlayShape extends ShapeBorder { final _borderLength = borderLength > cutOutSize / 2 + borderWidth * 2 ? borderWidthSize / 2 : borderLength; - final _cutOutSize = cutOutSize != null && cutOutSize < width + final _cutOutSize = cutOutSize < width ? cutOutSize : width - borderOffset; diff --git a/lib/src/types/barcode_format.dart b/lib/src/types/barcode_format.dart index e32756b..49bcee2 100644 --- a/lib/src/types/barcode_format.dart +++ b/lib/src/types/barcode_format.dart @@ -53,7 +53,10 @@ enum BarcodeFormat { upcE, /// UPC/EAN extension format. Not a stand-alone format. - upcEanExtension + upcEanExtension, + + /// Unknown + unknown } extension BarcodeTypesExtension on BarcodeFormat { @@ -61,61 +64,44 @@ extension BarcodeTypesExtension on BarcodeFormat { return index; } - static BarcodeFormat? fromString(String? format) { + static BarcodeFormat fromString(String format) { switch (format) { case 'AZTEC': return BarcodeFormat.aztec; - break; case 'CODABAR': return BarcodeFormat.codabar; - break; case 'CODE_39': return BarcodeFormat.code39; - break; case 'CODE_93': return BarcodeFormat.code93; - break; case 'CODE_128': return BarcodeFormat.code128; - break; case 'DATA_MATRIX': return BarcodeFormat.dataMatrix; - break; case 'EAN_8': return BarcodeFormat.ean8; - break; case 'EAN_13': return BarcodeFormat.ean13; - break; case 'ITF': return BarcodeFormat.itf; - break; case 'MAXICODE': return BarcodeFormat.maxicode; - break; case 'PDF_417': return BarcodeFormat.pdf417; - break; case 'QR_CODE': return BarcodeFormat.qrcode; - break; case 'RSS14': return BarcodeFormat.rss14; - break; case 'RSS_EXPANDED': return BarcodeFormat.rssExpanded; - break; case 'UPC_A': return BarcodeFormat.upcA; - break; case 'UPC_E': return BarcodeFormat.upcE; - break; case 'UPC_EAN_EXTENSION': return BarcodeFormat.upcEanExtension; - break; default: - return null; + return BarcodeFormat.unknown; } } @@ -123,57 +109,40 @@ extension BarcodeTypesExtension on BarcodeFormat { switch (this) { case BarcodeFormat.aztec: return 'AZTEC'; - break; case BarcodeFormat.codabar: return 'CODABAR'; - break; case BarcodeFormat.code39: return 'CODE_39'; - break; case BarcodeFormat.code93: return 'CODE_93'; - break; case BarcodeFormat.code128: return 'CODE_128'; - break; case BarcodeFormat.dataMatrix: return 'DATA_MATRIX'; - break; case BarcodeFormat.ean8: return 'EAN_8'; - break; case BarcodeFormat.ean13: return 'EAN_13'; - break; case BarcodeFormat.itf: return 'ITF'; - break; case BarcodeFormat.maxicode: return 'MAXICODE'; - break; case BarcodeFormat.pdf417: return 'PDF_417'; - break; case BarcodeFormat.qrcode: return 'QR_CODE'; - break; case BarcodeFormat.rss14: return 'RSS14'; - break; case BarcodeFormat.rssExpanded: return 'RSS_EXPANDED'; - break; case BarcodeFormat.upcA: return 'UPC_A'; - break; case BarcodeFormat.upcE: return 'UPC_E'; - break; case BarcodeFormat.upcEanExtension: return 'UPC_EAN_EXTENSION'; - break; default: - return 'NOT_VALID'; + return 'UNKNOWN'; } } } From 742568c50ad86b4e936ee11a5f42723bbca5ad44 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Sun, 14 Mar 2021 19:50:04 +0100 Subject: [PATCH 05/22] Dartfmt --- lib/src/qr_scanner_overlay_shape.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/qr_scanner_overlay_shape.dart b/lib/src/qr_scanner_overlay_shape.dart index dcb5906..1b11dfb 100644 --- a/lib/src/qr_scanner_overlay_shape.dart +++ b/lib/src/qr_scanner_overlay_shape.dart @@ -11,7 +11,7 @@ class QrScannerOverlayShape extends ShapeBorder { this.borderLength = 40, this.cutOutSize = 250, this.cutOutBottomOffset = 0, - }) : assert( borderLength <= cutOutSize / 2 + borderWidth * 2, + }) : assert(borderLength <= cutOutSize / 2 + borderWidth * 2, "Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}"); final Color borderColor; @@ -65,9 +65,7 @@ class QrScannerOverlayShape extends ShapeBorder { final _borderLength = borderLength > cutOutSize / 2 + borderWidth * 2 ? borderWidthSize / 2 : borderLength; - final _cutOutSize = cutOutSize < width - ? cutOutSize - : width - borderOffset; + final _cutOutSize = cutOutSize < width ? cutOutSize : width - borderOffset; final backgroundPaint = Paint() ..color = overlayColor From c8ed07e9158a693548cfc9ed13601c38e504cadb Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Mon, 22 Mar 2021 10:36:02 +0100 Subject: [PATCH 06/22] refactor: changed lifecycle callback to late --- lib/src/lifecycle_event_handler.dart | 14 +++----------- lib/src/qr_code_scanner.dart | 5 ++--- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/src/lifecycle_event_handler.dart b/lib/src/lifecycle_event_handler.dart index f2bfe15..0580d17 100644 --- a/lib/src/lifecycle_event_handler.dart +++ b/lib/src/lifecycle_event_handler.dart @@ -3,28 +3,20 @@ import 'package:flutter/foundation.dart'; class LifecycleEventHandler extends WidgetsBindingObserver { LifecycleEventHandler({ - this.resumeCallBack, - this.suspendingCallBack, + required this.resumeCallBack, }); - final AsyncCallback? resumeCallBack; - final AsyncCallback? suspendingCallBack; + late final AsyncCallback resumeCallBack; @override Future didChangeAppLifecycleState(AppLifecycleState state) async { switch (state) { case AppLifecycleState.resumed: - if (resumeCallBack != null) { - await resumeCallBack!(); - } + await resumeCallBack(); break; case AppLifecycleState.inactive: case AppLifecycleState.paused: case AppLifecycleState.detached: - if (suspendingCallBack != null) { - await suspendingCallBack!(); - } - break; } } } diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 23b7589..a3cefd8 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -98,7 +98,6 @@ class _QRViewState extends State { widget.key as GlobalKey>, _channel, overlay: widget.overlay) }); - return false; } @@ -139,7 +138,7 @@ class _QRViewState extends State { break; default: throw UnsupportedError( - "Trying to use the default webview implementation for $defaultTargetPlatform but there isn't a default one"); + "Trying to use the default qrview implementation for $defaultTargetPlatform but there isn't a default one"); } return _platformQrView; } @@ -199,7 +198,7 @@ class QRViewController { } break; case 'onPermissionSet': - await getSystemFeatures(); // if we have no permission all features will not be avaible + await getSystemFeatures(); // if we have no permission all features will not be available if (call.arguments != null) { if (call.arguments as bool) { _hasPermissions = true; From dcdc6726cabdbc0978043cecffea0d92a712bb26 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Mon, 22 Mar 2021 11:07:17 +0100 Subject: [PATCH 07/22] style: changed pedantic to dev_dependencies --- analysis_options.yaml | 108 +----------------------------------------- example/pubspec.yaml | 5 +- 2 files changed, 2 insertions(+), 111 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 180afc8..d4fcc1a 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,107 +1 @@ -include: package:pedantic/analysis_options.yaml - -linter: - rules: - - always_put_required_named_parameters_first - - always_require_non_null_named_parameters - - avoid_annotating_with_dynamic - - avoid_bool_literals_in_conditional_expressions - - avoid_catching_errors - - avoid_classes_with_only_static_members - - avoid_empty_else - - avoid_init_to_null - - avoid_null_checks_in_equality_operators - - avoid_print - - avoid_relative_lib_imports - - avoid_return_types_on_setters - - avoid_returning_null - - avoid_returning_null_for_future - - avoid_returning_null_for_void - - avoid_shadowing_type_parameters - - avoid_single_cascade_in_expression_statements - - avoid_types_as_parameter_names - - avoid_types_on_closure_parameters - - avoid_void_async - - await_only_futures - - camel_case_types - - cancel_subscriptions - - cascade_invocations - - close_sinks - - comment_references - - constant_identifier_names - - control_flow_in_finally - - curly_braces_in_flow_control_structures - - directives_ordering - - empty_catches - - empty_constructor_bodies - - empty_statements - - file_names - - hash_and_equals - - implementation_imports - - invariant_booleans - - iterable_contains_unrelated_type - - join_return_with_assignment - - library_names - - library_prefixes - - list_remove_unrelated_type - - no_duplicate_case_values - - non_constant_identifier_names - - null_closures - - only_throw_errors - - overridden_fields - - package_api_docs - - package_names - - package_prefixed_library_names - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_declarations - - prefer_contains - - prefer_equal_for_default_values - - prefer_final_fields - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - prefer_is_not_empty - - prefer_iterable_whereType - - prefer_null_aware_operators - - prefer_void_to_null - - provide_deprecation_message - - recursive_getters - - slash_for_doc_comments - - sort_child_properties_last - - sort_constructors_first - - sort_pub_dependencies - - sort_unnamed_constructors_first - - test_types_in_equals - - throw_in_finally - - type_init_formals - - unawaited_futures - - unnecessary_await_in_return - - unnecessary_brace_in_string_interps - - unnecessary_const - - unnecessary_getters_setters - - unnecessary_lambdas - - unnecessary_new - - unnecessary_null_aware_assignments - - unnecessary_null_in_if_null_operators - - unnecessary_overrides - - unnecessary_parenthesis - - unnecessary_statements - - unnecessary_this - - unrelated_type_equality_checks - - unsafe_html - - use_full_hex_values_for_flutter_colors - - use_function_type_syntax_for_parameters - - use_rethrow_when_possible - - use_setters_to_change_properties - - use_string_buffers - - use_to_and_as_if_applicable - - valid_regexps - - void_checks +include: package:pedantic/analysis_options.yaml \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 3913710..b93026c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,11 +9,8 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - dev_dependencies: + pedantic: ^1.11.0 flutter_test: sdk: flutter From 30991e741afdf0b3215b7fda866f16b52d6fee9c Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Mon, 22 Mar 2021 12:18:32 +0100 Subject: [PATCH 08/22] style: typo --- lib/src/qr_code_scanner.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index a3cefd8..d4bc951 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -329,7 +329,7 @@ class QRViewController { static Future updateDimensions(GlobalKey key, MethodChannel channel, {QrScannerOverlayShape? overlay}) async { if (defaultTargetPlatform == TargetPlatform.iOS) { - // Add small delay to ensure the renderbox is loaded + // Add small delay to ensure the render box is loaded await Future.delayed(Duration(milliseconds: 100)); final renderBox = key.currentContext!.findRenderObject() as RenderBox; try { From 3ed399166612759328d865ba1b8e059e83790bdb Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Mon, 22 Mar 2021 13:51:06 +0100 Subject: [PATCH 09/22] ci: updated to new commands Signed-off-by: Julian Steenbakker --- .github/workflows/dart.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 2722427..845be33 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -8,18 +8,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-java@v1 - with: - java-version: '12.x' - - uses: subosito/flutter-action@v1 - with: - channel: 'stable' - - name: Version - run: flutter doctor -v - - name: Install dependencies - run: flutter pub get - - name: Format - run: dartfmt -n --set-exit-if-changed . - - name: Linter - run: dartanalyzer . --options=analysis_options.yaml --fatal-hints + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1 + - name: Version + run: flutter doctor -v + - name: Install dependencies + run: flutter pub get + - name: Format + run: flutter format -n --set-exit-if-changed . + - name: Linter + run: flutter analyze + - name: Test + run: flutter test From afd988b0b8c33c03a90f8aedc55ad1717b794a0b Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Mon, 22 Mar 2021 15:18:15 +0100 Subject: [PATCH 10/22] ci: remove flutter test --- .github/workflows/dart.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 845be33..eafb986 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -20,6 +20,4 @@ jobs: - name: Format run: flutter format -n --set-exit-if-changed . - name: Linter - run: flutter analyze - - name: Test - run: flutter test + run: flutter analyze \ No newline at end of file From 0d0ae75ed6d3321a9b16266ce739348a09c8bd17 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 09:09:47 +0100 Subject: [PATCH 11/22] refactor: changed onPermissionSet argument to non nullable --- lib/src/qr_code_scanner.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index d4bc951..833b778 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -14,7 +14,7 @@ import 'types/camera_exception.dart'; import 'types/features.dart'; typedef QRViewCreatedCallback = void Function(QRViewController); -typedef PermissionSetCallback = void Function(QRViewController, bool?); +typedef PermissionSetCallback = void Function(QRViewController, bool); /// The [QRView] is the view where the camera /// and the barcode scanner gets displayed. @@ -198,15 +198,14 @@ class QRViewController { } break; case 'onPermissionSet': - await getSystemFeatures(); // if we have no permission all features will not be available - if (call.arguments != null) { - if (call.arguments as bool) { + if (call.arguments != null && call.arguments is bool) { + if (call.arguments) { _hasPermissions = true; } else { _hasPermissions = false; } if (onPermissionSet != null) { - onPermissionSet(this, call.arguments as bool?); + onPermissionSet(this, call.arguments); } } break; From 0f3b2bbef3c05654e4e62a71ee5d9857ac1201e8 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:20:18 +0100 Subject: [PATCH 12/22] refactor: change formatsAllowed to non null --- lib/src/qr_code_scanner.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 833b778..e1e8437 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -26,7 +26,7 @@ class QRView extends StatefulWidget { this.overlayMargin = EdgeInsets.zero, this.cameraFacing = CameraFacing.back, this.onPermissionSet, - this.formatsAllowed, + this.formatsAllowed = const [], }) : super(key: key); /// [onQRViewCreated] gets called when the view is created @@ -49,7 +49,7 @@ class QRView extends StatefulWidget { final PermissionSetCallback? onPermissionSet; /// Use [formatsAllowed] to specify which formats needs to be scanned. - final List? formatsAllowed; + final List formatsAllowed; @override State createState() => _QRViewState(); From 9eaaf33a8b05e03cbfbb9190233f425caa11b7a3 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:24:31 +0100 Subject: [PATCH 13/22] refactor: Change QRViewState variables to non null --- lib/src/qr_code_scanner.dart | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index e1e8437..793cd47 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -56,21 +56,13 @@ class QRView extends StatefulWidget { } class _QRViewState extends State { - var _channel; - late var _observer; + late MethodChannel _channel; + late LifecycleEventHandler _observer; @override void initState() { super.initState(); - _observer = LifecycleEventHandler( - resumeCallBack: () async => { - if (_channel != null) - { - QRViewController.updateDimensions( - widget.key as GlobalKey>, _channel, - overlay: widget.overlay) - } - }); + _observer = LifecycleEventHandler(resumeCallBack: updateDimensions); WidgetsBinding.instance!.addObserver(_observer); } @@ -92,12 +84,14 @@ class _QRViewState extends State { WidgetsBinding.instance!.removeObserver(_observer); } + Future updateDimensions() async { + await QRViewController.updateDimensions( + widget.key as GlobalKey>, _channel, + overlay: widget.overlay); + } + bool onNotification(notification) { - Future.microtask(() => { - QRViewController.updateDimensions( - widget.key as GlobalKey>, _channel, - overlay: widget.overlay) - }); + updateDimensions(); return false; } From a722df94150a6efd33fd556c4eba14ca8463802d Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:25:24 +0100 Subject: [PATCH 14/22] bug: fixed cast --- lib/src/qr_code_scanner.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 793cd47..a4d6207 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -304,9 +304,11 @@ class QRViewController { Future getSystemFeatures() async { try { var features = - await (_channel.invokeMapMethod('getSystemFeatures') - as FutureOr>); - return SystemFeatures.fromJson(features); + await _channel.invokeMapMethod('getSystemFeatures'); + if (features != null) { + return SystemFeatures.fromJson(features); + } + throw CameraException('Error', 'Could not get system features'); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } From 03328cc397ab81b0c60aaf12bc8e7abd32260c00 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:37:44 +0100 Subject: [PATCH 15/22] refactor: make CameraFacing non null --- lib/src/qr_code_scanner.dart | 6 +++--- lib/src/types/camera.dart | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index a4d6207..19b90a3 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -156,14 +156,14 @@ class _QRViewState extends State { class _QrCameraSettings { _QrCameraSettings({ - this.cameraFacing, + this.cameraFacing = CameraFacing.unknown, }); - final CameraFacing? cameraFacing; + final CameraFacing cameraFacing; Map toMap() { return { - 'cameraFacing': cameraFacing!.index, + 'cameraFacing': cameraFacing.index, }; } } diff --git a/lib/src/types/camera.dart b/lib/src/types/camera.dart index 532f3b4..67fe8cb 100644 --- a/lib/src/types/camera.dart +++ b/lib/src/types/camera.dart @@ -3,5 +3,8 @@ enum CameraFacing { back, /// Shows front facing camera. - front + front, + + /// Unknown camera + unknown } From 0f07133d032b9f362c5741246f7e95749ee734d9 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:39:15 +0100 Subject: [PATCH 16/22] refactor: removed unused late keyword --- lib/src/qr_code_scanner.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 19b90a3..0ec8e5f 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -207,7 +207,7 @@ class QRViewController { }); } - late final MethodChannel _channel; + final MethodChannel _channel; final CameraFacing _cameraFacing; final StreamController _scanUpdateController = StreamController(); From b6978a5ba24220725024d480c0fb05c728070c8e Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:42:02 +0100 Subject: [PATCH 17/22] refactor: removed unused _features and made _hasPermissions non nullable --- lib/src/qr_code_scanner.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 0ec8e5f..b1da196 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -214,11 +214,8 @@ class QRViewController { Stream get scannedDataStream => _scanUpdateController.stream; - SystemFeatures? _features; - bool? _hasPermissions; - - SystemFeatures? get systemFeatures => _features; - bool? get hasPermissions => _hasPermissions; + bool _hasPermissions = false; + bool get hasPermissions => _hasPermissions; /// Starts the barcode scanner Future _startScan(GlobalKey key, QrScannerOverlayShape? overlay, From c0ce8e30dcfaf7bd90c2a8cbd9de60dbeb0c0739 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:43:25 +0100 Subject: [PATCH 18/22] refactor: removed unused null check --- lib/src/qr_code_scanner.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index b1da196..2fdc584 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -233,7 +233,7 @@ class QRViewController { /// Gets information about which camera is active. Future getCameraInfo() async { try { - var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int?; + var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int; if (cameraFacing == -1) return _cameraFacing; return CameraFacing .values[await _channel.invokeMethod('getCameraInfo') as int]; From 9f7eaec71e9b0719627a3a81cd62cc7ace946fd3 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 10:59:52 +0100 Subject: [PATCH 19/22] refactor: safe usage of updateDimensions --- lib/src/qr_code_scanner.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/qr_code_scanner.dart b/lib/src/qr_code_scanner.dart index 2fdc584..03a1a39 100644 --- a/lib/src/qr_code_scanner.dart +++ b/lib/src/qr_code_scanner.dart @@ -318,11 +318,12 @@ class QRViewController { } /// Updates the view dimensions for iOS. - static Future updateDimensions(GlobalKey key, MethodChannel channel, + static Future updateDimensions(GlobalKey key, MethodChannel channel, {QrScannerOverlayShape? overlay}) async { if (defaultTargetPlatform == TargetPlatform.iOS) { // Add small delay to ensure the render box is loaded await Future.delayed(Duration(milliseconds: 100)); + if (key.currentContext == null) return false; final renderBox = key.currentContext!.findRenderObject() as RenderBox; try { await channel.invokeMethod('setDimensions', { @@ -331,9 +332,11 @@ class QRViewController { 'scanArea': overlay?.cutOutSize ?? 0, 'scanAreaOffset': overlay?.cutOutBottomOffset ?? 0 }); + return true; } on PlatformException catch (e) { throw CameraException(e.code, e.message); } } + return false; } } From ec0b8070b53d825c2df6006c632bf40f5e32c0d9 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 11:10:52 +0100 Subject: [PATCH 20/22] refactor: barcode code to non nullable --- lib/src/types/barcode.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/types/barcode.dart b/lib/src/types/barcode.dart index 091c79a..9627a9f 100644 --- a/lib/src/types/barcode.dart +++ b/lib/src/types/barcode.dart @@ -8,7 +8,7 @@ import 'barcode_format.dart'; class Barcode { Barcode(this.code, this.format, this.rawBytes); - final String? code; + final String code; final BarcodeFormat format; /// Raw bytes are only supported by Android. From f6cfe84d3f1153798aab014a9428796ad641627d Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Thu, 25 Mar 2021 11:20:13 +0100 Subject: [PATCH 21/22] release of v0.4.0 --- CHANGELOG.md | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1de6da..5e90a8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.4.0 +Stable null-safety support. (#278) + ## 0.3.5 #### Bug fixes * Fixed QRView opening zoomed in on some devices by adding small delay to updateDimensions(). (#250) diff --git a/pubspec.yaml b/pubspec.yaml index bdddd05..722fd49 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: qr_code_scanner description: QR code scanner that can be embedded inside flutter. It uses zxing in Android and MTBBarcode scanner in iOS. -version: 0.3.5 +version: 0.4.0 homepage: https://juliuscanute.com repository: https://github.com/juliuscanute/qr_code_scanner From d1c117335ee4570ee27acc4f2bdf1515ca8c90a8 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Tue, 6 Apr 2021 16:55:00 +0200 Subject: [PATCH 22/22] Update README.md doc: add badges --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 5e9a69d..2713f6e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # QR Code Scanner + +[![pub package](https://img.shields.io/pub/v/qr_code_scanner?include_prereleases)](https://pub.dartlang.org/packages/qr_code_scanner) +[![Join the chat](https://img.shields.io/discord/829004904600961054)](https://discord.gg/aZujk84f6V) [![GH Actions](https://github.com/juliuscanute/qr_code_scanner/workflows/dart/badge.svg)](https://github.com/juliuscanute/qr_code_scanner/actions) A QR code scanner that works on both iOS and Android by natively embedding the platform view within Flutter. The integration with Flutter is seamless, much better than jumping into a native Activity or a ViewController to perform the scan.