Julian Steenbakker
Committed by GitHub

Merge branch 'master' into master

@@ -11,7 +11,7 @@ jobs: @@ -11,7 +11,7 @@ jobs:
11 analysis: 11 analysis:
12 runs-on: ubuntu-latest 12 runs-on: ubuntu-latest
13 steps: 13 steps:
14 - - uses: actions/checkout@v3.5.2 14 + - uses: actions/checkout@v3.5.3
15 - uses: actions/setup-java@v3.11.0 15 - uses: actions/setup-java@v3.11.0
16 with: 16 with:
17 java-version: 11 17 java-version: 11
@@ -28,7 +28,7 @@ jobs: @@ -28,7 +28,7 @@ jobs:
28 formatting: 28 formatting:
29 runs-on: ubuntu-latest 29 runs-on: ubuntu-latest
30 steps: 30 steps:
31 - - uses: actions/checkout@v3.5.2 31 + - uses: actions/checkout@v3.5.3
32 - uses: actions/setup-java@v3.11.0 32 - uses: actions/setup-java@v3.11.0
33 with: 33 with:
34 java-version: 11 34 java-version: 11
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 release-please: 7 release-please:
8 runs-on: ubuntu-latest 8 runs-on: ubuntu-latest
9 steps: 9 steps:
10 - - uses: GoogleCloudPlatform/release-please-action@v3.7.9 10 + - uses: GoogleCloudPlatform/release-please-action@v3.7.10
11 with: 11 with:
12 token: ${{ secrets.GITHUB_TOKEN }} 12 token: ${{ secrets.GITHUB_TOKEN }}
13 release-type: simple 13 release-type: simple
1 # This file tracks properties of this Flutter project. 1 # This file tracks properties of this Flutter project.
2 # Used by Flutter tool to assess capabilities and perform upgrades etc. 2 # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 # 3 #
4 -# This file should be version controlled and should not be manually edited. 4 +# This file should be version controlled.
5 5
6 version: 6 version:
7 - revision: 5f105a6ca7a5ac7b8bc9b241f4c2d86f4188cf5c 7 + revision: 796c8ef79279f9c774545b3771238c3098dbefab
8 channel: stable 8 channel: stable
9 9
10 project_type: plugin 10 project_type: plugin
  11 +
  12 +# Tracks metadata for the flutter migrate command
  13 +migration:
  14 + platforms:
  15 + - platform: root
  16 + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  17 + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  18 + - platform: android
  19 + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  20 + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  21 + - platform: ios
  22 + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  23 + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  24 + - platform: macos
  25 + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  26 + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  27 + - platform: web
  28 + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  29 + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
  30 +
  31 + # User provided section
  32 +
  33 + # List of Local paths (relative to this file) that should be
  34 + # ignored by the migrate tool.
  35 + #
  36 + # Files that are not part of the templates will be ignored by default.
  37 + unmanaged_files:
  38 + - 'lib/main.dart'
  39 + - 'ios/Runner.xcodeproj/project.pbxproj'
1 -## 3.2.1 1 +## 3.3.0
2 Bugs fixed: 2 Bugs fixed:
  3 +* Fixed bug where onDetect method was being called multiple times
