Navaron Bracke

update the readme

Showing 1 changed file with 78 additions and 172 deletions
@@ -7,17 +7,15 @@ @@ -7,17 +7,15 @@
7 7
8 A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS. 8 A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS.
9 9
10 -  
11 ## Features Supported 10 ## Features Supported
12 11
13 See the example app for detailed implementation information. 12 See the example app for detailed implementation information.
14 13
15 -| Features | Android | iOS | macOS | Web |  
16 -|------------------------|--------------------|--------------------|-------|-----|  
17 -| analyzeImage (Gallery) | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |  
18 -| returnImage | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |  
19 -| scanWindow | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |  
20 -| barcodeOverlay | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | 14 +| Features | Android | iOS | macOS | Web |
  15 +|------------------------|--------------------|--------------------|----------------------|-----|
  16 +| analyzeImage (Gallery) | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
  17 +| returnImage | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
  18 +| scanWindow | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
21 19
22 ## Platform Support 20 ## Platform Support
23 21
@@ -26,6 +24,7 @@ See the example app for detailed implementation information. @@ -26,6 +24,7 @@ See the example app for detailed implementation information.
26 | ✔ | ✔ | ✔ | ✔ | :x: | :x: | 24 | ✔ | ✔ | ✔ | ✔ | :x: | :x: |
27 25
28 ## Platform specific setup 26 ## Platform specific setup
  27 +
29 ### Android 28 ### Android
30 This package uses by default the **bundled version** of MLKit Barcode-scanning for Android. This version is immediately available to the device. But it will increase the size of the app by approximately 3 to 10 MB. 29 This package uses by default the **bundled version** of MLKit Barcode-scanning for Android. This version is immediately available to the device. But it will increase the size of the app by approximately 3 to 10 MB.
31 30
@@ -61,194 +60,101 @@ Ensure that you granted camera permission in XCode -> Signing & Capabilities: @@ -61,194 +60,101 @@ Ensure that you granted camera permission in XCode -> Signing & Capabilities:
61 <img width="696" alt="Screenshot of XCode where Camera is checked" src="https://user-images.githubusercontent.com/24459435/193464115-d76f81d0-6355-4cb2-8bee-538e413a3ad0.png"> 60 <img width="696" alt="Screenshot of XCode where Camera is checked" src="https://user-images.githubusercontent.com/24459435/193464115-d76f81d0-6355-4cb2-8bee-538e413a3ad0.png">
62 61
63 ## Web 62 ## Web
64 -This package uses ZXing on web to read barcodes so it needs to be included in `index.html` as script. 63 +
  64 +Include the `ZXing` library in the `<head>` of your `index.html` as a script.
  65 +
65 ```html 66 ```html
66 -<script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script> 67 +<head>
  68 + <!-- other things in the tag -->
  69 +
  70 + <script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script>
  71 +</head>
67 ``` 72 ```
68 73
69 ## Usage 74 ## Usage
70 75
71 -Import `package:mobile_scanner/mobile_scanner.dart`, and use the widget with or without the controller. 76 +Import the package with `package:mobile_scanner/mobile_scanner.dart`.
72 77
73 -If you don't provide a controller, you can't control functions like the torch(flash) or switching camera.  
74 -  
75 -If you don't set `detectionSpeed` to `DetectionSpeed.noDuplicates`, you can get multiple scans in a very short time, causing things like pop() to fire lots of times.  
76 -  
77 -Example without controller: 78 +Create a new `MobileScannerController` controller, using the required options.
  79 +Provide a `StreamSubscription` for the barcode events.
78 80
79 ```dart 81 ```dart
80 -import 'package:mobile_scanner/mobile_scanner.dart'; 82 +final MobileScannerController controller = MobileScannerController(
  83 + // required options for the scanner
  84 +);
81 85
82 - @override  
83 - Widget build(BuildContext context) {  
84 - return Scaffold(  
85 - appBar: AppBar(title: const Text('Mobile Scanner')),  
86 - body: MobileScanner(  
87 - // fit: BoxFit.contain,  
88 - onDetect: (capture) {  
89 - final List<Barcode> barcodes = capture.barcodes;  
90 - final Uint8List? image = capture.image;  
91 - for (final barcode in barcodes) {  
92 - debugPrint('Barcode found! ${barcode.rawValue}');  
93 - }  
94 - },  
95 - ),  
96 - );  
97 - } 86 +StreamSubscription<Object?>? _subscription;
98 ``` 87 ```
99 88
100 -Example with controller and initial values: 89 +Ensure that your `State` class mixes in `WidgetsBindingObserver`, to handle lifecyle changes:
101 90
102 ```dart 91 ```dart
103 -import 'package:mobile_scanner/mobile_scanner.dart'; 92 +class MyState extends State<MyStatefulWidget> with WidgetsBindingObserver {
  93 + // ...
104 94
105 @override 95 @override
106 - Widget build(BuildContext context) {  
107 - return Scaffold(  
108 - appBar: AppBar(title: const Text('Mobile Scanner')),  
109 - body: MobileScanner(  
110 - // fit: BoxFit.contain,  
111 - controller: MobileScannerController(  
112 - detectionSpeed: DetectionSpeed.normal,  
113 - facing: CameraFacing.front,  
114 - torchEnabled: true,  
115 - ),  
116 - onDetect: (capture) {  
117 - final List<Barcode> barcodes = capture.barcodes;  
118 - final Uint8List? image = capture.image;  
119 - for (final barcode in barcodes) {  
120 - debugPrint('Barcode found! ${barcode.rawValue}');  
121 - }  
122 - },  
123 - ),  
124 - ); 96 + void didChangeAppLifecycleState(AppLifecycleState state) {
  97 + super.didChangeAppLifecycleState(state);
  98 +
  99 + switch (state) {
  100 + case AppLifecycleState.detached:
  101 + case AppLifecycleState.hidden:
  102 + case AppLifecycleState.paused:
  103 + return;
  104 + case AppLifecycleState.resumed:
  105 + // Restart the scanner when the app is resumed.
  106 + // Don't forget to resume listening to the barcode events.
  107 + _subscription = controller.barcodes.listen(_handleBarcode);
  108 +
  109 + unawaited(controller.start());
  110 + case AppLifecycleState.inactive:
  111 + // Stop the scanner when the app is paused.
  112 + // Also stop the barcode events subscription.
  113 + unawaited(_subscription?.cancel());
  114 + _subscription = null;
  115 + unawaited(controller.stop());
  116 + }
125 } 117 }
  118 +
  119 + // ...
  120 +}
126 ``` 121 ```
127 122
128 -Example with controller and torch & camera controls: 123 +Then, start the scanner in `void initState()`:
129 124
130 ```dart 125 ```dart
131 -import 'package:mobile_scanner/mobile_scanner.dart';  
132 -  
133 - MobileScannerController cameraController = MobileScannerController();  
134 -  
135 - @override  
136 - Widget build(BuildContext context) {  
137 - return Scaffold(  
138 - appBar: AppBar(  
139 - title: const Text('Mobile Scanner'),  
140 - actions: [  
141 - IconButton(  
142 - color: Colors.white,  
143 - icon: ValueListenableBuilder(  
144 - valueListenable: cameraController.torchState,  
145 - builder: (context, state, child) {  
146 - switch (state as TorchState) {  
147 - case TorchState.off:  
148 - return const Icon(Icons.flash_off, color: Colors.grey);  
149 - case TorchState.on:  
150 - return const Icon(Icons.flash_on, color: Colors.yellow);  
151 - }  
152 - },  
153 - ),  
154 - iconSize: 32.0,  
155 - onPressed: () => cameraController.toggleTorch(),  
156 - ),  
157 - IconButton(  
158 - color: Colors.white,  
159 - icon: ValueListenableBuilder(  
160 - valueListenable: cameraController.cameraFacingState,  
161 - builder: (context, state, child) {  
162 - switch (state as CameraFacing) {  
163 - case CameraFacing.front:  
164 - return const Icon(Icons.camera_front);  
165 - case CameraFacing.back:  
166 - return const Icon(Icons.camera_rear);  
167 - }  
168 - },  
169 - ),  
170 - iconSize: 32.0,  
171 - onPressed: () => cameraController.switchCamera(),  
172 - ),  
173 - ],  
174 - ),  
175 - body: MobileScanner(  
176 - // fit: BoxFit.contain,  
177 - controller: cameraController,  
178 - onDetect: (capture) {  
179 - final List<Barcode> barcodes = capture.barcodes;  
180 - final Uint8List? image = capture.image;  
181 - for (final barcode in barcodes) {  
182 - debugPrint('Barcode found! ${barcode.rawValue}');  
183 - }  
184 - },  
185 - ),  
186 - );  
187 - } 126 +@override
  127 +void initState() {
  128 + super.initState();
  129 + // Start listening to lifecycle changes.
  130 + WidgetsBinding.instance.addObserver(this);
  131 +
  132 + // Start listening to the barcode events.
  133 + _subscription = controller.barcodes.listen(_handleBarcode);
  134 +
  135 + // Finally, start the scanner itself.
  136 + unawaited(controller.start());
  137 +}