3 * [Android] Fix Gradle 8 compatibility by adding the `namespace` attribute to the build.gradle. 4 * [Android] Fix Gradle 8 compatibility by adding the `namespace` attribute to the build.gradle.
4 5
  6 +Improvements:
  7 +* [Android] Upgraded camera2 dependency
  8 +* Added zoomScale value notifier in MobileScannerController for the application to know the zoom scale value set actually.
  9 + The value is notified from the native SDK(CameraX/AVFoundation).
  10 +* Added resetZoomScale() in MobileScannerController to reset zoom ratio with 1x.
  11 + Both Android and iOS, if the device have ultra-wide camera, calling setZoomScale with small value causes to use ultra-wide camera and may be diffcult to detect barcodes.
  12 + resetZoomScale() is useful to use standard camera with zoom 1x.
  13 + setZoomScale() with the specific value can realize same effect, but added resetZoomScale for avoiding floating point errors.
  14 + The application can know what zoom scale value is selected actually by subscribing zoomScale above after calling resetZoomScale.
  15 +* [iOS] Call resetZoomScale while starting scan.
  16 + Android camera is initialized with a zoom of 1x, whereas iOS is initialized with the minimum zoom value, which causes to select the ultra-wide camera unintentionally ([iOS] Impossible to focus and scan the QR code due to picking the wide back camera #554).
  17 + Fixed this issue by calling resetZoomScale
  18 +* [iOS] Remove zoom animation with ramp function to match Android behavior.
  19 +
5 ## 3.2.0 20 ## 3.2.0
6 Improvements: 21 Improvements:
7 * [iOS] Updated GoogleMLKit/BarcodeScanning to 4.0.0 22 * [iOS] Updated GoogleMLKit/BarcodeScanning to 4.0.0
@@ -54,6 +54,12 @@ Ensure that you granted camera permission in XCode -> Signing & Capabilities: @@ -54,6 +54,12 @@ Ensure that you granted camera permission in XCode -> Signing & Capabilities:
54 54
55 <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"> 55 <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">
56 56
  57 +## Web
  58 +This package uses ZXing on web to read barcodes so it needs to be included in `index.html` as script.
  59 +```html
  60 +<script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script>
  61 +```
  62 +
57 ## Usage 63 ## Usage
58 64
59 Import `package:mobile_scanner/mobile_scanner.dart`, and use the widget with or without the controller. 65 Import `package:mobile_scanner/mobile_scanner.dart`, and use the widget with or without the controller.
@@ -2,14 +2,14 @@ group 'dev.steenbakker.mobile_scanner' @@ -2,14 +2,14 @@ group 'dev.steenbakker.mobile_scanner'
2 version '1.0-SNAPSHOT' 2 version '1.0-SNAPSHOT'
3 3
4 buildscript { 4 buildscript {
5 - ext.kotlin_version = '1.7.22' 5 + ext.kotlin_version = '1.8.22'
6 repositories { 6 repositories {
7 google() 7 google()
8 mavenCentral() 8 mavenCentral()
9 } 9 }
10 10
11 dependencies { 11 dependencies {
12 - classpath 'com.android.tools.build:gradle:8.0.0' 12 + classpath 'com.android.tools.build:gradle:8.0.2'
13 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 } 14 }
15 } 15 }
@@ -56,5 +56,6 @@ dependencies { @@ -56,5 +56,6 @@ dependencies {
56 // implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0' 56 // implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0'
57 57
58 implementation 'androidx.camera:camera-camera2:1.2.2' 58 implementation 'androidx.camera:camera-camera2:1.2.2'
59 - implementation 'androidx.camera:camera-lifecycle:1.2.2' 59 + implementation 'androidx.camera:camera-lifecycle:1.2.3'
  60 + implementation 'androidx.camera:camera-camera2:1.2.3'
60 } 61 }
1 buildscript { 1 buildscript {
2 - ext.kotlin_version = '1.7.22' 2 + ext.kotlin_version = '1.8.22'
3 repositories { 3 repositories {
4 google() 4 google()
5 mavenCentral() 5 mavenCentral()
6 } 6 }
7 7
8 dependencies { 8 dependencies {
9 - classpath 'com.android.tools.build:gradle:8.0.0' 9 + classpath 'com.android.tools.build:gradle:8.0.2'
10 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 } 11 }
12 } 12 }
@@ -26,6 +26,6 @@ subprojects { @@ -26,6 +26,6 @@ subprojects {
26 project.evaluationDependsOn(':app') 26 project.evaluationDependsOn(':app')
27 } 27 }
28 28
29 -task clean(type: Delete) { 29 +tasks.register("clean", Delete) {
30 delete rootProject.buildDir 30 delete rootProject.buildDir
31 } 31 }
1 -#Tue Aug 23 15:51:00 CEST 2022 1 +#Tue Jun 27 18:47:05 CEST 2023
2 distributionBase=GRADLE_USER_HOME 2 distributionBase=GRADLE_USER_HOME
3 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip  
4 distributionPath=wrapper/dists 3 distributionPath=wrapper/dists
5 -zipStorePath=wrapper/dists 4 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
6 zipStoreBase=GRADLE_USER_HOME 5 zipStoreBase=GRADLE_USER_HOME
  6 +zipStorePath=wrapper/dists
@@ -204,6 +204,7 @@ @@ -204,6 +204,7 @@
204 files = ( 204 files = (
205 ); 205 );
206 inputPaths = ( 206 inputPaths = (
  207 + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
207 ); 208 );
208 name = "Thin Binary"; 209 name = "Thin Binary";
209 outputPaths = ( 210 outputPaths = (
@@ -50,6 +50,7 @@ class _BarcodeListScannerWithControllerState @@ -50,6 +50,7 @@ class _BarcodeListScannerWithControllerState
50 @override 50 @override
51 Widget build(BuildContext context) { 51 Widget build(BuildContext context) {
52 return Scaffold( 52 return Scaffold(
  53 + appBar: AppBar(title: const Text('With ValueListenableBuilder')),
53 backgroundColor: Colors.black, 54 backgroundColor: Colors.black,
54 body: Builder( 55 body: Builder(
55 builder: (context) { 56 builder: (context) {
@@ -50,6 +50,7 @@ class _BarcodeScannerWithControllerState @@ -50,6 +50,7 @@ class _BarcodeScannerWithControllerState
50 @override 50 @override
51 Widget build(BuildContext context) { 51 Widget build(BuildContext context) {
52 return Scaffold( 52 return Scaffold(
  53 + appBar: AppBar(title: const Text('With controller')),
53 backgroundColor: Colors.black, 54 backgroundColor: Colors.black,
54 body: Builder( 55 body: Builder(
55 builder: (context) { 56 builder: (context) {
@@ -70,6 +70,7 @@ class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView> @@ -70,6 +70,7 @@ class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView>
70 @override 70 @override
71 Widget build(BuildContext context) { 71 Widget build(BuildContext context) {
72 return Scaffold( 72 return Scaffold(
  73 + appBar: AppBar(title: const Text('With PageView')),
73 backgroundColor: Colors.black, 74 backgroundColor: Colors.black,
74 body: PageView( 75 body: PageView(
75 children: [ 76 children: [
@@ -52,6 +52,7 @@ class _BarcodeScannerReturningImageState @@ -52,6 +52,7 @@ class _BarcodeScannerReturningImageState
52 @override 52 @override
53 Widget build(BuildContext context) { 53 Widget build(BuildContext context) {
54 return Scaffold( 54 return Scaffold(
  55 + appBar: AppBar(title: const Text('Returning image')),
55 body: SafeArea( 56 body: SafeArea(
56 child: Column( 57 child: Column(
57 children: [ 58 children: [
@@ -3,6 +3,8 @@ import 'dart:io'; @@ -3,6 +3,8 @@ import 'dart:io';
3 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
4 import 'package:mobile_scanner/mobile_scanner.dart'; 4 import 'package:mobile_scanner/mobile_scanner.dart';
5 5
  6 +import 'package:mobile_scanner_example/scanner_error_widget.dart';
  7 +
6 class BarcodeScannerWithScanWindow extends StatefulWidget { 8 class BarcodeScannerWithScanWindow extends StatefulWidget {
7 const BarcodeScannerWithScanWindow({Key? key}) : super(key: key); 9 const BarcodeScannerWithScanWindow({Key? key}) : super(key: key);
8 10
@@ -32,6 +34,7 @@ class _BarcodeScannerWithScanWindowState @@ -32,6 +34,7 @@ class _BarcodeScannerWithScanWindowState
32 height: 200, 34 height: 200,
33 ); 35 );
34 return Scaffold( 36 return Scaffold(
  37 + appBar: AppBar(title: const Text('With Scan window')),
35 backgroundColor: Colors.black, 38 backgroundColor: Colors.black,
36 body: Builder( 39 body: Builder(
37 builder: (context) { 40 builder: (context) {
@@ -47,6 +50,9 @@ class _BarcodeScannerWithScanWindowState @@ -47,6 +50,9 @@ class _BarcodeScannerWithScanWindowState
47 this.arguments = arguments; 50 this.arguments = arguments;
48 }); 51 });
49 }, 52 },
  53 + errorBuilder: (context, error, child) {
  54 + return ScannerErrorWidget(error: error);
  55 + },
50 onDetect: onDetect, 56 onDetect: onDetect,
51 ), 57 ),
52 if (barcode != null && 58 if (barcode != null &&
@@ -18,6 +18,7 @@ class _BarcodeScannerWithoutControllerState @@ -18,6 +18,7 @@ class _BarcodeScannerWithoutControllerState
18 @override 18 @override
19 Widget build(BuildContext context) { 19 Widget build(BuildContext context) {
20 return Scaffold( 20 return Scaffold(
  21 + appBar: AppBar(title: const Text('Without controller')),
21 backgroundColor: Colors.black, 22 backgroundColor: Colors.black,
22 body: Builder( 23 body: Builder(
23 builder: (context) { 24 builder: (context) {
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; @@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
2 import 'package:image_picker/image_picker.dart'; 2 import 'package:image_picker/image_picker.dart';
3 import 'package:mobile_scanner/mobile_scanner.dart'; 3 import 'package:mobile_scanner/mobile_scanner.dart';
4 4
  5 +import 'package:mobile_scanner_example/scanner_error_widget.dart';
  6 +
5 class BarcodeScannerWithZoom extends StatefulWidget { 7 class BarcodeScannerWithZoom extends StatefulWidget {
6 const BarcodeScannerWithZoom({Key? key}) : super(key: key); 8 const BarcodeScannerWithZoom({Key? key}) : super(key: key);
7 9
@@ -23,6 +25,7 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -23,6 +25,7 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
23 @override 25 @override
24 Widget build(BuildContext context) { 26 Widget build(BuildContext context) {
25 return Scaffold( 27 return Scaffold(
  28 + appBar: AppBar(title: const Text('With zoom slider')),
26 backgroundColor: Colors.black, 29 backgroundColor: Colors.black,
27 body: Builder( 30 body: Builder(
28 builder: (context) { 31 builder: (context) {
@@ -31,6 +34,9 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -31,6 +34,9 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
31 MobileScanner( 34 MobileScanner(
32 controller: controller, 35 controller: controller,
33 fit: BoxFit.contain, 36 fit: BoxFit.contain,
  37 + errorBuilder: (context, error, child) {
  38 + return ScannerErrorWidget(error: error);
  39 + },
34 onDetect: (barcode) { 40 onDetect: (barcode) {
35 setState(() { 41 setState(() {
36 this.barcode = barcode; 42 this.barcode = barcode;
@@ -17,6 +17,9 @@ class ScannerErrorWidget extends StatelessWidget { @@ -17,6 +17,9 @@ class ScannerErrorWidget extends StatelessWidget {
17 case MobileScannerErrorCode.permissionDenied: 17 case MobileScannerErrorCode.permissionDenied:
18 errorMessage = 'Permission denied'; 18 errorMessage = 'Permission denied';
19 break; 19 break;
  20 + case MobileScannerErrorCode.unsupported:
  21 + errorMessage = 'Scanning is unsupported on this device';
  22 + break;
20 default: 23 default:
21 errorMessage = 'Generic Error'; 24 errorMessage = 'Generic Error';
22 break; 25 break;
@@ -3,12 +3,12 @@ description: Demonstrates how to use the mobile_scanner plugin. @@ -3,12 +3,12 @@ description: Demonstrates how to use the mobile_scanner plugin.
3 publish_to: 'none' # Remove this line if you wish to publish to pub.dev 3 publish_to: 'none' # Remove this line if you wish to publish to pub.dev
4 4
5 environment: 5 environment:
6 - sdk: ">=2.12.0 <3.0.0" 6 + sdk: ">=2.12.0 <4.0.0"
7 7
8 dependencies: 8 dependencies:
9 flutter: 9 flutter:
10 sdk: flutter 10 sdk: flutter
11 - image_picker: ^0.8.7 11 + image_picker: ^1.0.0
12 12
13 mobile_scanner: 13 mobile_scanner:
14 path: ../ 14 path: ../
@@ -8,38 +8,53 @@ @@ -8,38 +8,53 @@
8 The path provided below has to start and end with a slash "/" in order for 8 The path provided below has to start and end with a slash "/" in order for
9 it to work correctly. 9 it to work correctly.
10 10
11 - Fore more details: 11 + For more details:
12 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base 12 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
  13 +
  14 + This is a placeholder for base href that will be replaced by the value of
  15 + the `--base-href` argument provided to `flutter build`.
13 --> 16 -->
14 - <base href="/"> 17 + <base href="$FLUTTER_BASE_HREF">
15 18
16 <meta charset="UTF-8"> 19 <meta charset="UTF-8">
17 <meta content="IE=Edge" http-equiv="X-UA-Compatible"> 20 <meta content="IE=Edge" http-equiv="X-UA-Compatible">
18 - <meta name="description" content="A new Flutter project."> 21 + <meta name="description" content="Demonstrates how to use the mobile_scanner plugin.">
19 22
20 <!-- iOS meta tags & icons --> 23 <!-- iOS meta tags & icons -->
21 <meta name="apple-mobile-web-app-capable" content="yes"> 24 <meta name="apple-mobile-web-app-capable" content="yes">
22 <meta name="apple-mobile-web-app-status-bar-style" content="black"> 25 <meta name="apple-mobile-web-app-status-bar-style" content="black">
23 - <meta name="apple-mobile-web-app-title" content="example"> 26 + <meta name="apple-mobile-web-app-title" content="mobile_scanner_example">
24 <link rel="apple-touch-icon" href="icons/Icon-192.png"> 27 <link rel="apple-touch-icon" href="icons/Icon-192.png">
25 28
26 <!-- Favicon --> 29 <!-- Favicon -->
27 <link rel="icon" type="image/png" href="favicon.png"/> 30 <link rel="icon" type="image/png" href="favicon.png"/>
28 31
29 - <title>example</title> 32 + <title>mobile_scanner_example</title>
30 <link rel="manifest" href="manifest.json"> 33 <link rel="manifest" href="manifest.json">
  34 +
  35 + <script>
  36 + // The value below is injected by flutter build, do not touch.
  37 + var serviceWorkerVersion = null;
  38 + </script>
  39 + <!-- This script adds the flutter initialization JS code -->
  40 + <script src="flutter.js" defer></script>
31 </head> 41 </head>
32 <body> 42 <body>
33 - <!-- This script installs service_worker.js to provide PWA functionality to  
34 - application. For more information, see:  
35 - https://developers.google.com/web/fundamentals/primers/service-workers --> 43 + <script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script>
36 <script> 44 <script>
37 - if ('serviceWorker' in navigator) {  
38 - window.addEventListener('flutter-first-frame', function () {  
39 - navigator.serviceWorker.register('flutter_service_worker.js'); 45 + window.addEventListener('load', function(ev) {
  46 + // Download main.dart.js
  47 + _flutter.loader.loadEntrypoint({
  48 + serviceWorker: {
  49 + serviceWorkerVersion: serviceWorkerVersion,
  50 + },
  51 + onEntrypointLoaded: function(engineInitializer) {
  52 + engineInitializer.initializeEngine().then(function(appRunner) {
  53 + appRunner.runApp();
40 }); 54 });
41 } 55 }
  56 + });
  57 + });
42 </script> 58 </script>
43 - <script src="main.dart.js" type="application/javascript"></script>  
44 </body> 59 </body>
45 </html> 60 </html>
1 { 1 {
2 - "name": "Mobile Scanner Example", 2 + "name": "mobile_scanner_example",
3 "short_name": "mobile_scanner_example", 3 "short_name": "mobile_scanner_example",
4 "start_url": ".", 4 "start_url": ".",
5 "display": "standalone", 5 "display": "standalone",
6 "background_color": "#0175C2", 6 "background_color": "#0175C2",
7 "theme_color": "#0175C2", 7 "theme_color": "#0175C2",
8 - "description": "A barcode and qr code scanner example.", 8 + "description": "Demonstrates how to use the mobile_scanner plugin.",
9 "orientation": "portrait-primary", 9 "orientation": "portrait-primary",
10 "prefer_related_applications": false, 10 "prefer_related_applications": false,
11 "icons": [ 11 "icons": [
@@ -18,6 +18,18 @@ @@ -18,6 +18,18 @@
18 "src": "icons/Icon-512.png", 18 "src": "icons/Icon-512.png",
19 "sizes": "512x512", 19 "sizes": "512x512",
20 "type": "image/png" 20 "type": "image/png"
  21 + },
  22 + {
  23 + "src": "icons/Icon-maskable-192.png",
  24 + "sizes": "192x192",
  25 + "type": "image/png",
  26 + "purpose": "maskable"
  27 + },
  28 + {
  29 + "src": "icons/Icon-maskable-512.png",
  30 + "sizes": "512x512",
  31 + "type": "image/png",
  32 + "purpose": "maskable"
21 } 33 }
22 ] 34 ]
23 } 35 }
@@ -227,6 +227,8 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -227,6 +227,8 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
227 for output in captureSession.outputs { 227 for output in captureSession.outputs {
228 captureSession.removeOutput(output) 228 captureSession.removeOutput(output)
229 } 229 }
  230 +
  231 + latestBuffer = nil
230 device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode)) 232 device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode))
231 device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.videoZoomFactor)) 233 device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.videoZoomFactor))
232 registry?.unregisterTexture(textureId) 234 registry?.unregisterTexture(textureId)
@@ -8,7 +8,6 @@ import 'package:mobile_scanner/mobile_scanner_web.dart'; @@ -8,7 +8,6 @@ import 'package:mobile_scanner/mobile_scanner_web.dart';
8 import 'package:mobile_scanner/src/barcode_utility.dart'; 8 import 'package:mobile_scanner/src/barcode_utility.dart';
9 import 'package:mobile_scanner/src/enums/camera_facing.dart'; 9 import 'package:mobile_scanner/src/enums/camera_facing.dart';
10 import 'package:mobile_scanner/src/objects/barcode.dart'; 10 import 'package:mobile_scanner/src/objects/barcode.dart';
11 -import 'package:mobile_scanner/src/web/utils.dart';  
12 11
13 /// This plugin is the web implementation of mobile_scanner. 12 /// This plugin is the web implementation of mobile_scanner.
14 /// It only supports QR codes. 13 /// It only supports QR codes.
@@ -26,8 +25,6 @@ class MobileScannerWebPlugin { @@ -26,8 +25,6 @@ class MobileScannerWebPlugin {
26 ); 25 );
27 final MobileScannerWebPlugin instance = MobileScannerWebPlugin(); 26 final MobileScannerWebPlugin instance = MobileScannerWebPlugin();
28 27
29 - _jsLibrariesLoadingFuture = injectJSLibraries(barCodeReader.jsLibraries);  
30 -  
31 channel.setMethodCallHandler(instance.handleMethodCall); 28 channel.setMethodCallHandler(instance.handleMethodCall);
32 event.setController(instance.controller); 29 event.setController(instance.controller);
33 } 30 }
@@ -55,11 +52,8 @@ class MobileScannerWebPlugin { @@ -55,11 +52,8 @@ class MobileScannerWebPlugin {
55 ZXingBarcodeReader(videoContainer: vidDiv); 52 ZXingBarcodeReader(videoContainer: vidDiv);
56 StreamSubscription? _barCodeStreamSubscription; 53 StreamSubscription? _barCodeStreamSubscription;
57 54
58 - static late Future _jsLibrariesLoadingFuture;  
59 -  
60 /// Handle incomming messages 55 /// Handle incomming messages
61 Future<dynamic> handleMethodCall(MethodCall call) async { 56 Future<dynamic> handleMethodCall(MethodCall call) async {
62 - await _jsLibrariesLoadingFuture;  
63 switch (call.method) { 57 switch (call.method) {
64 case 'start': 58 case 'start':
65 return _start(call.arguments as Map); 59 return _start(call.arguments as Map);
@@ -67,6 +61,8 @@ class MobileScannerWebPlugin { @@ -67,6 +61,8 @@ class MobileScannerWebPlugin {
67 return _torch(call.arguments); 61 return _torch(call.arguments);
68 case 'stop': 62 case 'stop':
69 return cancel(); 63 return cancel();
  64 + case 'updateScanWindow':
  65 + return Future<void>.value();
70 default: 66 default:
71 throw PlatformException( 67 throw PlatformException(
72 code: 'Unimplemented', 68 code: 'Unimplemented',
@@ -117,12 +113,14 @@ class MobileScannerWebPlugin { @@ -117,12 +113,14 @@ class MobileScannerWebPlugin {
117 .map((e) => toFormat(e)) 113 .map((e) => toFormat(e))
118 .toList(); 114 .toList();
119 } 115 }
  116 +
120 final Duration? detectionTimeout; 117 final Duration? detectionTimeout;
121 if (arguments.containsKey('timeout')) { 118 if (arguments.containsKey('timeout')) {
122 detectionTimeout = Duration(milliseconds: arguments['timeout'] as int); 119 detectionTimeout = Duration(milliseconds: arguments['timeout'] as int);
123 } else { 120 } else {
124 detectionTimeout = null; 121 detectionTimeout = null;
125 } 122 }
  123 +
126 await barCodeReader.start( 124 await barCodeReader.start(
127 cameraFacing: cameraFacing, 125 cameraFacing: cameraFacing,
128 formats: formats, 126 formats: formats,
@@ -132,20 +130,31 @@ class MobileScannerWebPlugin { @@ -132,20 +130,31 @@ class MobileScannerWebPlugin {
132 _barCodeStreamSubscription = 130 _barCodeStreamSubscription =
133 barCodeReader.detectBarcodeContinuously().listen((code) { 131 barCodeReader.detectBarcodeContinuously().listen((code) {
134 if (code != null) { 132 if (code != null) {
  133 + final List<Offset>? corners = code.corners;
  134 +
135 controller.add({ 135 controller.add({
136 'name': 'barcodeWeb', 136 'name': 'barcodeWeb',
137 'data': { 137 'data': {
138 'rawValue': code.rawValue, 138 'rawValue': code.rawValue,
139 'rawBytes': code.rawBytes, 139 'rawBytes': code.rawBytes,
140 'format': code.format.rawValue, 140 'format': code.format.rawValue,
  141 + 'displayValue': code.displayValue,
  142 + 'type': code.type.index,
  143 + if (corners != null && corners.isNotEmpty)
  144 + 'corners': corners
  145 + .map(
  146 + (Offset c) => <Object?, Object?>{'x': c.dx, 'y': c.dy},
  147 + )
  148 + .toList(),
141 }, 149 },
142 }); 150 });
143 } 151 }
144 }); 152 });
  153 +
145 final hasTorch = await barCodeReader.hasTorch(); 154 final hasTorch = await barCodeReader.hasTorch();
146 155
147 if (hasTorch && arguments.containsKey('torch')) { 156 if (hasTorch && arguments.containsKey('torch')) {
148 - barCodeReader.toggleTorch(enabled: arguments['torch'] as bool); 157 + await barCodeReader.toggleTorch(enabled: arguments['torch'] as bool);
149 } 158 }
150 159
151 return { 160 return {
@@ -154,8 +163,12 @@ class MobileScannerWebPlugin { @@ -154,8 +163,12 @@ class MobileScannerWebPlugin {
154 'videoHeight': barCodeReader.videoHeight, 163 'videoHeight': barCodeReader.videoHeight,
155 'torchable': hasTorch, 164 'torchable': hasTorch,
156 }; 165 };
157 - } catch (e) {  
158 - throw PlatformException(code: 'MobileScannerWeb', message: '$e'); 166 + } catch (e, stackTrace) {
  167 + throw PlatformException(
  168 + code: 'MobileScannerWeb',
  169 + message: '$e',
  170 + details: stackTrace.toString(),
  171 + );
159 } 172 }
160 } 173 }
161 174
@@ -9,14 +9,16 @@ Size toSize(Map data) { @@ -9,14 +9,16 @@ Size toSize(Map data) {
9 return Size(width, height); 9 return Size(width, height);
10 } 10 }
11 11
12 -List<Offset>? toCorners(List? data) {  
13 - if (data != null) {  
14 - return List.unmodifiable(  
15 - data.map((e) => Offset((e as Map)['x'] as double, e['y'] as double)),  
16 - );  
17 - } else { 12 +List<Offset>? toCorners(List<Map<Object?, Object?>>? data) {
  13 + if (data == null) {
18 return null; 14 return null;
19 } 15 }
  16 +
  17 + return List.unmodifiable(
  18 + data.map((Map<Object?, Object?> e) {
  19 + return Offset(e['x']! as double, e['y']! as double);
  20 + }),
  21 + );
20 } 22 }
21 23
22 BarcodeFormat toFormat(int value) { 24 BarcodeFormat toFormat(int value) {
@@ -11,4 +11,7 @@ enum MobileScannerErrorCode { @@ -11,4 +11,7 @@ enum MobileScannerErrorCode {
11 11
12 /// The permission to use the camera was denied. 12 /// The permission to use the camera was denied.
13 permissionDenied, 13 permissionDenied,
  14 +
  15 + /// Scanning is unsupported on the current device.
  16 + unsupported,
14 } 17 }
@@ -132,7 +132,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -132,7 +132,6 @@ class _MobileScannerState extends State<MobileScanner>
132 widget.onStart?.call(arguments); 132 widget.onStart?.call(arguments);
133 widget.onScannerStarted?.call(arguments); 133 widget.onScannerStarted?.call(arguments);
134 }).catchError((error) { 134 }).catchError((error) {
135 - debugPrint('mobile_scanner: $error');  
136 if (mounted) { 135 if (mounted) {
137 setState(() { 136 setState(() {
138 _startException = error as MobileScannerException; 137 _startException = error as MobileScannerException;
@@ -247,8 +246,8 @@ class _MobileScannerState extends State<MobileScanner> @@ -247,8 +246,8 @@ class _MobileScannerState extends State<MobileScanner>
247 246
248 @override 247 @override
249 Widget build(BuildContext context) { 248 Widget build(BuildContext context) {
250 - return LayoutBuilder(  
251 - builder: (context, constraints) { 249 + final Size size = MediaQuery.sizeOf(context);
  250 +
252 return ValueListenableBuilder<MobileScannerArguments?>( 251 return ValueListenableBuilder<MobileScannerArguments?>(
253 valueListenable: _controller.startArguments, 252 valueListenable: _controller.startArguments,
254 builder: (context, value, child) { 253 builder: (context, value, child) {
@@ -261,7 +260,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -261,7 +260,7 @@ class _MobileScannerState extends State<MobileScanner>
261 widget.fit, 260 widget.fit,
262 widget.scanWindow!, 261 widget.scanWindow!,
263 value.size, 262 value.size,
264 - Size(constraints.maxWidth, constraints.maxHeight), 263 + size,
265 ); 264 );
266 265
267 _controller.updateScanWindow(scanWindow); 266 _controller.updateScanWindow(scanWindow);
@@ -274,10 +273,8 @@ class _MobileScannerState extends State<MobileScanner> @@ -274,10 +273,8 @@ class _MobileScannerState extends State<MobileScanner>
274 size: constraints.biggest, 273 size: constraints.biggest,
275 child: FittedBox( 274 child: FittedBox(
276 fit: widget.fit, 275 fit: widget.fit,
277 - // alignment: Alignment.topCenter,  
278 - child: SizedBox(  
279 - width: value.size.width,  
280 - height: value.size.height, 276 + child: SizedBox.fromSize(
  277 + size: value.size,
281 child: kIsWeb 278 child: kIsWeb
282 ? HtmlElementView(viewType: value.webId!) 279 ? HtmlElementView(viewType: value.webId!)
283 : Texture(textureId: value.textureId!), 280 : Texture(textureId: value.textureId!),
@@ -289,8 +286,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -289,8 +286,6 @@ class _MobileScannerState extends State<MobileScanner>
289 ); 286 );
290 }, 287 },
291 ); 288 );
292 - },  
293 - );  
294 } 289 }
295 290
296 @override 291 @override
@@ -207,9 +207,21 @@ class MobileScannerController { @@ -207,9 +207,21 @@ class MobileScannerController {
207 } on PlatformException catch (error) { 207 } on PlatformException catch (error) {
208 MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError; 208 MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError;
209 209
210 - if (error.code == "MobileScannerWeb") { 210 + final String? errorMessage = error.message;
  211 +
  212 + if (kIsWeb) {
  213 + if (errorMessage == null) {
  214 + errorCode = MobileScannerErrorCode.genericError;
  215 + } else if (errorMessage.contains('NotFoundError') ||
  216 + errorMessage.contains('NotSupportedError')) {
  217 + errorCode = MobileScannerErrorCode.unsupported;
  218 + } else if (errorMessage.contains('NotAllowedError')) {
211 errorCode = MobileScannerErrorCode.permissionDenied; 219 errorCode = MobileScannerErrorCode.permissionDenied;
  220 + } else {
  221 + errorCode = MobileScannerErrorCode.genericError;
212 } 222 }
  223 + }
  224 +
213 isStarting = false; 225 isStarting = false;
214 226
215 throw MobileScannerException( 227 throw MobileScannerException(
@@ -388,6 +400,10 @@ class MobileScannerController { @@ -388,6 +400,10 @@ class MobileScannerController {
388 rawValue: barcode['rawValue'] as String?, 400 rawValue: barcode['rawValue'] as String?,
389 rawBytes: barcode['rawBytes'] as Uint8List?, 401 rawBytes: barcode['rawBytes'] as Uint8List?,
390 format: toFormat(barcode['format'] as int), 402 format: toFormat(barcode['format'] as int),
  403 + corners: toCorners(
  404 + (barcode['corners'] as List<Object?>? ?? [])
  405 + .cast<Map<Object?, Object?>>(),
  406 + ),
391 ), 407 ),
392 ], 408 ],
393 ), 409 ),
@@ -92,7 +92,9 @@ class Barcode { @@ -92,7 +92,9 @@ class Barcode {
92 92
93 /// Create a [Barcode] from native data. 93 /// Create a [Barcode] from native data.
94 Barcode.fromNative(Map data) 94 Barcode.fromNative(Map data)
95 - : corners = toCorners(data['corners'] as List?), 95 + : corners = toCorners(
  96 + (data['corners'] as List?)?.cast<Map<Object?, Object?>>(),
  97 + ),
96 format = toFormat(data['format'] as int), 98 format = toFormat(data['format'] as int),
97 rawBytes = data['rawBytes'] as Uint8List?, 99 rawBytes = data['rawBytes'] as Uint8List?,
98 rawValue = data['rawValue'] as String?, 100 rawValue = data['rawValue'] as String?,
@@ -201,18 +203,20 @@ class ContactInfo { @@ -201,18 +203,20 @@ class ContactInfo {
201 /// Create a [ContactInfo] from native data. 203 /// Create a [ContactInfo] from native data.
202 ContactInfo.fromNative(Map data) 204 ContactInfo.fromNative(Map data)
203 : addresses = List.unmodifiable( 205 : addresses = List.unmodifiable(
204 - (data['addresses'] as List).map((e) => Address.fromNative(e as Map)), 206 + (data['addresses'] as List? ?? [])
  207 + .cast<Map>()
  208 + .map(Address.fromNative),
205 ), 209 ),
206 emails = List.unmodifiable( 210 emails = List.unmodifiable(
207 - (data['emails'] as List).map((e) => Email.fromNative(e as Map)), 211 + (data['emails'] as List? ?? []).cast<Map>().map(Email.fromNative),
208 ), 212 ),
209 name = toName(data['name'] as Map?), 213 name = toName(data['name'] as Map?),
210 organization = data['organization'] as String?, 214 organization = data['organization'] as String?,
211 phones = List.unmodifiable( 215 phones = List.unmodifiable(
212 - (data['phones'] as List).map((e) => Phone.fromNative(e as Map)), 216 + (data['phones'] as List? ?? []).cast<Map>().map(Phone.fromNative),
213 ), 217 ),
214 title = data['title'] as String?, 218 title = data['title'] as String?,
215 - urls = List.unmodifiable(data['urls'] as List); 219 + urls = List.unmodifiable((data['urls'] as List? ?? []).cast<String>());
216 } 220 }
217 221
218 /// An address. 222 /// An address.
@@ -227,7 +231,9 @@ class Address { @@ -227,7 +231,9 @@ class Address {
227 231
228 /// Create a [Address] from native data. 232 /// Create a [Address] from native data.
229 Address.fromNative(Map data) 233 Address.fromNative(Map data)
230 - : addressLines = List.unmodifiable(data['addressLines'] as List), 234 + : addressLines = List.unmodifiable(
  235 + (data['addressLines'] as List? ?? []).cast<String>(),
  236 + ),
231 type = AddressType.values[data['type'] as int]; 237 type = AddressType.values[data['type'] as int];
232 } 238 }
233 239
@@ -39,9 +39,6 @@ abstract class WebBarcodeReaderBase { @@ -39,9 +39,6 @@ abstract class WebBarcodeReaderBase {
39 int get videoWidth; 39 int get videoWidth;
40 int get videoHeight; 40 int get videoHeight;
41 41
42 - /// JS libraries to be injected into html page.  
43 - List<JsLibrary> get jsLibraries;  
44 -  
45 /// Starts streaming video 42 /// Starts streaming video
46 Future<void> start({ 43 Future<void> start({
47 required CameraFacing cameraFacing, 44 required CameraFacing cameraFacing,
@@ -128,10 +125,8 @@ mixin InternalTorchDetection on InternalStreamCreation { @@ -128,10 +125,8 @@ mixin InternalTorchDetection on InternalStreamCreation {
128 final photoCapabilities = await promiseToFuture<PhotoCapabilities>( 125 final photoCapabilities = await promiseToFuture<PhotoCapabilities>(
129 imageCapture.getPhotoCapabilities(), 126 imageCapture.getPhotoCapabilities(),
130 ); 127 );
131 - final fillLightMode = photoCapabilities.fillLightMode;  
132 - if (fillLightMode != null) {  
133 - return fillLightMode;  
134 - } 128 +
  129 + return photoCapabilities.fillLightMode;
135 } 130 }
136 } catch (e) { 131 } catch (e) {
137 // ImageCapture is not supported by some browsers: 132 // ImageCapture is not supported by some browsers:
@@ -165,9 +160,16 @@ class Promise<T> {} @@ -165,9 +160,16 @@ class Promise<T> {}
165 160
166 @JS() 161 @JS()
167 @anonymous 162 @anonymous
168 -class PhotoCapabilities { 163 +@staticInterop
  164 +class PhotoCapabilities {}
  165 +
  166 +extension PhotoCapabilitiesExtension on PhotoCapabilities {
  167 + @JS('fillLightMode')
  168 + external List<dynamic>? get _fillLightMode;
  169 +
169 /// Returns an array of available fill light options. Options include auto, off, or flash. 170 /// Returns an array of available fill light options. Options include auto, off, or flash.
170 - external List<String>? get fillLightMode; 171 + List<String> get fillLightMode =>
  172 + _fillLightMode?.cast<String>() ?? <String>[];
171 } 173 }
172 174
173 @JS('ImageCapture') 175 @JS('ImageCapture')
@@ -20,12 +20,6 @@ class Code { @@ -20,12 +20,6 @@ class Code {
20 external Uint8ClampedList get binaryData; 20 external Uint8ClampedList get binaryData;
21 } 21 }
22 22
23 -const jsqrLibrary = JsLibrary(  
24 - contextName: 'jsQR',  
25 - url: 'https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js',  
26 - usesRequireJs: true,  
27 -);  
28 -  
29 /// Barcode reader that uses jsQR library. 23 /// Barcode reader that uses jsQR library.
30 /// jsQR supports only QR codes format. 24 /// jsQR supports only QR codes format.
31 class JsQrCodeReader extends WebBarcodeReaderBase 25 class JsQrCodeReader extends WebBarcodeReaderBase
@@ -36,9 +30,6 @@ class JsQrCodeReader extends WebBarcodeReaderBase @@ -36,9 +30,6 @@ class JsQrCodeReader extends WebBarcodeReaderBase
36 bool get isStarted => localMediaStream != null; 30 bool get isStarted => localMediaStream != null;
37 31
38 @override 32 @override
39 - List<JsLibrary> get jsLibraries => [jsqrLibrary];  
40 -  
41 - @override  
42 Future<void> start({ 33 Future<void> start({
43 required CameraFacing cameraFacing, 34 required CameraFacing cameraFacing,
44 List<BarcodeFormat>? formats, 35 List<BarcodeFormat>? formats,
1 -import 'dart:async';  
2 -import 'dart:html' as html;  
3 -import 'dart:js' show JsObject, context;  
4 -  
5 -import 'package:mobile_scanner/src/web/base.dart';  
6 -  
7 -Future<void> loadScript(JsLibrary library) async {  
8 - dynamic amd;  
9 - dynamic define;  
10 - // ignore: avoid_dynamic_calls  
11 - if (library.usesRequireJs && context['define']?['amd'] != null) {  
12 - // In dev, requireJs is loaded in. Disable it here.  
13 - // see https://github.com/dart-lang/sdk/issues/33979  
14 - define = JsObject.fromBrowserObject(context['define'] as Object);  
15 - // ignore: avoid_dynamic_calls  
16 - amd = define['amd'];  
17 - // ignore: avoid_dynamic_calls  
18 - define['amd'] = false;  
19 - }  
20 - try {  
21 - await loadScriptUsingScriptTag(library.url);  
22 - } finally {  
23 - if (amd != null) {  
24 - // Re-enable requireJs  
25 - // ignore: avoid_dynamic_calls  
26 - define['amd'] = amd;  
27 - }  
28 - }  
29 -}  
30 -  
31 -Future<void> loadScriptUsingScriptTag(String url) {  
32 - final script = html.ScriptElement()  
33 - ..async = true  
34 - ..defer = false  
35 - ..crossOrigin = 'anonymous'  
36 - ..type = 'text/javascript'  
37 - // ignore: unsafe_html  
38 - ..src = url;  
39 -  
40 - html.document.head!.append(script);  
41 -  
42 - return script.onLoad.first;  
43 -}  
44 -  
45 -/// Injects JS [libraries]  
46 -///  
47 -/// Returns a [Future] that resolves when all of the `script` tags `onLoad` events trigger.  
48 -Future<void> injectJSLibraries(List<JsLibrary> libraries) {  
49 - final List<Future<void>> loading = [];  
50 -  
51 - for (final library in libraries) {  
52 - final future = loadScript(library);  
53 - loading.add(future);  
54 - }  
55 -  
56 - return Future.wait(loading);  
57 -}  
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:html'; 2 import 'dart:html';
3 import 'dart:typed_data'; 3 import 'dart:typed_data';
  4 +import 'dart:ui';
4 5
5 import 'package:js/js.dart'; 6 import 'package:js/js.dart';
6 import 'package:mobile_scanner/src/enums/camera_facing.dart'; 7 import 'package:mobile_scanner/src/enums/camera_facing.dart';
@@ -19,6 +20,16 @@ class JsZXingBrowserMultiFormatReader { @@ -19,6 +20,16 @@ class JsZXingBrowserMultiFormatReader {
19 20
20 @JS() 21 @JS()
21 @anonymous 22 @anonymous
  23 +abstract class ResultPoint {
  24 + /// The x coordinate of the point.
  25 + external double get x;
  26 +
  27 + /// The y coordinate of the point.
  28 + external double get y;
  29 +}
  30 +
  31 +@JS()
  32 +@anonymous
22 abstract class Result { 33 abstract class Result {
23 /// raw text encoded by the barcode 34 /// raw text encoded by the barcode
24 external String get text; 35 external String get text;
@@ -28,15 +39,24 @@ abstract class Result { @@ -28,15 +39,24 @@ abstract class Result {
28 39
29 /// Representing the format of the barcode that was decoded 40 /// Representing the format of the barcode that was decoded
30 external int? format; 41 external int? format;
  42 +
  43 + /// Returns the result points of the barcode. These points represent the corners of the barcode.
  44 + external List<Object?> get resultPoints;
31 } 45 }
32 46
33 extension ResultExt on Result { 47 extension ResultExt on Result {
34 Barcode toBarcode() { 48 Barcode toBarcode() {
  49 + final corners = resultPoints
  50 + .cast<ResultPoint>()
  51 + .map((ResultPoint rp) => Offset(rp.x, rp.y))
  52 + .toList();
  53 +
35 final rawBytes = this.rawBytes; 54 final rawBytes = this.rawBytes;
36 return Barcode( 55 return Barcode(
37 rawValue: text, 56 rawValue: text,
38 rawBytes: rawBytes != null ? Uint8List.fromList(rawBytes) : null, 57 rawBytes: rawBytes != null ? Uint8List.fromList(rawBytes) : null,
39 format: barcodeFormat, 58 format: barcodeFormat,
  59 + corners: corners,
40 ); 60 );
41 } 61 }
42 62
@@ -168,12 +188,6 @@ extension JsZXingBrowserMultiFormatReaderExt @@ -168,12 +188,6 @@ extension JsZXingBrowserMultiFormatReaderExt
168 external MediaStream? stream; 188 external MediaStream? stream;
169 } 189 }
170 190
171 -const zxingJsLibrary = JsLibrary(  
172 - contextName: 'ZXing',  
173 - url: 'https://unpkg.com/@zxing/library@0.19.1',  
174 - usesRequireJs: true,  
175 -);  
176 -  
177 /// Barcode reader that uses zxing-js library. 191 /// Barcode reader that uses zxing-js library.
178 class ZXingBarcodeReader extends WebBarcodeReaderBase 192 class ZXingBarcodeReader extends WebBarcodeReaderBase
179 with InternalStreamCreation, InternalTorchDetection { 193 with InternalStreamCreation, InternalTorchDetection {
@@ -185,9 +199,6 @@ class ZXingBarcodeReader extends WebBarcodeReaderBase @@ -185,9 +199,6 @@ class ZXingBarcodeReader extends WebBarcodeReaderBase
185 bool get isStarted => localMediaStream != null; 199 bool get isStarted => localMediaStream != null;
186 200
187 @override 201 @override
188 - List<JsLibrary> get jsLibraries => [zxingJsLibrary];  
189 -  
190 - @override  
191 Future<void> start({ 202 Future<void> start({
192 required CameraFacing cameraFacing, 203 required CameraFacing cameraFacing,
193 List<BarcodeFormat>? formats, 204 List<BarcodeFormat>? formats,
1 name: mobile_scanner 1 name: mobile_scanner
2 description: A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS. 2 description: A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS.
3 -version: 3.2.1 3 +version: 3.3.0
4 repository: https://github.com/juliansteenbakker/mobile_scanner 4 repository: https://github.com/juliansteenbakker/mobile_scanner
5 5
6 environment: 6 environment:
7 - sdk: ">=2.17.0 <3.0.0" 7 + sdk: ">=2.17.0 <4.0.0"
8 flutter: ">=3.0.0" 8 flutter: ">=3.0.0"
9 9
10 dependencies: 10 dependencies:
@@ -14,7 +14,6 @@ dependencies: @@ -14,7 +14,6 @@ dependencies:
14 sdk: flutter 14 sdk: flutter
15 js: ^0.6.3 15 js: ^0.6.3
16 16
17 -  
18 dev_dependencies: 17 dev_dependencies:
19 flutter_test: 18 flutter_test:
20 sdk: flutter 19 sdk: flutter