188 ``` 138 ```
189 139
190 -Example with controller and returning images 140 +Finally, dispose of the the `MobileScannerController` when you are done with it.
191 141
192 ```dart 142 ```dart
193 -import 'package:mobile_scanner/mobile_scanner.dart';  
194 -  
195 - @override  
196 - Widget build(BuildContext context) {  
197 - return Scaffold(  
198 - appBar: AppBar(title: const Text('Mobile Scanner')),  
199 - body: MobileScanner(  
200 - fit: BoxFit.contain,  
201 - controller: MobileScannerController(  
202 - // facing: CameraFacing.back,  
203 - // torchEnabled: false,  
204 - returnImage: true,  
205 - ),  
206 - onDetect: (capture) {  
207 - final List<Barcode> barcodes = capture.barcodes;  
208 - final Uint8List? image = capture.image;  
209 - for (final barcode in barcodes) {  
210 - debugPrint('Barcode found! ${barcode.rawValue}');  
211 - }  
212 - if (image != null) {  
213 - showDialog(  
214 - context: context,  
215 - builder: (context) =>  
216 - Image(image: MemoryImage(image)),  
217 - );  
218 - Future.delayed(const Duration(seconds: 5), () {  
219 - Navigator.pop(context);  
220 - });  
221 - }  
222 - },  
223 - ),  
224 - );  
225 - } 143 +@override
  144 +Future<void> dispose() async {
  145 + // Stop listening to lifecycle changes.
  146 + WidgetsBinding.instance.removeObserver(this);
  147 + // Stop listening to the barcode events.
  148 + unawaited(_subscription?.cancel());
  149 + _subscription = null;
  150 + // Dispose the widget itself.
  151 + super.dispose();
  152 + // Finally, dispose of the controller.
  153 + await controller.dispose();
  154 +}
226 ``` 155 ```
227 156
228 -### BarcodeCapture  
229 -  
230 -The onDetect function returns a BarcodeCapture objects which contains the following items.  
231 -  
232 -| Property name | Type | Description |  
233 -|---------------|---------------|-----------------------------------|  
234 -| barcodes | List<Barcode> | A list with scanned barcodes. |  
235 -| image | Uint8List? | If enabled, an image of the scan. |  
236 -  
237 -You can use the following properties of the Barcode object.  
238 -  
239 -| Property name | Type | Description |  
240 -|---------------|----------------|-------------------------------------|  
241 -| format | BarcodeFormat | |  
242 -| rawBytes | Uint8List? | binary scan result |  
243 -| rawValue | String? | Value if barcode is in UTF-8 format |  
244 -| displayValue | String? | |  
245 -| type | BarcodeType | |  
246 -| calendarEvent | CalendarEvent? | |  
247 -| contactInfo | ContactInfo? | |  
248 -| driverLicense | DriverLicense? | |  
249 -| email | Email? | |  
250 -| geoPoint | GeoPoint? | |  
251 -| phone | Phone? | |  
252 -| sms | SMS? | |  
253 -| url | UrlBookmark? | |  
254 -| wifi | WiFi? | WiFi Access-Point details | 157 +To display the camera preview, pass the controller to a `MobileScanner` widget.
  158 +
  159 +See the examples for runnable examples of various usages,
  160 +such as the basic usage, applying a scan window, or retrieving images from the barcodes.