├── .dart_tool ├── version ├── package_config_subset └── package_config.json ├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterQrBarScannerPlugin.h │ ├── Atomic.swift │ ├── FlutterQrBarScannerPlugin.m │ ├── SwiftQrBarScannerPlugin.swift │ └── QrReader.swift ├── .gitignore └── flutter_qr_bar_scanner.podspec ├── android ├── gradle.properties ├── src │ └── main │ │ ├── res │ │ └── values │ │ │ ├── strings.xml │ │ │ └── style.xml │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── contactlutforrahman │ │ │ └── flutter_qr_bar_scanner │ │ │ ├── NoPermissionException.java │ │ │ ├── QrReaderCallbacks.java │ │ │ ├── QrCamera.java │ │ │ ├── Heartbeat.java │ │ │ ├── QrDetector.java │ │ │ ├── BarcodeFormats.java │ │ │ ├── QrReader.java │ │ │ ├── QrCameraC1.java │ │ │ ├── FlutterQrBarScannerPlugin.java │ │ │ └── QrCameraC2.java │ │ └── AndroidManifest.xml ├── settings.gradle ├── .gitignore ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── build.gradle ├── .idea ├── .gitignore ├── misc.xml ├── vcs.xml ├── runConfigurations │ └── example_lib_main_dart.xml ├── libraries │ ├── Flutter_Plugins.xml │ └── Dart_SDK.xml ├── modules.xml └── codeStyles │ └── Project.xml ├── .gitignore ├── example ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── .gitignore │ └── Podfile ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── .metadata ├── README.md ├── .vscode │ └── launch.json ├── .gitignore ├── .flutter-plugins-dependencies ├── test │ └── widget_test.dart ├── lib │ └── main.dart ├── pubspec.yaml ├── pubspec.lock └── .dart_tool │ └── package_config.json ├── .metadata ├── CHANGELOG.md ├── pubspec.yaml ├── flutter_qr_bar_scanner.iml ├── LICENSE ├── pubspec.lock ├── lib ├── flutter_qr_bar_scanner.dart └── qr_bar_scanner_camera.dart └── README.md /.dart_tool/version: -------------------------------------------------------------------------------- 1 | 2.2.3 -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_qr_bar_scanner' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | gen/ -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Classes/FlutterQrBarScannerPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterQrBarScannerPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contactlutforrahman/flutter_qr_bar_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/NoPermissionException.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | class NoPermissionException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrReaderCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | public interface QrReaderCallbacks { 4 | void qrRead(String data); 5 | } 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 28 09:56:16 PDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrCamera.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | interface QrCamera { 4 | void start() throws QrReader.Exception; 5 | void stop(); 6 | int getOrientation(); 7 | int getWidth(); 8 | int getHeight(); 9 | } 10 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations/example_lib_main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | 13 | *.pbxuser 14 | *.mode1v3 15 | *.mode2v3 16 | *.perspectivev3 17 | 18 | !default.pbxuser 19 | !default.mode1v3 20 | !default.mode2v3 21 | !default.perspectivev3 22 | 23 | xcuserdata 24 | 25 | *.moved-aside 26 | 27 | *.pyc 28 | *sync/ 29 | Icon? 30 | .tags* 31 | 32 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.0.0] - February 9, 2020 2 | 3 | * Flutter QR Bar Scanner initial release 4 | 5 | ## [1.0.1] - February 9, 2020 6 | 7 | * Updated documentation 8 | 9 | ## [1.0.2] - April 24, 2020 10 | 11 | * Fixed pod error 12 | 13 | ## [2.0.0] - June 03, 2021 14 | 15 | * Upgraded to Flutter Null safety 16 | 17 | ## [2.0.1] - August 28, 2021 18 | 19 | * Solved bugs 20 | 21 | ## [3.0.0] - October 31, 2021 22 | 23 | * Solved deprecated API issue 24 | 25 | ## [3.0.1] - October 31, 2021 26 | 27 | * Solved missing plugins exception 28 | 29 | ## [3.0.2] - October 31, 2021 30 | 31 | * Fixed bugs -------------------------------------------------------------------------------- /android/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "example", 9 | "request": "launch", 10 | "type": "dart" 11 | }, 12 | { 13 | "name": "example (profile mode)", 14 | "request": "launch", 15 | "type": "dart", 16 | "flutterMode": "profile" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /ios/Classes/Atomic.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | final class Atomic { 4 | 5 | private let sema = DispatchSemaphore(value: 1) 6 | private var _value: T 7 | 8 | init (_ value: T) { 9 | _value = value 10 | } 11 | 12 | var value: T { 13 | get { 14 | sema.wait() 15 | defer { 16 | sema.signal() 17 | } 18 | return _value 19 | } 20 | set { 21 | sema.wait() 22 | _value = newValue 23 | sema.signal() 24 | } 25 | } 26 | 27 | func swap(_ value: T) -> T { 28 | sema.wait() 29 | let v = _value 30 | _value = value 31 | sema.signal() 32 | return v 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_qr_bar_scanner 2 | description: "A Flutter Plugin for reading/scanning QR & Bar codes using Firebase's Mobile Vision API" 3 | version: 3.0.2 4 | homepage: https://github.com/contactlutforrahman/flutter_qr_bar_scanner 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | flutter: ">=1.10.0" 9 | 10 | flutter: 11 | plugin: 12 | platforms: 13 | android: 14 | package: com.github.contactlutforrahman.flutter_qr_bar_scanner 15 | pluginClass: FlutterQrBarScannerPlugin 16 | ios: 17 | pluginClass: FlutterQrBarScannerPlugin 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | native_device_orientation: ^1.0.0 23 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Classes/FlutterQrBarScannerPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterQrBarScannerPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "flutter_qr_bar_scanner-Swift.h" 9 | #endif 10 | 11 | @implementation FlutterQrBarScannerPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftQrBarScannerPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/Heartbeat.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import android.os.Handler; 4 | 5 | public class Heartbeat { 6 | 7 | private final Handler handler = new Handler(); 8 | private final Runnable runner; 9 | private final int timeout; 10 | 11 | public Heartbeat(int timeout, Runnable runner) { 12 | this.timeout = timeout; 13 | this.runner = runner; 14 | 15 | handler.postDelayed(runner, timeout); 16 | } 17 | 18 | public void beat() { 19 | handler.removeCallbacks(runner); 20 | handler.postDelayed(runner, timeout); 21 | } 22 | 23 | public void stop() { 24 | handler.removeCallbacks(runner); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_qr_bar_scanner","path":"/Users/hello/Documents/packages-update/flutter_qr_bar_scanner/","dependencies":["native_device_orientation"]},{"name":"native_device_orientation","path":"/Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0/","dependencies":[]}],"android":[{"name":"flutter_qr_bar_scanner","path":"/Users/hello/Documents/packages-update/flutter_qr_bar_scanner/","dependencies":["native_device_orientation"]},{"name":"native_device_orientation","path":"/Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_qr_bar_scanner","dependencies":["native_device_orientation"]},{"name":"native_device_orientation","dependencies":[]}],"date_created":"2021-10-31 22:47:23.454891","version":"2.2.3"} -------------------------------------------------------------------------------- /flutter_qr_bar_scanner.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Lutfor Rahman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.github.contactlutforrahman.flutter_qr_bar_scanner' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:4.1.2' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | 24 | android { 25 | compileSdkVersion 29 26 | 27 | defaultConfig { 28 | minSdkVersion 16 29 | } 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | } 34 | 35 | dependencies { 36 | implementation 'com.google.mlkit:barcode-scanning:16.1.1' 37 | } 38 | 39 | 40 | // if flutter.dir has been defined, use this to add dependency to flutter. This allows the android studio to provide 41 | // auto-complete & not show errors for flutter stuff =) 42 | if(project.hasProperty('flutter.dir')) { 43 | print("Adding flutter dependency for development purposes.") 44 | dependencies { 45 | implementation files("${flutter.dir}/bin/cache/artifacts/engine/android-arm/flutter.jar") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ios/flutter_qr_bar_scanner.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'flutter_qr_bar_scanner' 3 | s.version = '3.0.1' 4 | s.summary = "A Plugin for reading/scanning QR & Bar codes using Firebase's Mobile Vision API." 5 | s.description = <<-DESC 6 | A Plugin for reading/scanning QR & Bar codes using Firebase's Mobile Vision API. 7 | DESC 8 | s.homepage = 'https://github.com/contactlutforrahman/flutter_qr_bar_scanner' 9 | s.license = { :file => '../LICENSE' } 10 | s.author = { 'Lutfor Rahman' => 'contact.lutforrahman@gmail.com' } 11 | s.source = { :path => '.' } 12 | s.source_files = 'Classes/**/*' 13 | s.public_header_files = 'Classes/**/*.h' 14 | s.dependency 'Flutter' 15 | s.platform = :ios, '11.0' 16 | 17 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. 18 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } 19 | # Mobile vision doesn't support 32 bit ios 20 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphoneos*]' => 'arm64' } 21 | s.swift_version = '5.0' 22 | 23 | s.dependency 'GoogleMLKit/BarcodeScanning' 24 | 25 | s.static_framework = true 26 | end 27 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | characters: 5 | dependency: transitive 6 | description: 7 | name: characters 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "1.1.0" 11 | collection: 12 | dependency: transitive 13 | description: 14 | name: collection 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.15.0" 18 | flutter: 19 | dependency: "direct main" 20 | description: flutter 21 | source: sdk 22 | version: "0.0.0" 23 | meta: 24 | dependency: transitive 25 | description: 26 | name: meta 27 | url: "https://pub.dartlang.org" 28 | source: hosted 29 | version: "1.3.0" 30 | native_device_orientation: 31 | dependency: "direct main" 32 | description: 33 | name: native_device_orientation 34 | url: "https://pub.dartlang.org" 35 | source: hosted 36 | version: "1.0.0" 37 | sky_engine: 38 | dependency: transitive 39 | description: flutter 40 | source: sdk 41 | version: "0.0.99" 42 | typed_data: 43 | dependency: transitive 44 | description: 45 | name: typed_data 46 | url: "https://pub.dartlang.org" 47 | source: hosted 48 | version: "1.3.0" 49 | vector_math: 50 | dependency: transitive 51 | description: 52 | name: vector_math 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "2.1.0" 56 | sdks: 57 | dart: ">=2.12.0 <3.0.0" 58 | flutter: ">=2.0.0" 59 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | target.build_configurations.each do |config| 40 | config.build_settings['ENABLE_BITCODE'] = 'NO' 41 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.dart_tool/package_config_subset: -------------------------------------------------------------------------------- 1 | flutter_qr_bar_scanner 2 | 2.12 3 | file:///Users/hello/Documents/packages-update/flutter_qr_bar_scanner/ 4 | file:///Users/hello/Documents/packages-update/flutter_qr_bar_scanner/lib/ 5 | characters 6 | 2.12 7 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/ 8 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/lib/ 9 | collection 10 | 2.12 11 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/ 12 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ 13 | meta 14 | 2.12 15 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0/ 16 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0/lib/ 17 | native_device_orientation 18 | 2.12 19 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0/ 20 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0/lib/ 21 | typed_data 22 | 2.12 23 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/ 24 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ 25 | vector_math 26 | 2.12 27 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0/ 28 | file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0/lib/ 29 | sky_engine 30 | 2.12 31 | file:///Users/hello/Documents/src/flutter/bin/cache/pkg/sky_engine/ 32 | file:///Users/hello/Documents/src/flutter/bin/cache/pkg/sky_engine/lib/ 33 | flutter 34 | 2.12 35 | file:///Users/hello/Documents/src/flutter/packages/flutter/ 36 | file:///Users/hello/Documents/src/flutter/packages/flutter/lib/ 37 | 2 38 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.example" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_qr_bar_scanner/qr_bar_scanner_camera.dart'; 3 | 4 | void main() { 5 | runApp(MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return MaterialApp( 12 | title: 'Flutter QR/Bar Code Reader', 13 | debugShowCheckedModeBanner: false, 14 | theme: ThemeData( 15 | primarySwatch: Colors.blue, 16 | ), 17 | home: MyHomePage(title: 'Flutter QR/Bar Code Reader'), 18 | ); 19 | } 20 | } 21 | 22 | class MyHomePage extends StatefulWidget { 23 | MyHomePage({Key? key, this.title}) : super(key: key); 24 | final String? title; 25 | @override 26 | _MyHomePageState createState() => _MyHomePageState(); 27 | } 28 | 29 | class _MyHomePageState extends State { 30 | String? _qrInfo = 'Scan a QR/Bar code'; 31 | bool _camState = false; 32 | 33 | _qrCallback(String? code) { 34 | setState(() { 35 | _camState = false; 36 | _qrInfo = code; 37 | }); 38 | } 39 | 40 | _scanCode() { 41 | setState(() { 42 | _camState = true; 43 | }); 44 | } 45 | 46 | @override 47 | void initState() { 48 | super.initState(); 49 | _scanCode(); 50 | } 51 | 52 | @override 53 | void dispose() { 54 | super.dispose(); 55 | } 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | return Scaffold( 60 | appBar: AppBar( 61 | title: Text(widget.title!), 62 | ), 63 | body: _camState 64 | ? Center( 65 | child: SizedBox( 66 | height: 1000, 67 | width: 500, 68 | child: QRBarScannerCamera( 69 | onError: (context, error) => Text( 70 | error.toString(), 71 | style: TextStyle(color: Colors.red), 72 | ), 73 | qrCodeCallback: (code) { 74 | _qrCallback(code); 75 | }, 76 | ), 77 | ), 78 | ) 79 | : Center( 80 | child: Text(_qrInfo!), 81 | ), 82 | ); 83 | } 84 | } -------------------------------------------------------------------------------- /.dart_tool/package_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configVersion": 2, 3 | "packages": [ 4 | { 5 | "name": "characters", 6 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0", 7 | "packageUri": "lib/", 8 | "languageVersion": "2.12" 9 | }, 10 | { 11 | "name": "collection", 12 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0", 13 | "packageUri": "lib/", 14 | "languageVersion": "2.12" 15 | }, 16 | { 17 | "name": "flutter", 18 | "rootUri": "file:///Users/hello/Documents/src/flutter/packages/flutter", 19 | "packageUri": "lib/", 20 | "languageVersion": "2.12" 21 | }, 22 | { 23 | "name": "meta", 24 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0", 25 | "packageUri": "lib/", 26 | "languageVersion": "2.12" 27 | }, 28 | { 29 | "name": "native_device_orientation", 30 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0", 31 | "packageUri": "lib/", 32 | "languageVersion": "2.12" 33 | }, 34 | { 35 | "name": "sky_engine", 36 | "rootUri": "file:///Users/hello/Documents/src/flutter/bin/cache/pkg/sky_engine", 37 | "packageUri": "lib/", 38 | "languageVersion": "2.12" 39 | }, 40 | { 41 | "name": "typed_data", 42 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0", 43 | "packageUri": "lib/", 44 | "languageVersion": "2.12" 45 | }, 46 | { 47 | "name": "vector_math", 48 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0", 49 | "packageUri": "lib/", 50 | "languageVersion": "2.12" 51 | }, 52 | { 53 | "name": "flutter_qr_bar_scanner", 54 | "rootUri": "../", 55 | "packageUri": "lib/", 56 | "languageVersion": "2.12" 57 | } 58 | ], 59 | "generated": "2021-10-31T05:27:28.034218Z", 60 | "generator": "pub", 61 | "generatorVersion": "2.13.4" 62 | } 63 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrDetector.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.annotation.GuardedBy; 6 | import androidx.annotation.NonNull; 7 | 8 | import com.google.android.gms.tasks.OnFailureListener; 9 | import com.google.android.gms.tasks.OnSuccessListener; 10 | import com.google.mlkit.vision.barcode.Barcode; 11 | import com.google.mlkit.vision.barcode.BarcodeScanner; 12 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions; 13 | import com.google.mlkit.vision.barcode.BarcodeScanning; 14 | import com.google.mlkit.vision.common.InputImage; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Allows QrCamera classes to send frames to a Detector 20 | */ 21 | 22 | class QrDetector implements OnSuccessListener>, OnFailureListener { 23 | private static final String TAG = "cgr.qrmv.QrDetector"; 24 | private final QrReaderCallbacks communicator; 25 | private final BarcodeScanner detector; 26 | 27 | public interface Frame { 28 | InputImage toImage(); 29 | 30 | void close(); 31 | } 32 | 33 | @GuardedBy("this") 34 | private Frame latestFrame; 35 | 36 | @GuardedBy("this") 37 | private Frame processingFrame; 38 | 39 | QrDetector(QrReaderCallbacks communicator, BarcodeScannerOptions options) { 40 | this.communicator = communicator; 41 | this.detector = BarcodeScanning.getClient(options); 42 | } 43 | 44 | void detect(Frame frame) { 45 | if (latestFrame != null) latestFrame.close(); 46 | latestFrame = frame; 47 | 48 | if (processingFrame == null) { 49 | processLatest(); 50 | } 51 | } 52 | 53 | private synchronized void processLatest() { 54 | if (processingFrame != null) processingFrame.close(); 55 | processingFrame = latestFrame; 56 | latestFrame = null; 57 | if (processingFrame != null) { 58 | processFrame(processingFrame); 59 | } 60 | } 61 | 62 | private void processFrame(Frame frame) { 63 | InputImage image; 64 | try { 65 | image = frame.toImage(); 66 | } catch (IllegalStateException ex) { 67 | // ignore state exception from making frame to image 68 | // as the image may be closed already. 69 | return; 70 | } 71 | 72 | detector.process(image) 73 | .addOnSuccessListener(this) 74 | .addOnFailureListener(this); 75 | } 76 | 77 | @Override 78 | public void onSuccess(List firebaseVisionBarcodes) { 79 | for (Barcode barcode : firebaseVisionBarcodes) { 80 | communicator.qrRead(barcode.getRawValue()); 81 | } 82 | processLatest(); 83 | } 84 | 85 | @Override 86 | public void onFailure(@NonNull Exception e) { 87 | Log.w(TAG, "Barcode Reading Failure: ", e); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.2 31 | 32 | dev_dependencies: 33 | flutter_test: 34 | sdk: flutter 35 | 36 | flutter_qr_bar_scanner: 37 | path: ../ 38 | 39 | # For information on the generic Dart part of this file, see the 40 | # following page: https://dart.dev/tools/pub/pubspec 41 | 42 | # The following section is specific to Flutter. 43 | flutter: 44 | 45 | # The following line ensures that the Material Icons font is 46 | # included with your application, so that you can use the icons in 47 | # the material Icons class. 48 | uses-material-design: true 49 | 50 | # To add assets to your application, add an assets section, like this: 51 | # assets: 52 | # - images/a_dot_burr.jpeg 53 | # - images/a_dot_ham.jpeg 54 | 55 | # An image asset can refer to one or more resolution-specific "variants", see 56 | # https://flutter.dev/assets-and-images/#resolution-aware. 57 | 58 | # For details regarding adding assets from package dependencies, see 59 | # https://flutter.dev/assets-and-images/#from-packages 60 | 61 | # To add custom fonts to your application, add a fonts section here, 62 | # in this "flutter" section. Each entry in this list should have a 63 | # "family" key with the font family name, and a "fonts" key with a 64 | # list giving the asset and other descriptors for the font. For 65 | # example: 66 | # fonts: 67 | # - family: Schyler 68 | # fonts: 69 | # - asset: fonts/Schyler-Regular.ttf 70 | # - asset: fonts/Schyler-Italic.ttf 71 | # style: italic 72 | # - family: Trajan Pro 73 | # fonts: 74 | # - asset: fonts/TrajanPro.ttf 75 | # - asset: fonts/TrajanPro_Bold.ttf 76 | # weight: 700 77 | # 78 | # For details regarding fonts from package dependencies, 79 | # see https://flutter.dev/custom-fonts/#from-packages 80 | -------------------------------------------------------------------------------- /lib/flutter_qr_bar_scanner.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/services.dart'; 4 | 5 | class PreviewDetails { 6 | num? width; 7 | num? height; 8 | num? sensorOrientation; 9 | int? textureId; 10 | 11 | PreviewDetails( 12 | this.width, this.height, this.sensorOrientation, this.textureId); 13 | } 14 | 15 | enum BarcodeFormats { 16 | ALL_FORMATS, 17 | AZTEC, 18 | CODE_128, 19 | CODE_39, 20 | CODE_93, 21 | CODABAR, 22 | DATA_MATRIX, 23 | EAN_13, 24 | EAN_8, 25 | ITF, 26 | PDF417, 27 | QR_CODE, 28 | UPC_A, 29 | UPC_E, 30 | } 31 | 32 | const _defaultBarcodeFormats = const [ 33 | BarcodeFormats.ALL_FORMATS, 34 | ]; 35 | 36 | class FlutterQrReader { 37 | static const MethodChannel _channel = const MethodChannel( 38 | 'com.github.contactlutforrahman/flutter_qr_bar_scanner'); 39 | static QrChannelReader channelReader = QrChannelReader(_channel); 40 | 41 | //Set target size before starting 42 | static Future start({ 43 | required int width, 44 | required int height, 45 | required QRCodeHandler qrCodeHandler, 46 | List? formats = _defaultBarcodeFormats, 47 | }) async { 48 | final _formats = formats ?? _defaultBarcodeFormats; 49 | assert(_formats.length > 0); 50 | 51 | List formatStrings = _formats 52 | .map((format) => format.toString().split('.')[1]) 53 | .toList(growable: false); 54 | 55 | channelReader.setQrCodeHandler(qrCodeHandler); 56 | var details = await _channel.invokeMethod('start', { 57 | 'targetWidth': width, 58 | 'targetHeight': height, 59 | 'heartbeatTimeout': 0, 60 | 'formats': formatStrings, 61 | }); 62 | 63 | // invokeMethod returns Map in dart 2.0 64 | assert(details is Map); 65 | 66 | int? textureId = details["textureId"]; 67 | num? orientation = details["surfaceOrientation"]; 68 | num? surfaceHeight = details["surfaceHeight"]; 69 | num? surfaceWidth = details["surfaceWidth"]; 70 | 71 | return PreviewDetails(surfaceWidth, surfaceHeight, orientation, textureId); 72 | } 73 | 74 | static Future stop() { 75 | channelReader.setQrCodeHandler(null); 76 | return _channel.invokeMethod('stop').catchError(print); 77 | } 78 | 79 | static Future heartbeat() { 80 | return _channel.invokeMethod('heartbeat').catchError(print); 81 | } 82 | 83 | static Future>?> getSupportedSizes() { 84 | return _channel.invokeMethod('getSupportedSizes').catchError(print) 85 | as Future>?>; 86 | } 87 | } 88 | 89 | enum FrameRotation { none, ninetyCC, oneeighty, twoseventyCC } 90 | 91 | typedef void QRCodeHandler(String? qr); 92 | 93 | class QrChannelReader { 94 | QrChannelReader(this.channel) { 95 | channel.setMethodCallHandler((MethodCall call) async { 96 | switch (call.method) { 97 | case 'qrRead': 98 | if (qrCodeHandler != null) { 99 | assert(call.arguments is String); 100 | qrCodeHandler!(call.arguments); 101 | } 102 | break; 103 | default: 104 | print("QrChannelHandler: unknown method call received at " 105 | "${call.method}"); 106 | } 107 | }); 108 | } 109 | 110 | void setQrCodeHandler(QRCodeHandler? qrch) { 111 | this.qrCodeHandler = qrch; 112 | } 113 | 114 | MethodChannel channel; 115 | QRCodeHandler? qrCodeHandler; 116 | } 117 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Classes/SwiftQrBarScannerPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import MLKitVision 4 | import MLKitBarcodeScanning 5 | 6 | class MapArgumentReader { 7 | 8 | let args: [String: Any]? 9 | 10 | init(_ args: [String: Any]?) { 11 | self.args = args 12 | } 13 | 14 | func string(key: String) -> String? { 15 | return args?[key] as? String 16 | } 17 | 18 | func int(key: String) -> Int? { 19 | return (args?[key] as? NSNumber)?.intValue 20 | } 21 | 22 | func stringArray(key: String) -> [String]? { 23 | return args?[key] as? [String] 24 | } 25 | 26 | } 27 | 28 | public class SwiftQrBarScannerPlugin: NSObject, FlutterPlugin { 29 | 30 | let textureRegistry: FlutterTextureRegistry 31 | let channel: FlutterMethodChannel 32 | 33 | init(channel: FlutterMethodChannel, textureRegistry: FlutterTextureRegistry) { 34 | self.textureRegistry = textureRegistry 35 | self.channel = channel 36 | } 37 | 38 | public static func register(with registrar: FlutterPluginRegistrar) { 39 | let channel = FlutterMethodChannel(name: "com.github.contactlutforrahman/flutter_qr_bar_scanner", binaryMessenger: registrar.messenger()); 40 | let instance = SwiftQrBarScannerPlugin(channel: channel, textureRegistry: registrar.textures()); 41 | registrar.addMethodCallDelegate(instance, channel: channel) 42 | } 43 | 44 | var reader: QrReader? = nil 45 | 46 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 47 | let argReader = MapArgumentReader(call.arguments as? [String: Any]) 48 | 49 | switch call.method{ 50 | case "start": 51 | if reader != nil { 52 | result(FlutterError(code: "ALREADY_RUNNING", message: "Start cannot be called when already running", details: "")) 53 | return 54 | } 55 | 56 | // let heartBeatTimeout = argReader.int(key: "heartBeatTimeout") 57 | 58 | guard let targetWidth = argReader.int(key: "targetWidth"), 59 | let targetHeight = argReader.int(key: "targetHeight"), 60 | let formatStrings = argReader.stringArray(key: "formats") else { 61 | result(FlutterError(code: "INVALID_ARGUMENT", message: "Missing a required argument", details: "Expecting targetWidth, targetHeight, formats, and optionally heartbeatTimeout")) 62 | return 63 | } 64 | 65 | let options = BarcodeScannerOptions(formatStrings: formatStrings) 66 | 67 | do { 68 | reader = try QrReader( 69 | targetWidth: targetWidth, 70 | targetHeight: targetHeight, 71 | textureRegistry: textureRegistry, 72 | options: options) { [unowned self] qr in 73 | self.channel.invokeMethod("qrRead", arguments: qr) 74 | } 75 | 76 | reader!.start(); 77 | 78 | result([ 79 | "surfaceWidth": reader!.previewSize.height, 80 | "surfaceHeight": reader!.previewSize.width, 81 | "surfaceOrientation": 0, //TODO: check on iPAD 82 | "textureId": reader!.textureId! 83 | ]) 84 | } catch QrReaderError.noCamera { 85 | result(FlutterError(code: "CAMERA_ERROR", message: "QrReader couldn't open camera", details: nil)) 86 | } catch { 87 | result(FlutterError(code: "PERMISSION_DENIED", message: "QrReader initialization threw an exception", details: error.localizedDescription)) 88 | } 89 | case "stop": 90 | reader?.stop(); 91 | reader = nil 92 | result(nil) 93 | case "heartBeat": 94 | // reader?.heartBeat(); 95 | result(nil) 96 | default : result(FlutterMethodNotImplemented); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | example 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/BarcodeFormats.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | 11 | public enum BarcodeFormats { 12 | 13 | ALL_FORMATS(com.google.mlkit.vision.barcode.Barcode.FORMAT_ALL_FORMATS), 14 | CODE_128(com.google.mlkit.vision.barcode.Barcode.FORMAT_CODE_128), 15 | CODE_39(com.google.mlkit.vision.barcode.Barcode.FORMAT_CODE_39), 16 | CODE_93(com.google.mlkit.vision.barcode.Barcode.FORMAT_CODE_93), 17 | CODABAR(com.google.mlkit.vision.barcode.Barcode.FORMAT_CODABAR), 18 | DATA_MATRIX(com.google.mlkit.vision.barcode.Barcode.FORMAT_DATA_MATRIX), 19 | EAN_13(com.google.mlkit.vision.barcode.Barcode.FORMAT_EAN_13), 20 | EAN_8(com.google.mlkit.vision.barcode.Barcode.FORMAT_EAN_8), 21 | ITF(com.google.mlkit.vision.barcode.Barcode.FORMAT_ITF), 22 | QR_CODE(com.google.mlkit.vision.barcode.Barcode.FORMAT_QR_CODE), 23 | UPC_A(com.google.mlkit.vision.barcode.Barcode.FORMAT_UPC_A), 24 | UPC_E(com.google.mlkit.vision.barcode.Barcode.FORMAT_UPC_E), 25 | PDF417(com.google.mlkit.vision.barcode.Barcode.FORMAT_PDF417), 26 | AZTEC(com.google.mlkit.vision.barcode.Barcode.FORMAT_AZTEC); 27 | 28 | BarcodeFormats(int intValue) { 29 | this.intValue = intValue; 30 | } 31 | 32 | public final int intValue; 33 | 34 | private static Map formatsMap; 35 | 36 | static { 37 | BarcodeFormats[] values = BarcodeFormats.values(); 38 | formatsMap = new HashMap<>(values.length * 4 / 3); 39 | for (BarcodeFormats value : values) { 40 | formatsMap.put(value.name(), value.intValue); 41 | } 42 | } 43 | 44 | /** 45 | * Return the integer value resuling from OR-ing all of the values 46 | * of the supplied strings. 47 | *

48 | * Note that if ALL_FORMATS is defined as well as other values, ALL_FORMATS 49 | * will be ignored (following how it would work with just OR-ing the ints). 50 | * 51 | * @param strings - list of strings representing the various formats 52 | * @return integer value corresponding to OR of all the values. 53 | */ 54 | static int intFromStringList(List strings) { 55 | if (strings == null) return BarcodeFormats.ALL_FORMATS.intValue; 56 | int val = 0; 57 | for (String string : strings) { 58 | Integer asInt = BarcodeFormats.formatsMap.get(string); 59 | if (asInt != null) { 60 | val |= asInt; 61 | } 62 | } 63 | return val; 64 | } 65 | 66 | static BarcodeScannerOptions optionsFromStringList(List strings) { 67 | if (strings == null) { 68 | return new BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue).build(); 69 | } 70 | 71 | List ints = new ArrayList<>(strings.size()); 72 | for (int i = 0, l = strings.size(); i < l; ++i) { 73 | Integer integer = BarcodeFormats.formatsMap.get(strings.get(i)); 74 | if (integer != null) { 75 | ints.add(integer); 76 | } 77 | } 78 | 79 | if (ints.size() == 0) { 80 | return new BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue).build(); 81 | } 82 | 83 | if (ints.size() == 1) { 84 | return new BarcodeScannerOptions.Builder().setBarcodeFormats(ints.get(0)).build(); 85 | } 86 | 87 | int first = ints.get(0); 88 | int[] rest = new int[ints.size() - 1]; 89 | int i = 0; 90 | for (Integer e : ints.subList(1, ints.size())) { 91 | rest[i++] = e; 92 | } 93 | 94 | 95 | return new BarcodeScannerOptions.Builder() 96 | .setBarcodeFormats(first, rest).build(); 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.6.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.15.0" 46 | cupertino_icons: 47 | dependency: "direct main" 48 | description: 49 | name: cupertino_icons 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.0.3" 53 | fake_async: 54 | dependency: transitive 55 | description: 56 | name: fake_async 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.2.0" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_qr_bar_scanner: 66 | dependency: "direct dev" 67 | description: 68 | path: ".." 69 | relative: true 70 | source: path 71 | version: "3.0.1" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | matcher: 78 | dependency: transitive 79 | description: 80 | name: matcher 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.12.10" 84 | meta: 85 | dependency: transitive 86 | description: 87 | name: meta 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.3.0" 91 | native_device_orientation: 92 | dependency: transitive 93 | description: 94 | name: native_device_orientation 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.0.0" 98 | path: 99 | dependency: transitive 100 | description: 101 | name: path 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.8.0" 105 | sky_engine: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.99" 110 | source_span: 111 | dependency: transitive 112 | description: 113 | name: source_span 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.8.1" 117 | stack_trace: 118 | dependency: transitive 119 | description: 120 | name: stack_trace 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.10.0" 124 | stream_channel: 125 | dependency: transitive 126 | description: 127 | name: stream_channel 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "2.1.0" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "1.1.0" 138 | term_glyph: 139 | dependency: transitive 140 | description: 141 | name: term_glyph 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.2.0" 145 | test_api: 146 | dependency: transitive 147 | description: 148 | name: test_api 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "0.3.0" 152 | typed_data: 153 | dependency: transitive 154 | description: 155 | name: typed_data 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.3.0" 159 | vector_math: 160 | dependency: transitive 161 | description: 162 | name: vector_math 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "2.1.0" 166 | sdks: 167 | dart: ">=2.12.0 <3.0.0" 168 | flutter: ">=2.0.0" 169 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrReader.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner;; 2 | 3 | import android.Manifest; 4 | import android.annotation.SuppressLint; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.pm.PackageManager; 8 | import android.graphics.SurfaceTexture; 9 | import android.os.Build; 10 | import android.util.Log; 11 | 12 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions; 13 | 14 | import java.io.IOException; 15 | 16 | class QrReader { 17 | private static final String TAG = "cgr.qrmv.QrReader"; 18 | final QrCamera qrCamera; 19 | private final Activity context; 20 | private final QRReaderStartedCallback startedCallback; 21 | private Heartbeat heartbeat; 22 | 23 | QrReader(int width, int height, Activity context, BarcodeScannerOptions options, 24 | final QRReaderStartedCallback startedCallback, final QrReaderCallbacks communicator, 25 | final SurfaceTexture texture) { 26 | this.context = context; 27 | this.startedCallback = startedCallback; 28 | 29 | if (android.os.Build.VERSION.SDK_INT >= 21) { 30 | Log.i(TAG, "Using new camera API."); 31 | qrCamera = new QrCameraC2(width, height, texture, context, new QrDetector(communicator, options)); 32 | } else { 33 | Log.i(TAG, "Using old camera API."); 34 | qrCamera = new QrCameraC1(width, height, texture, context, new QrDetector(communicator, options)); 35 | } 36 | } 37 | 38 | void start(final int heartBeatTimeout) throws IOException, NoPermissionException, Exception { 39 | if (!hasCameraHardware(context)) { 40 | throw new Exception(Exception.Reason.noHardware); 41 | } 42 | 43 | if (!checkCameraPermission(context)) { 44 | throw new NoPermissionException(); 45 | } else { 46 | continueStarting(heartBeatTimeout); 47 | } 48 | } 49 | 50 | private void continueStarting(int heartBeatTimeout) throws IOException { 51 | try { 52 | if (heartBeatTimeout > 0) { 53 | if (heartbeat != null) { 54 | heartbeat.stop(); 55 | } 56 | heartbeat = new Heartbeat(heartBeatTimeout, new Runnable() { 57 | @Override 58 | public void run() { 59 | stop(); 60 | } 61 | }); 62 | } 63 | 64 | qrCamera.start(); 65 | startedCallback.started(); 66 | } catch (Throwable t) { 67 | startedCallback.startingFailed(t); 68 | } 69 | } 70 | 71 | void stop() { 72 | if (heartbeat != null) { 73 | heartbeat.stop(); 74 | } 75 | 76 | qrCamera.stop(); 77 | } 78 | 79 | void heartBeat() { 80 | if (heartbeat != null) { 81 | heartbeat.beat(); 82 | } 83 | } 84 | 85 | private boolean hasCameraHardware(Context context) { 86 | if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 87 | return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); 88 | } else { 89 | @SuppressLint("UnsupportedChromeOsCameraSystemFeature") 90 | boolean hasFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); 91 | 92 | return hasFeature; 93 | } 94 | } 95 | 96 | private boolean checkCameraPermission(Context context) { 97 | String[] permissions = {Manifest.permission.CAMERA}; 98 | 99 | int res = context.checkCallingOrSelfPermission(permissions[0]); 100 | return res == PackageManager.PERMISSION_GRANTED; 101 | } 102 | 103 | interface QRReaderStartedCallback { 104 | void started(); 105 | 106 | void startingFailed(Throwable t); 107 | } 108 | 109 | static class Exception extends java.lang.Exception { 110 | private Reason reason; 111 | 112 | Exception(Reason reason) { 113 | super("QR reader failed because " + reason.toString()); 114 | this.reason = reason; 115 | } 116 | 117 | Reason reason() { 118 | return reason; 119 | } 120 | 121 | enum Reason { 122 | noHardware, 123 | noPermissions, 124 | noBackCamera 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /example/.dart_tool/package_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configVersion": 2, 3 | "packages": [ 4 | { 5 | "name": "async", 6 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.6.1", 7 | "packageUri": "lib/", 8 | "languageVersion": "2.12" 9 | }, 10 | { 11 | "name": "boolean_selector", 12 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0", 13 | "packageUri": "lib/", 14 | "languageVersion": "2.12" 15 | }, 16 | { 17 | "name": "characters", 18 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0", 19 | "packageUri": "lib/", 20 | "languageVersion": "2.12" 21 | }, 22 | { 23 | "name": "charcode", 24 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0", 25 | "packageUri": "lib/", 26 | "languageVersion": "2.12" 27 | }, 28 | { 29 | "name": "clock", 30 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0", 31 | "packageUri": "lib/", 32 | "languageVersion": "2.12" 33 | }, 34 | { 35 | "name": "collection", 36 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0", 37 | "packageUri": "lib/", 38 | "languageVersion": "2.12" 39 | }, 40 | { 41 | "name": "cupertino_icons", 42 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.3", 43 | "packageUri": "lib/", 44 | "languageVersion": "2.12" 45 | }, 46 | { 47 | "name": "fake_async", 48 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0", 49 | "packageUri": "lib/", 50 | "languageVersion": "2.12" 51 | }, 52 | { 53 | "name": "flutter", 54 | "rootUri": "file:///Users/hello/Documents/src/flutter/packages/flutter", 55 | "packageUri": "lib/", 56 | "languageVersion": "2.12" 57 | }, 58 | { 59 | "name": "flutter_qr_bar_scanner", 60 | "rootUri": "../../", 61 | "packageUri": "lib/", 62 | "languageVersion": "2.12" 63 | }, 64 | { 65 | "name": "flutter_test", 66 | "rootUri": "file:///Users/hello/Documents/src/flutter/packages/flutter_test", 67 | "packageUri": "lib/", 68 | "languageVersion": "2.12" 69 | }, 70 | { 71 | "name": "matcher", 72 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10", 73 | "packageUri": "lib/", 74 | "languageVersion": "2.12" 75 | }, 76 | { 77 | "name": "meta", 78 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0", 79 | "packageUri": "lib/", 80 | "languageVersion": "2.12" 81 | }, 82 | { 83 | "name": "native_device_orientation", 84 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/native_device_orientation-1.0.0", 85 | "packageUri": "lib/", 86 | "languageVersion": "2.12" 87 | }, 88 | { 89 | "name": "path", 90 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0", 91 | "packageUri": "lib/", 92 | "languageVersion": "2.12" 93 | }, 94 | { 95 | "name": "sky_engine", 96 | "rootUri": "file:///Users/hello/Documents/src/flutter/bin/cache/pkg/sky_engine", 97 | "packageUri": "lib/", 98 | "languageVersion": "2.12" 99 | }, 100 | { 101 | "name": "source_span", 102 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1", 103 | "packageUri": "lib/", 104 | "languageVersion": "2.12" 105 | }, 106 | { 107 | "name": "stack_trace", 108 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0", 109 | "packageUri": "lib/", 110 | "languageVersion": "2.12" 111 | }, 112 | { 113 | "name": "stream_channel", 114 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0", 115 | "packageUri": "lib/", 116 | "languageVersion": "2.12" 117 | }, 118 | { 119 | "name": "string_scanner", 120 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0", 121 | "packageUri": "lib/", 122 | "languageVersion": "2.12" 123 | }, 124 | { 125 | "name": "term_glyph", 126 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0", 127 | "packageUri": "lib/", 128 | "languageVersion": "2.12" 129 | }, 130 | { 131 | "name": "test_api", 132 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.3.0", 133 | "packageUri": "lib/", 134 | "languageVersion": "2.12" 135 | }, 136 | { 137 | "name": "typed_data", 138 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0", 139 | "packageUri": "lib/", 140 | "languageVersion": "2.12" 141 | }, 142 | { 143 | "name": "vector_math", 144 | "rootUri": "file:///Users/hello/Documents/src/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0", 145 | "packageUri": "lib/", 146 | "languageVersion": "2.12" 147 | }, 148 | { 149 | "name": "example", 150 | "rootUri": "../", 151 | "packageUri": "lib/", 152 | "languageVersion": "2.12" 153 | } 154 | ], 155 | "generated": "2021-10-31T16:47:23.303357Z", 156 | "generator": "pub", 157 | "generatorVersion": "2.13.4" 158 | } 159 | -------------------------------------------------------------------------------- /lib/qr_bar_scanner_camera.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/rendering.dart'; 6 | import 'package:native_device_orientation/native_device_orientation.dart'; 7 | import 'package:flutter_qr_bar_scanner/flutter_qr_bar_scanner.dart'; 8 | 9 | final WidgetBuilder _defaultNotStartedBuilder = 10 | (context) => Text("Camera Loading ..."); 11 | final WidgetBuilder _defaultOffscreenBuilder = 12 | (context) => Text("Camera Paused."); 13 | final ErrorCallback _defaultOnError = (BuildContext context, Object? error) { 14 | print("Error reading from camera: $error"); 15 | return Text("Error reading from camera..."); 16 | }; 17 | 18 | typedef Widget ErrorCallback(BuildContext context, Object? error); 19 | 20 | class QRBarScannerCamera extends StatefulWidget { 21 | QRBarScannerCamera({ 22 | Key? key, 23 | required this.qrCodeCallback, 24 | this.child, 25 | this.fit = BoxFit.cover, 26 | WidgetBuilder? notStartedBuilder, 27 | WidgetBuilder? offscreenBuilder, 28 | ErrorCallback? onError, 29 | this.formats, 30 | }) : notStartedBuilder = notStartedBuilder ?? _defaultNotStartedBuilder, 31 | offscreenBuilder = 32 | offscreenBuilder ?? notStartedBuilder ?? _defaultOffscreenBuilder, 33 | onError = onError ?? _defaultOnError, 34 | super(key: key); 35 | 36 | final BoxFit fit; 37 | final ValueChanged qrCodeCallback; 38 | final Widget? child; 39 | final WidgetBuilder notStartedBuilder; 40 | final WidgetBuilder offscreenBuilder; 41 | final ErrorCallback onError; 42 | final List? formats; 43 | 44 | @override 45 | QRBarScannerCameraState createState() => QRBarScannerCameraState(); 46 | } 47 | 48 | class QRBarScannerCameraState extends State 49 | with WidgetsBindingObserver { 50 | @override 51 | void initState() { 52 | super.initState(); 53 | WidgetsBinding.instance!.addObserver(this); 54 | } 55 | 56 | @override 57 | dispose() { 58 | WidgetsBinding.instance!.removeObserver(this); 59 | super.dispose(); 60 | } 61 | 62 | @override 63 | void didChangeAppLifecycleState(AppLifecycleState state) { 64 | if (state == AppLifecycleState.resumed) { 65 | setState(() => onScreen = true); 66 | } else { 67 | if (_asyncInitOnce != null && onScreen) { 68 | FlutterQrReader.stop(); 69 | } 70 | setState(() { 71 | onScreen = false; 72 | _asyncInitOnce = null; 73 | }); 74 | } 75 | } 76 | 77 | bool onScreen = true; 78 | Future? _asyncInitOnce; 79 | 80 | Future _asyncInit(num width, num height) async { 81 | final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; 82 | return await FlutterQrReader.start( 83 | width: (devicePixelRatio * width.toInt()).ceil(), 84 | height: (devicePixelRatio * height.toInt()).ceil(), 85 | qrCodeHandler: widget.qrCodeCallback, 86 | formats: widget.formats, 87 | ); 88 | } 89 | 90 | /// This method can be used to restart scanning 91 | /// the event that it was paused. 92 | void restart() { 93 | (() async { 94 | await FlutterQrReader.stop(); 95 | setState(() { 96 | _asyncInitOnce = null; 97 | }); 98 | })(); 99 | } 100 | 101 | /// This method can be used to manually stop the 102 | /// camera. 103 | void stop() { 104 | (() async { 105 | await FlutterQrReader.stop(); 106 | })(); 107 | } 108 | 109 | @override 110 | deactivate() { 111 | super.deactivate(); 112 | FlutterQrReader.stop(); 113 | } 114 | 115 | @override 116 | Widget build(BuildContext context) { 117 | return LayoutBuilder( 118 | builder: (BuildContext context, BoxConstraints constraints) { 119 | if (_asyncInitOnce == null && onScreen) { 120 | _asyncInitOnce = 121 | _asyncInit(constraints.maxWidth, constraints.maxHeight); 122 | } else if (!onScreen) { 123 | return widget.offscreenBuilder(context); 124 | } 125 | 126 | return FutureBuilder( 127 | future: _asyncInitOnce, 128 | builder: (BuildContext context, AsyncSnapshot details) { 129 | switch (details.connectionState) { 130 | case ConnectionState.none: 131 | case ConnectionState.waiting: 132 | return widget.notStartedBuilder(context); 133 | case ConnectionState.done: 134 | if (details.hasError) { 135 | debugPrint(details.error.toString()); 136 | return widget.onError(context, details.error); 137 | } 138 | Widget preview = SizedBox( 139 | width: constraints.maxWidth, 140 | height: constraints.maxHeight, 141 | child: Preview( 142 | previewDetails: details.data!, 143 | targetWidth: constraints.maxWidth, 144 | targetHeight: constraints.maxHeight, 145 | fit: widget.fit, 146 | ), 147 | ); 148 | 149 | if (widget.child != null) { 150 | return Stack( 151 | children: [ 152 | preview, 153 | widget.child!, 154 | ], 155 | ); 156 | } 157 | return preview; 158 | 159 | default: 160 | throw AssertionError("${details.connectionState} not supported."); 161 | } 162 | }, 163 | ); 164 | }); 165 | } 166 | } 167 | 168 | class Preview extends StatelessWidget { 169 | final double width, height; 170 | final double targetWidth, targetHeight; 171 | final int? textureId; 172 | final int? sensorOrientation; 173 | final BoxFit fit; 174 | 175 | Preview({ 176 | required PreviewDetails previewDetails, 177 | required this.targetWidth, 178 | required this.targetHeight, 179 | required this.fit, 180 | }) : textureId = previewDetails.textureId, 181 | width = previewDetails.width!.toDouble(), 182 | height = previewDetails.height!.toDouble(), 183 | sensorOrientation = previewDetails.sensorOrientation as int?; 184 | 185 | @override 186 | Widget build(BuildContext context) { 187 | return NativeDeviceOrientationReader( 188 | builder: (context) { 189 | var nativeOrientation = 190 | NativeDeviceOrientationReader.orientation(context); 191 | 192 | int nativeRotation = 0; 193 | switch (nativeOrientation) { 194 | case NativeDeviceOrientation.portraitUp: 195 | nativeRotation = 0; 196 | break; 197 | case NativeDeviceOrientation.landscapeRight: 198 | nativeRotation = 90; 199 | break; 200 | case NativeDeviceOrientation.portraitDown: 201 | nativeRotation = 180; 202 | break; 203 | case NativeDeviceOrientation.landscapeLeft: 204 | nativeRotation = 270; 205 | break; 206 | case NativeDeviceOrientation.unknown: 207 | default: 208 | break; 209 | } 210 | 211 | int rotationCompensation = 212 | ((nativeRotation - sensorOrientation! + 450) % 360) ~/ 90; 213 | 214 | double frameHeight = width; 215 | double frameWidth = height; 216 | 217 | return ClipRect( 218 | child: FittedBox( 219 | fit: fit, 220 | child: RotatedBox( 221 | quarterTurns: rotationCompensation, 222 | child: SizedBox( 223 | width: frameWidth, 224 | height: frameHeight, 225 | child: Texture(textureId: textureId!), 226 | ), 227 | ), 228 | ), 229 | ); 230 | }, 231 | ); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /ios/Classes/QrReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AVFoundation 3 | import MLKitVision 4 | import MLKitBarcodeScanning 5 | import os.log 6 | 7 | 8 | extension BarcodeScannerOptions { 9 | convenience init(formatStrings: [String]) { 10 | let formats = formatStrings.map { (format) -> BarcodeFormat? in 11 | switch format { 12 | case "ALL_FORMATS": 13 | return .all 14 | case "AZTEC": 15 | return .aztec 16 | case "CODE_128": 17 | return .code128 18 | case "CODE_39": 19 | return .code39 20 | case "CODE_93": 21 | return .code93 22 | case "CODABAR": 23 | return .codaBar 24 | case "DATA_MATRIX": 25 | return .dataMatrix 26 | case "EAN_13": 27 | return .EAN13 28 | case "EAN_8": 29 | return .EAN8 30 | case "ITF": 31 | return .ITF 32 | case "PDF417": 33 | return .PDF417 34 | case "QR_CODE": 35 | return .qrCode 36 | case "UPC_A": 37 | return .UPCA 38 | case "UPC_E": 39 | return .UPCE 40 | default: 41 | // ignore any unknown values 42 | return nil 43 | } 44 | }.reduce([]) { (result, format) -> BarcodeFormat in 45 | guard let format = format else { 46 | return result 47 | } 48 | return result.union(format) 49 | } 50 | 51 | self.init(formats: formats) 52 | } 53 | } 54 | 55 | class OrientationHandler { 56 | 57 | var lastKnownOrientation: UIDeviceOrientation! 58 | 59 | init() { 60 | setLastOrientation(UIDevice.current.orientation, defaultOrientation: .portrait) 61 | UIDevice.current.beginGeneratingDeviceOrientationNotifications() 62 | 63 | NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: nil, using: orientationDidChange(_:)) 64 | } 65 | 66 | func setLastOrientation(_ deviceOrientation: UIDeviceOrientation, defaultOrientation: UIDeviceOrientation?) { 67 | 68 | // set last device orientation but only if it is recognized 69 | switch deviceOrientation { 70 | case .unknown, .faceUp, .faceDown: 71 | lastKnownOrientation = defaultOrientation ?? lastKnownOrientation 72 | break 73 | default: 74 | lastKnownOrientation = deviceOrientation 75 | } 76 | } 77 | 78 | func orientationDidChange(_ notification: Notification) { 79 | let deviceOrientation = UIDevice.current.orientation 80 | 81 | let prevOrientation = lastKnownOrientation 82 | setLastOrientation(deviceOrientation, defaultOrientation: nil) 83 | 84 | if prevOrientation != lastKnownOrientation { 85 | //TODO: notify of orientation change??? (but mostly why bother...) 86 | } 87 | } 88 | 89 | deinit { 90 | UIDevice.current.endGeneratingDeviceOrientationNotifications() 91 | } 92 | } 93 | 94 | protocol QrReaderResponses { 95 | func surfaceReceived(buffer: CMSampleBuffer) 96 | func qrReceived(code: String) 97 | } 98 | 99 | enum QrReaderError: Error { 100 | case noCamera 101 | } 102 | 103 | class QrReader: NSObject { 104 | let targetWidth: Int 105 | let targetHeight: Int 106 | let textureRegistry: FlutterTextureRegistry 107 | let isProcessing = Atomic(false) 108 | 109 | var captureDevice: AVCaptureDevice! 110 | var captureSession: AVCaptureSession! 111 | var previewSize: CMVideoDimensions! 112 | var textureId: Int64! 113 | var pixelBuffer : CVPixelBuffer? 114 | let barcodeDetector: BarcodeScanner 115 | let cameraPosition = AVCaptureDevice.Position.back 116 | let qrCallback: (_:String) -> Void 117 | 118 | init(targetWidth: Int, targetHeight: Int, textureRegistry: FlutterTextureRegistry, options: BarcodeScannerOptions, qrCallback: @escaping (_:String) -> Void) throws { 119 | self.targetWidth = targetWidth 120 | self.targetHeight = targetHeight 121 | self.textureRegistry = textureRegistry 122 | self.qrCallback = qrCallback 123 | 124 | self.barcodeDetector = BarcodeScanner.barcodeScanner() 125 | 126 | super.init() 127 | 128 | captureSession = AVCaptureSession() 129 | 130 | if #available(iOS 10.0, *) { 131 | captureDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: cameraPosition) 132 | } else { 133 | for device in AVCaptureDevice.devices(for: AVMediaType.video) { 134 | if device.position == cameraPosition { 135 | captureDevice = device 136 | break 137 | } 138 | } 139 | } 140 | 141 | if captureDevice == nil { 142 | captureDevice = AVCaptureDevice.default(for: AVMediaType.video) 143 | 144 | guard captureDevice != nil else { 145 | throw QrReaderError.noCamera 146 | } 147 | } 148 | 149 | let input = try AVCaptureDeviceInput.init(device: captureDevice) 150 | previewSize = CMVideoFormatDescriptionGetDimensions(captureDevice.activeFormat.formatDescription) 151 | 152 | let output = AVCaptureVideoDataOutput() 153 | output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] 154 | output.alwaysDiscardsLateVideoFrames = true 155 | 156 | let queue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default) 157 | output.setSampleBufferDelegate(self, queue: queue) 158 | 159 | captureSession.addInput(input) 160 | captureSession.addOutput(output) 161 | } 162 | 163 | func start() { 164 | captureSession.startRunning() 165 | self.textureId = textureRegistry.register(self) 166 | } 167 | 168 | func stop() { 169 | captureSession.stopRunning() 170 | pixelBuffer = nil 171 | textureRegistry.unregisterTexture(textureId) 172 | textureId = nil 173 | } 174 | } 175 | 176 | extension QrReader : FlutterTexture { 177 | func copyPixelBuffer() -> Unmanaged? { 178 | if(pixelBuffer == nil){ 179 | return nil 180 | } 181 | return .passRetained(pixelBuffer!) 182 | } 183 | } 184 | 185 | extension QrReader: AVCaptureVideoDataOutputSampleBufferDelegate { 186 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 187 | // runs on dispatch queue 188 | 189 | pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 190 | textureRegistry.textureFrameAvailable(self.textureId) 191 | 192 | guard !isProcessing.swap(true) else { 193 | return 194 | } 195 | 196 | let image = VisionImage(buffer: sampleBuffer) 197 | image.orientation = imageOrientation( 198 | deviceOrientation: UIDevice.current.orientation, 199 | defaultOrientation: .portrait 200 | ) 201 | 202 | DispatchQueue.global(qos: DispatchQoS.QoSClass.utility).async { 203 | self.barcodeDetector.process(image) { features, error in 204 | self.isProcessing.value = false 205 | 206 | guard error == nil else { 207 | if #available(iOS 10.0, *) { 208 | os_log("Error decoding barcode %@", error!.localizedDescription) 209 | } else { 210 | // Fallback on earlier versions 211 | NSLog("Error decoding barcode %@", error!.localizedDescription) 212 | } 213 | return 214 | } 215 | 216 | guard let features = features, !features.isEmpty else { 217 | return 218 | } 219 | 220 | for feature in features { 221 | if let value = feature.rawValue { 222 | self.qrCallback(value) 223 | } 224 | } 225 | } 226 | } 227 | } 228 | 229 | 230 | 231 | func imageOrientation( 232 | deviceOrientation: UIDeviceOrientation, 233 | defaultOrientation: UIDeviceOrientation 234 | ) -> UIImage.Orientation { 235 | switch deviceOrientation { 236 | case .portrait: 237 | return cameraPosition == .front ? .leftMirrored : .right 238 | case .landscapeLeft: 239 | return cameraPosition == .front ? .downMirrored : .up 240 | case .portraitUpsideDown: 241 | return cameraPosition == .front ? .rightMirrored : .left 242 | case .landscapeRight: 243 | return cameraPosition == .front ? .upMirrored : .down 244 | case .faceDown, .faceUp, .unknown: 245 | return .up 246 | @unknown default: 247 | return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait) 248 | } 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter QR Bar Scanner 2 | 3 | ![pub package][version_badge] 4 | 5 | A Full Screen Scanner for Scanning QR code and Barcode using Google's Mobile Vision API 6 | 7 | Reading & Scanning QR/Bar codes using Firebase's MLKit. 8 | 9 | This plugin uses Android & iOS native APIs for reading images from the device's camera. 10 | It then pipes these images both to the MLKit Vision Barcode API which detects qr/bar codes etc, 11 | and outputs a preview image to be shown on a flutter texture. 12 | 13 | The plugin includes a widget which performs all needed transformations on the camera 14 | output to show within the defined area. 15 | 16 | ## Android Models 17 | 18 | With this new version of MLKit, there are two separate models you can use to do the barcode scanning. Currently, this 19 | apk chooses to use the build-in model. This will increase your code size by ~2.2MB but will 20 | result in better scanning and won't require a separate package to be downloaded in the background for barcode scanning 21 | to work properly. 22 | 23 | You could also use the Google Play Services and tell your app to download it on install from the play store. See the 24 | instruction on the [ml-kit barcode-scanning documentation page](https://developers.google.com/ml-kit/vision/barcode-scanning/android) 25 | for android. You would also have to remove the com.google.mlkit:barcode-scanning dependency; 26 | 27 | ``` 28 | configurations.all { 29 | exclude group: "com.google.mlkit", module:"barcode-scanning" 30 | } 31 | // ... 32 | dependencies { 33 | // ... 34 | // Use this dependency to use the dynamically downloaded model in Google Play Services 35 | implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:16.1.4' 36 | } 37 | ``` 38 | 39 | Note that if you do this, you should tell your app to automatically download the model as in the above linked docs.MLKit 40 | ``` 41 | 42 | ... 43 | 46 | 47 | 48 | ``` 49 | 50 | If this doesn't work for you please open an issue. 51 | 52 | ## 64 Bit Only on iOS 53 | 54 | The plugin is only supported for only 64 Bit on iOS as Google has only released MLKit as a 64 bit binary. 55 | 56 | When you upgrade, if you are targeting a version of iOS before 11, you'll see a warning during the `pod install` 57 | and your app probably won't build (at least for release). That's because it'll be trying to build the 32-bit version and 58 | won't find the required files. 59 | 60 | The easy way to solve this is by updating to build for iOS 11 and later. To do this: 61 | 62 | 1) Add this line to your Podfile: 63 | ``` 64 | platform :ios, '11.0' 65 | ``` 66 | 67 | 2) (optional) Make sure your podfile sets build versions to 11 - if you see this at the bottom of your podfile make sure 68 | the line setting the deployment target to 11 is in there. 69 | ``` 70 | post_install do |installer| 71 | installer.pods_project.targets.each do |target| 72 | target.build_configurations.each do |config| 73 | config.build_settings['ENABLE_BITCODE'] = 'NO' 74 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 75 | end 76 | end 77 | end 78 | ``` 79 | 80 | 3) Setting the `iOS Deployment Target` to 11 in XCode -> Runner -> Build Settings -> Deployment -> iOS Deployment Target. 81 | 82 | ## Building for 64-bit before 11.0. 83 | 84 | If you absolutely need to build for devices before 11.0, you might need to use an old version of the library that supports 85 | 32-bit. If you're willing to live without 32 bit but do need to target before 11.0, you can do that by ignoring the warning 86 | CocoaPods will give you, and setting XCode -> Runner -> Build Settings -> Architectures -> Architectures to `${ARCHS_STANDARD_64_BIT}`. 87 | 88 | ## Usage 89 | 90 | See the example for how to use this plugin; it is the best resource available as it shows 91 | the plugin in use. However, these are the steps you need to take to 92 | use this plugin. 93 | 94 | First, figure out the area that you want the camera preview to be shown in. This is important 95 | as the preview __needs__ to have a constrained size or it won't be able to build. This 96 | is required due to the complex nature of the transforms needed to get the camera preview to 97 | show correctly on both iOS and Android, while still working with the screen rotated etc. 98 | 99 | It may be possible to get the camera preview to work without putting it in a SizedBox or Container, 100 | but the recommended way is to put it in a SizedBox or Container. 101 | 102 | You then need to include the package and instantiate the camera. 103 | 104 | 105 | ``` 106 | import 'package:flutter/material.dart'; 107 | import 'package:flutter_qr_bar_scanner/qr_bar_scanner_camera.dart'; 108 | 109 | void main() { 110 | runApp(MyApp()); 111 | } 112 | 113 | class MyApp extends StatelessWidget { 114 | @override 115 | Widget build(BuildContext context) { 116 | return MaterialApp( 117 | title: 'Flutter QR/Bar Code Reader', 118 | debugShowCheckedModeBanner: false, 119 | theme: ThemeData( 120 | primarySwatch: Colors.blue, 121 | ), 122 | home: MyHomePage(title: 'Flutter QR/Bar Code Reader'), 123 | ); 124 | } 125 | } 126 | 127 | class MyHomePage extends StatefulWidget { 128 | MyHomePage({Key? key, this.title}) : super(key: key); 129 | final String? title; 130 | @override 131 | _MyHomePageState createState() => _MyHomePageState(); 132 | } 133 | 134 | class _MyHomePageState extends State { 135 | String? _qrInfo = 'Scan a QR/Bar code'; 136 | bool _camState = false; 137 | 138 | _qrCallback(String? code) { 139 | setState(() { 140 | _camState = false; 141 | _qrInfo = code; 142 | }); 143 | } 144 | 145 | _scanCode() { 146 | setState(() { 147 | _camState = true; 148 | }); 149 | } 150 | 151 | @override 152 | void initState() { 153 | super.initState(); 154 | _scanCode(); 155 | } 156 | 157 | @override 158 | void dispose() { 159 | super.dispose(); 160 | } 161 | 162 | @override 163 | Widget build(BuildContext context) { 164 | return Scaffold( 165 | appBar: AppBar( 166 | title: Text(widget.title!), 167 | ), 168 | body: _camState 169 | ? Center( 170 | child: SizedBox( 171 | height: 1000, 172 | width: 500, 173 | child: QRBarScannerCamera( 174 | onError: (context, error) => Text( 175 | error.toString(), 176 | style: TextStyle(color: Colors.red), 177 | ), 178 | qrCodeCallback: (code) { 179 | _qrCallback(code); 180 | }, 181 | ), 182 | ), 183 | ) 184 | : Center( 185 | child: Text(_qrInfo!), 186 | ), 187 | ); 188 | } 189 | } 190 | 191 | 192 | ``` 193 | 194 | The QrCodeCallback can do anything you'd like, and wil keep receiving QR/Bar codes 195 | until the camera is stopped. 196 | 197 | There are also optional parameters to QRScannerCamera. 198 | 199 | ### `fit` 200 | 201 | Takes as parameter the flutter `BoxFit`. 202 | Setting this to different values should get the preview image to fit in 203 | different ways, but only `BoxFit = cover` has been tested extensively. 204 | 205 | ### `notStartedBuilder` 206 | 207 | A callback that must return a widget if defined. 208 | This should build whatever you want to show up while the camera is loading (which can take 209 | from milliseconds to seconds depending on the device). 210 | 211 | ### `child` 212 | 213 | Widget that is shown on top of the QRScannerCamera. If you give it a specific size it may cause 214 | weird issues so try not to. 215 | 216 | ### `key` 217 | 218 | Standard flutter key argument. Can be used to get QRScannerCameraState with a GlobalKey. 219 | 220 | ### `offscreenBuilder` 221 | 222 | A callback that must return a widget if defined. 223 | This should build whatever you want to show up when the camera view is 'offscreen'. 224 | i.e. when the app is paused. May or may not show up in preview of app. 225 | 226 | ### `onError` 227 | 228 | Callback for if there's an error. 229 | 230 | ### 'formats' 231 | 232 | A list of supported formats, all by default. If you use all, you shouldn't define any others. 233 | 234 | These are the supported types: 235 | 236 | ``` 237 | ALL_FORMATS, 238 | AZTEC, 239 | CODE_128, 240 | CODE_39, 241 | CODE_93, 242 | CODABAR, 243 | DATA_MATRIX, 244 | EAN_13, 245 | EAN_8, 246 | ITF, 247 | PDF417, 248 | QR_CODE, 249 | UPC_A, 250 | UPC_E 251 | ``` 252 | 253 | ## Push and Pop 254 | 255 | If you push a new widget on top of a the current page using the navigator, the camera doesn't 256 | necessarily know about it. 257 | 258 | ## Contributions 259 | 260 | Any kind of contribution will be appreciated. 261 | 262 | [version_badge]: https://img.shields.io/pub/v/flutter_qr_bar_scanner.svg 263 | 264 | 265 | ## License 266 | [MIT License](https://github.com/contactlutforrahman/flutter_qr_bar_scanner/blob/master/LICENSE) 267 | 268 | 269 | ## Inspire me 270 | [Be a Patreon](https://www.patreon.com/join/_lutfor?) -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrCameraC1.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.ImageFormat; 6 | import android.graphics.SurfaceTexture; 7 | import android.util.Log; 8 | import android.util.SparseIntArray; 9 | import android.view.Surface; 10 | import android.view.WindowManager; 11 | 12 | import com.google.mlkit.vision.common.InputImage; 13 | 14 | import java.io.IOException; 15 | import java.util.List; 16 | 17 | /** 18 | * Implements QrCamera using Deprecated Camera API 19 | * NOTE: uses fully qualified names for android.hardware.Camera 20 | * so that deprecation warnings can be avoided. 21 | */ 22 | @TargetApi(16) 23 | class QrCameraC1 implements QrCamera { 24 | 25 | private static final String TAG = "cgr.qrmv.QrCameraC1"; 26 | private static final int IMAGEFORMAT = ImageFormat.NV21; 27 | private final SurfaceTexture texture; 28 | private final QrDetector detector; 29 | private android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); 30 | private int targetWidth, targetHeight; 31 | private android.hardware.Camera camera = null; 32 | private Context context; 33 | 34 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); 35 | 36 | static { 37 | ORIENTATIONS.append(Surface.ROTATION_0, 90); 38 | ORIENTATIONS.append(Surface.ROTATION_90, 0); 39 | ORIENTATIONS.append(Surface.ROTATION_180, 270); 40 | ORIENTATIONS.append(Surface.ROTATION_270, 180); 41 | } 42 | 43 | QrCameraC1(int width, int height, SurfaceTexture texture, Context context, QrDetector detector) { 44 | this.texture = texture; 45 | targetHeight = height; 46 | targetWidth = width; 47 | this.detector = detector; 48 | this.context = context; 49 | } 50 | 51 | 52 | private int getFirebaseOrientation() { 53 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 54 | int deviceRotation = windowManager.getDefaultDisplay().getRotation(); 55 | int rotationCompensation = (ORIENTATIONS.get(deviceRotation) + info.orientation + 270) % 360; 56 | 57 | // Return the corresponding FirebaseVisionImageMetadata rotation value. 58 | int result; 59 | switch (rotationCompensation) { 60 | case 0: 61 | result = 0; 62 | break; 63 | case 90: 64 | result = 90; 65 | break; 66 | case 180: 67 | result = 180; 68 | break; 69 | case 270: 70 | result = 270; 71 | break; 72 | default: 73 | result = Surface.ROTATION_0; 74 | Log.e(TAG, "Bad rotation value: " + rotationCompensation); 75 | } 76 | return result; 77 | } 78 | 79 | @Override 80 | public void start() throws QrReader.Exception { 81 | int numberOfCameras = android.hardware.Camera.getNumberOfCameras(); 82 | info = new android.hardware.Camera.CameraInfo(); 83 | for (int i = 0; i < numberOfCameras; i++) { 84 | android.hardware.Camera.getCameraInfo(i, info); 85 | if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) { 86 | camera = android.hardware.Camera.open(i); 87 | break; 88 | } 89 | } 90 | 91 | if (camera == null) { 92 | throw new QrReader.Exception(QrReader.Exception.Reason.noBackCamera); 93 | } 94 | 95 | final android.hardware.Camera.Parameters parameters = camera.getParameters(); 96 | 97 | List focusModes = parameters.getSupportedFocusModes(); 98 | if (focusModes.contains(android.hardware.Camera.Parameters.FOCUS_MODE_AUTO)) { 99 | Log.i(TAG, "Initializing with autofocus on."); 100 | parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_AUTO); 101 | } else { 102 | Log.i(TAG, "Initializing with autofocus off as not supported."); 103 | } 104 | 105 | List supportedSizes = parameters.getSupportedPreviewSizes(); 106 | android.hardware.Camera.Size size = getAppropriateSize(supportedSizes); 107 | 108 | parameters.setPreviewSize(size.width, size.height); 109 | texture.setDefaultBufferSize(size.width, size.height); 110 | 111 | parameters.setPreviewFormat(IMAGEFORMAT); 112 | 113 | try { 114 | camera.setPreviewCallback(new android.hardware.Camera.PreviewCallback() { 115 | @Override 116 | public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { 117 | android.hardware.Camera.Size previewSize = camera.getParameters().getPreviewSize(); 118 | 119 | if (data != null) { 120 | 121 | QrDetector.Frame frame = new Frame(data, 122 | previewSize.width, previewSize.height, getFirebaseOrientation(), IMAGEFORMAT); 123 | detector.detect(frame); 124 | } else { 125 | //TODO: something better here? 126 | System.out.println("It's NULL!"); 127 | } 128 | } 129 | }); 130 | camera.setPreviewTexture(texture); 131 | camera.startPreview(); 132 | camera.autoFocus(new android.hardware.Camera.AutoFocusCallback() { 133 | @Override 134 | public void onAutoFocus(boolean success, android.hardware.Camera camera) { 135 | } 136 | }); 137 | } catch (IOException e) { 138 | e.printStackTrace(); 139 | } 140 | 141 | } 142 | 143 | static class Frame implements QrDetector.Frame { 144 | private byte[] data; 145 | private final int imageFormat; 146 | private final int width; 147 | private final int height; 148 | private final int rotationDegrees; 149 | 150 | Frame(byte[] data, int width, int height, int rotationDegrees, int imageFormat) { 151 | this.data = data; 152 | this.width = width; 153 | this.height = height; 154 | this.rotationDegrees = rotationDegrees; 155 | this.imageFormat = imageFormat; 156 | } 157 | 158 | @Override 159 | public InputImage toImage() { 160 | //fromByteArray(byte[] byteArray, int width, int height, int rotationDegrees, int format) 161 | return InputImage.fromByteArray(data, width, height, rotationDegrees, imageFormat); 162 | } 163 | 164 | @Override 165 | public void close() { 166 | data = null; 167 | } 168 | } 169 | 170 | @Override 171 | public int getWidth() { 172 | return camera.getParameters().getPreviewSize().height; 173 | } 174 | 175 | @Override 176 | public int getHeight() { 177 | return camera.getParameters().getPreviewSize().width; 178 | } 179 | 180 | @Override 181 | public int getOrientation() { 182 | return (info.orientation + 270) % 360; 183 | } 184 | 185 | @Override 186 | public void stop() { 187 | if (camera != null) { 188 | camera.stopPreview(); 189 | camera.setPreviewCallback(null); 190 | camera.release(); 191 | camera = null; 192 | } 193 | } 194 | 195 | //Size here is Camera.Size, not android.util.Size as in the QrCameraC2 version of this method 196 | private android.hardware.Camera.Size getAppropriateSize(List sizes) { 197 | // assume sizes is never 0 198 | if (sizes.size() == 1) { 199 | return sizes.get(0); 200 | } 201 | 202 | android.hardware.Camera.Size s = sizes.get(0); 203 | android.hardware.Camera.Size s1 = sizes.get(1); 204 | 205 | if (s1.width > s.width || s1.height > s.height) { 206 | // ascending 207 | if (info.orientation % 180 == 0) { 208 | for (android.hardware.Camera.Size size : sizes) { 209 | s = size; 210 | if (size.height > targetHeight && size.width > targetWidth) { 211 | break; 212 | } 213 | } 214 | } else { 215 | for (android.hardware.Camera.Size size : sizes) { 216 | s = size; 217 | if (size.height > targetWidth && size.width > targetHeight) { 218 | break; 219 | } 220 | } 221 | } 222 | } else { 223 | // descending 224 | if (info.orientation % 180 == 0) { 225 | for (android.hardware.Camera.Size size : sizes) { 226 | if (size.height < targetHeight || size.width < targetWidth) { 227 | break; 228 | } 229 | s = size; 230 | } 231 | } else { 232 | for (android.hardware.Camera.Size size : sizes) { 233 | if (size.height < targetWidth || size.width < targetHeight) { 234 | break; 235 | } 236 | s = size; 237 | } 238 | } 239 | } 240 | return s; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/FlutterQrBarScannerPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.pm.PackageManager; 6 | import android.util.Log; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.core.app.ActivityCompat; 10 | 11 | 12 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions; 13 | 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | import io.flutter.embedding.engine.plugins.FlutterPlugin; 21 | import io.flutter.embedding.engine.plugins.activity.ActivityAware; 22 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; 23 | import io.flutter.plugin.common.BinaryMessenger; 24 | import io.flutter.plugin.common.MethodCall; 25 | import io.flutter.plugin.common.MethodChannel; 26 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 27 | import io.flutter.plugin.common.MethodChannel.Result; 28 | import io.flutter.plugin.common.PluginRegistry; 29 | import io.flutter.plugin.common.PluginRegistry.Registrar; 30 | import io.flutter.view.TextureRegistry; 31 | 32 | 33 | /** 34 | * FlutterQrBarScannerPlugin 35 | */ 36 | public class FlutterQrBarScannerPlugin implements MethodCallHandler, QrReaderCallbacks, QrReader.QRReaderStartedCallback, PluginRegistry.RequestPermissionsResultListener, FlutterPlugin, ActivityAware { 37 | 38 | private static final String TAG = "cgr.qrmv.FlutterQrBarScannerPlugin"; 39 | private static final int REQUEST_PERMISSION = 1; 40 | private MethodChannel channel; 41 | private Activity activity; 42 | private TextureRegistry textures; 43 | private Integer lastHeartbeatTimeout; 44 | private boolean waitingForPermissionResult; 45 | private boolean permissionDenied; 46 | private ReadingInstance readingInstance; 47 | private FlutterPluginBinding flutterPluginBinding; 48 | 49 | /** 50 | * Plugin registration. 51 | */ 52 | public static void registerWith(Registrar registrar) { 53 | FlutterQrBarScannerPlugin plugin = new FlutterQrBarScannerPlugin(); 54 | plugin.performV1Registration(registrar); 55 | } 56 | 57 | @Override 58 | public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { 59 | flutterPluginBinding = binding; 60 | } 61 | 62 | @Override 63 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 64 | flutterPluginBinding = null; 65 | } 66 | 67 | @Override 68 | public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { 69 | performV2Registration(flutterPluginBinding, binding); 70 | } 71 | 72 | @Override 73 | public void onDetachedFromActivityForConfigChanges() { 74 | onDetachedFromActivity(); 75 | } 76 | 77 | @Override 78 | public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { 79 | onAttachedToActivity(binding); 80 | } 81 | 82 | @Override 83 | public void onDetachedFromActivity() { 84 | channel.setMethodCallHandler(null); 85 | channel = null; 86 | } 87 | 88 | private void performV1Registration(Registrar registrar) { 89 | performRegistration(true, registrar, null, null); 90 | } 91 | 92 | private void performV2Registration(FlutterPluginBinding flutterPluginBinding, ActivityPluginBinding activityPluginBinding) { 93 | performRegistration(false, null, flutterPluginBinding, activityPluginBinding); 94 | } 95 | 96 | private void performRegistration(boolean isVersion1Embedding, Registrar registrar, FlutterPluginBinding flutterPluginBinding, ActivityPluginBinding activityPluginBinding) { 97 | Log.i(TAG, "Plugin Registration being performed: " + 98 | "isVersion1Embedding " + isVersion1Embedding + 99 | ", registrar " + registrar + 100 | ", flutterPluginBinding " + flutterPluginBinding + 101 | ", activityPluginBinding " + activityPluginBinding); 102 | 103 | BinaryMessenger messenger; 104 | if (isVersion1Embedding) { 105 | messenger = registrar.messenger(); 106 | activity = registrar.activity(); 107 | textures = registrar.textures(); 108 | registrar.addRequestPermissionsResultListener(this); 109 | } else { 110 | messenger = flutterPluginBinding.getBinaryMessenger(); 111 | activity = activityPluginBinding.getActivity(); 112 | textures = flutterPluginBinding.getTextureRegistry(); 113 | activityPluginBinding.addRequestPermissionsResultListener(this); 114 | } 115 | channel = new MethodChannel(messenger, "com.github.contactlutforrahman/flutter_qr_bar_scanner"); 116 | channel.setMethodCallHandler(this); 117 | } 118 | 119 | @Override 120 | public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 121 | if (requestCode == REQUEST_PERMISSION) { 122 | waitingForPermissionResult = false; 123 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 124 | Log.i(TAG, "Permissions request granted."); 125 | stopReader(); 126 | } else { 127 | Log.i(TAG, "Permissions request denied."); 128 | permissionDenied = true; 129 | startingFailed(new QrReader.Exception(QrReader.Exception.Reason.noPermissions)); 130 | stopReader(); 131 | } 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | private void stopReader() { 138 | if (readingInstance != null) { 139 | if (readingInstance.reader != null) { 140 | readingInstance.reader.stop(); 141 | } 142 | if (readingInstance.textureEntry != null) { 143 | readingInstance.textureEntry.release(); 144 | } 145 | } 146 | readingInstance = null; 147 | lastHeartbeatTimeout = null; 148 | } 149 | 150 | @Override 151 | public void onMethodCall(MethodCall methodCall, Result result) { 152 | switch (methodCall.method) { 153 | case "start": { 154 | if (permissionDenied) { 155 | permissionDenied = false; 156 | result.error("QRREADER_ERROR", "noPermission", null); 157 | } else if (readingInstance != null) { 158 | result.error("ALREADY_RUNNING", "Start cannot be called when already running", ""); 159 | } else { 160 | lastHeartbeatTimeout = methodCall.argument("heartbeatTimeout"); 161 | Integer targetWidth = methodCall.argument("targetWidth"); 162 | Integer targetHeight = methodCall.argument("targetHeight"); 163 | List formatStrings = methodCall.argument("formats"); 164 | 165 | if (targetWidth == null || targetHeight == null) { 166 | result.error("INVALID_ARGUMENT", "Missing a required argument", "Expecting targetWidth, targetHeight, and optionally heartbeatTimeout"); 167 | break; 168 | } 169 | 170 | BarcodeScannerOptions options = BarcodeFormats.optionsFromStringList(formatStrings); 171 | 172 | TextureRegistry.SurfaceTextureEntry textureEntry = textures.createSurfaceTexture(); 173 | QrReader reader = new QrReader(targetWidth, targetHeight, activity, options, 174 | this, this, textureEntry.surfaceTexture()); 175 | 176 | readingInstance = new ReadingInstance(reader, textureEntry, result); 177 | try { 178 | reader.start( 179 | lastHeartbeatTimeout == null ? 0 : lastHeartbeatTimeout 180 | ); 181 | } catch (IOException e) { 182 | e.printStackTrace(); 183 | result.error("IOException", "Error starting camera because of IOException: " + e.getLocalizedMessage(), null); 184 | } catch (QrReader.Exception e) { 185 | e.printStackTrace(); 186 | result.error(e.reason().name(), "Error starting camera for reason: " + e.reason().name(), null); 187 | } catch (NoPermissionException e) { 188 | waitingForPermissionResult = true; 189 | ActivityCompat.requestPermissions(activity, 190 | new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION); 191 | } 192 | } 193 | break; 194 | } 195 | case "stop": { 196 | if (readingInstance != null && !waitingForPermissionResult) { 197 | stopReader(); 198 | } 199 | result.success(null); 200 | break; 201 | } 202 | case "heartbeat": { 203 | if (readingInstance != null) { 204 | readingInstance.reader.heartBeat(); 205 | } 206 | result.success(null); 207 | break; 208 | } 209 | default: 210 | result.notImplemented(); 211 | } 212 | } 213 | 214 | @Override 215 | public void qrRead(String data) { 216 | channel.invokeMethod("qrRead", data); 217 | } 218 | 219 | @Override 220 | public void started() { 221 | Map response = new HashMap<>(); 222 | response.put("surfaceWidth", readingInstance.reader.qrCamera.getWidth()); 223 | response.put("surfaceHeight", readingInstance.reader.qrCamera.getHeight()); 224 | response.put("surfaceOrientation", readingInstance.reader.qrCamera.getOrientation()); 225 | response.put("textureId", readingInstance.textureEntry.id()); 226 | readingInstance.startResult.success(response); 227 | } 228 | 229 | private List stackTraceAsString(StackTraceElement[] stackTrace) { 230 | if (stackTrace == null) { 231 | return null; 232 | } 233 | 234 | List stackTraceStrings = new ArrayList<>(stackTrace.length); 235 | for (StackTraceElement el : stackTrace) { 236 | stackTraceStrings.add(el.toString()); 237 | } 238 | return stackTraceStrings; 239 | } 240 | 241 | @Override 242 | public void startingFailed(Throwable t) { 243 | Log.w(TAG, "Starting QR Mobile Vision failed", t); 244 | List stackTraceStrings = stackTraceAsString(t.getStackTrace()); 245 | 246 | if (t instanceof QrReader.Exception) { 247 | QrReader.Exception qrException = (QrReader.Exception) t; 248 | readingInstance.startResult.error("QRREADER_ERROR", qrException.reason().name(), stackTraceStrings); 249 | } else { 250 | readingInstance.startResult.error("UNKNOWN_ERROR", t.getMessage(), stackTraceStrings); 251 | } 252 | } 253 | 254 | private class ReadingInstance { 255 | final QrReader reader; 256 | final TextureRegistry.SurfaceTextureEntry textureEntry; 257 | final Result startResult; 258 | 259 | private ReadingInstance(QrReader reader, TextureRegistry.SurfaceTextureEntry textureEntry, Result startResult) { 260 | this.reader = reader; 261 | this.textureEntry = textureEntry; 262 | this.startResult = startResult; 263 | } 264 | } 265 | } -------------------------------------------------------------------------------- /android/src/main/java/com/github/contactlutforrahman/flutter_qr_bar_scanner/QrCameraC2.java: -------------------------------------------------------------------------------- 1 | package com.github.contactlutforrahman.flutter_qr_bar_scanner; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.ImageFormat; 6 | import android.graphics.SurfaceTexture; 7 | import android.hardware.camera2.CameraAccessException; 8 | import android.hardware.camera2.CameraCaptureSession; 9 | import android.hardware.camera2.CameraCharacteristics; 10 | import android.hardware.camera2.CameraDevice; 11 | import android.hardware.camera2.CameraManager; 12 | import android.hardware.camera2.CameraMetadata; 13 | import android.hardware.camera2.CaptureRequest; 14 | import android.hardware.camera2.TotalCaptureResult; 15 | import android.hardware.camera2.params.StreamConfigurationMap; 16 | import android.media.Image; 17 | import android.media.ImageReader; 18 | import android.util.Log; 19 | import android.util.Size; 20 | import android.util.SparseIntArray; 21 | import android.view.Surface; 22 | import android.view.WindowManager; 23 | 24 | import androidx.annotation.NonNull; 25 | import androidx.annotation.RequiresApi; 26 | 27 | import com.google.mlkit.vision.common.InputImage; 28 | 29 | import java.util.ArrayList; 30 | import java.util.HashSet; 31 | import java.util.List; 32 | 33 | import static android.hardware.camera2.CameraMetadata.CONTROL_AF_MODE_AUTO; 34 | import static android.hardware.camera2.CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE; 35 | import static android.hardware.camera2.CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO; 36 | import static android.hardware.camera2.CameraMetadata.LENS_FACING_BACK; 37 | 38 | /** 39 | * Implements QrCamera using Camera2 API 40 | */ 41 | @TargetApi(21) 42 | @RequiresApi(21) 43 | class QrCameraC2 implements QrCamera { 44 | 45 | private static final String TAG = "cgr.qrmv.QrCameraC2"; 46 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); 47 | 48 | static { 49 | ORIENTATIONS.append(Surface.ROTATION_0, 90); 50 | ORIENTATIONS.append(Surface.ROTATION_90, 0); 51 | ORIENTATIONS.append(Surface.ROTATION_180, 270); 52 | ORIENTATIONS.append(Surface.ROTATION_270, 180); 53 | } 54 | 55 | private final int targetWidth; 56 | private final int targetHeight; 57 | private final Context context; 58 | private final SurfaceTexture texture; 59 | private Size size; 60 | private ImageReader reader; 61 | private CaptureRequest.Builder previewBuilder; 62 | private CameraCaptureSession previewSession; 63 | private Size[] jpegSizes = null; 64 | private QrDetector detector; 65 | private int sensorOrientation; 66 | private CameraDevice cameraDevice; 67 | private CameraCharacteristics cameraCharacteristics; 68 | private Frame latestFrame; 69 | 70 | QrCameraC2(int width, int height, SurfaceTexture texture, Context context, QrDetector detector) { 71 | this.targetWidth = width; 72 | this.targetHeight = height; 73 | this.context = context; 74 | this.texture = texture; 75 | this.detector = detector; 76 | } 77 | 78 | @Override 79 | public int getWidth() { 80 | return size.getWidth(); 81 | } 82 | 83 | @Override 84 | public int getHeight() { 85 | return size.getHeight(); 86 | } 87 | 88 | @Override 89 | public int getOrientation() { 90 | // ignore sensor orientation of devices with 'reverse landscape' orientation of sensor 91 | // as camera2 api seems to already rotate the output. 92 | return sensorOrientation == 270 ? 90 : sensorOrientation; 93 | } 94 | 95 | private int getFirebaseOrientation() { 96 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 97 | int deviceRotation = windowManager.getDefaultDisplay().getRotation(); 98 | int rotationCompensation = (ORIENTATIONS.get(deviceRotation) + sensorOrientation + 270) % 360; 99 | 100 | // Return the corresponding FirebaseVisionImageMetadata rotation value. 101 | int result; 102 | switch (rotationCompensation) { 103 | case 0: 104 | result = 0; 105 | break; 106 | case 90: 107 | result = 90; 108 | break; 109 | case 180: 110 | result = 180; 111 | break; 112 | case 270: 113 | result = 270; 114 | break; 115 | default: 116 | result = 0; 117 | Log.e(TAG, "Bad rotation value: " + rotationCompensation); 118 | } 119 | return result; 120 | } 121 | 122 | @Override 123 | public void start() throws QrReader.Exception { 124 | CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 125 | 126 | if (manager == null) { 127 | throw new RuntimeException("Unable to get camera manager."); 128 | } 129 | 130 | String cameraId = null; 131 | try { 132 | String[] cameraIdList = manager.getCameraIdList(); 133 | for (String id : cameraIdList) { 134 | CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(id); 135 | Integer integer = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING); 136 | if (integer != null && integer == LENS_FACING_BACK) { 137 | cameraId = id; 138 | break; 139 | } 140 | } 141 | } catch (CameraAccessException e) { 142 | Log.w(TAG, "Error getting back camera.", e); 143 | throw new RuntimeException(e); 144 | } 145 | 146 | if (cameraId == null) { 147 | throw new QrReader.Exception(QrReader.Exception.Reason.noBackCamera); 148 | } 149 | 150 | try { 151 | cameraCharacteristics = manager.getCameraCharacteristics(cameraId); 152 | StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 153 | Integer sensorOrientationInteger = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 154 | sensorOrientation = sensorOrientationInteger == null ? 0 : sensorOrientationInteger; 155 | 156 | size = getAppropriateSize(map.getOutputSizes(SurfaceTexture.class)); 157 | jpegSizes = map.getOutputSizes(ImageFormat.JPEG); 158 | 159 | manager.openCamera(cameraId, new CameraDevice.StateCallback() { 160 | @Override 161 | public void onOpened(@NonNull CameraDevice device) { 162 | cameraDevice = device; 163 | startCamera(); 164 | } 165 | 166 | @Override 167 | public void onDisconnected(@NonNull CameraDevice device) { 168 | } 169 | 170 | @Override 171 | public void onError(@NonNull CameraDevice device, int error) { 172 | Log.w(TAG, "Error opening camera: " + error); 173 | } 174 | }, null); 175 | } catch (CameraAccessException e) { 176 | Log.w(TAG, "Error getting camera configuration.", e); 177 | } 178 | } 179 | 180 | private Integer afMode(CameraCharacteristics cameraCharacteristics) { 181 | 182 | int[] afModes = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); 183 | 184 | if (afModes == null) { 185 | return null; 186 | } 187 | 188 | HashSet modes = new HashSet<>(afModes.length * 2); 189 | for (int afMode : afModes) { 190 | modes.add(afMode); 191 | } 192 | 193 | if (modes.contains(CONTROL_AF_MODE_CONTINUOUS_VIDEO)) { 194 | return CONTROL_AF_MODE_CONTINUOUS_VIDEO; 195 | } else if (modes.contains(CONTROL_AF_MODE_CONTINUOUS_PICTURE)) { 196 | return CONTROL_AF_MODE_CONTINUOUS_PICTURE; 197 | } else if (modes.contains(CONTROL_AF_MODE_AUTO)) { 198 | return CONTROL_AF_MODE_AUTO; 199 | } else { 200 | return null; 201 | } 202 | } 203 | 204 | static class Frame implements QrDetector.Frame { 205 | final Image image; 206 | final int firebaseOrientation; 207 | 208 | Frame(Image image, int firebaseOrientation) { 209 | this.image = image; 210 | this.firebaseOrientation = firebaseOrientation; 211 | } 212 | 213 | @Override 214 | public InputImage toImage() { 215 | return InputImage.fromMediaImage(image, firebaseOrientation); 216 | } 217 | 218 | @Override 219 | public void close() { 220 | image.close(); 221 | } 222 | 223 | } 224 | 225 | private void startCamera() { 226 | List list = new ArrayList<>(); 227 | 228 | Size jpegSize = getAppropriateSize(jpegSizes); 229 | 230 | final int width = jpegSize.getWidth(), height = jpegSize.getHeight(); 231 | reader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 5); 232 | 233 | list.add(reader.getSurface()); 234 | 235 | ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() { 236 | @Override 237 | public void onImageAvailable(ImageReader reader) { 238 | try { 239 | Image image = reader.acquireLatestImage(); 240 | if (image == null) return; 241 | latestFrame = new Frame(image, getFirebaseOrientation()); 242 | detector.detect(latestFrame); 243 | } catch (Throwable t) { 244 | t.printStackTrace(); 245 | } 246 | } 247 | }; 248 | 249 | reader.setOnImageAvailableListener(imageAvailableListener, null); 250 | 251 | texture.setDefaultBufferSize(size.getWidth(), size.getHeight()); 252 | list.add(new Surface(texture)); 253 | try { 254 | previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 255 | previewBuilder.addTarget(list.get(0)); 256 | previewBuilder.addTarget(list.get(1)); 257 | 258 | Integer afMode = afMode(cameraCharacteristics); 259 | 260 | previewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 261 | 262 | if (afMode != null) { 263 | previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, afMode); 264 | Log.i(TAG, "Setting af mode to: " + afMode); 265 | if (afMode == CONTROL_AF_MODE_AUTO) { 266 | previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); 267 | } else { 268 | previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 269 | } 270 | } 271 | } catch (java.lang.Exception e) { 272 | e.printStackTrace(); 273 | return; 274 | } 275 | 276 | try { 277 | cameraDevice.createCaptureSession(list, new CameraCaptureSession.StateCallback() { 278 | @Override 279 | public void onConfigured(@NonNull CameraCaptureSession session) { 280 | previewSession = session; 281 | startPreview(); 282 | } 283 | 284 | @Override 285 | public void onConfigureFailed(@NonNull CameraCaptureSession session) { 286 | System.out.println("### Configuration Fail ###"); 287 | } 288 | }, null); 289 | } catch (Throwable t) { 290 | t.printStackTrace(); 291 | } 292 | } 293 | 294 | private void startPreview() { 295 | CameraCaptureSession.CaptureCallback listener = new CameraCaptureSession.CaptureCallback() { 296 | @Override 297 | public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { 298 | super.onCaptureCompleted(session, request, result); 299 | } 300 | }; 301 | 302 | if (cameraDevice == null) return; 303 | 304 | try { 305 | previewSession.setRepeatingRequest(previewBuilder.build(), listener, null); 306 | } catch (java.lang.Exception e) { 307 | e.printStackTrace(); 308 | } 309 | } 310 | 311 | @Override 312 | public void stop() { 313 | if (cameraDevice != null) { 314 | cameraDevice.close(); 315 | } 316 | if (reader != null) { 317 | if (latestFrame != null) latestFrame.close(); 318 | latestFrame = null; 319 | reader.close(); 320 | } 321 | } 322 | 323 | private Size getAppropriateSize(Size[] sizes) { 324 | // assume sizes is never 0 325 | if (sizes.length == 1) { 326 | return sizes[0]; 327 | } 328 | 329 | Size s = sizes[0]; 330 | Size s1 = sizes[1]; 331 | 332 | if (s1.getWidth() > s.getWidth() || s1.getHeight() > s.getHeight()) { 333 | // ascending 334 | if (sensorOrientation % 180 == 0) { 335 | for (Size size : sizes) { 336 | s = size; 337 | if (size.getHeight() > targetHeight && size.getWidth() > targetWidth) { 338 | break; 339 | } 340 | } 341 | } else { 342 | for (Size size : sizes) { 343 | s = size; 344 | if (size.getHeight() > targetWidth && size.getWidth() > targetHeight) { 345 | break; 346 | } 347 | } 348 | } 349 | } else { 350 | // descending 351 | if (sensorOrientation % 180 == 0) { 352 | for (Size size : sizes) { 353 | if (size.getHeight() < targetHeight || size.getWidth() < targetWidth) { 354 | break; 355 | } 356 | s = size; 357 | } 358 | } else { 359 | for (Size size : sizes) { 360 | if (size.getHeight() < targetWidth || size.getWidth() < targetHeight) { 361 | break; 362 | } 363 | s = size; 364 | } 365 | } 366 | } 367 | return s; 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 35463D8686DA93758B2EFC70 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F31A6CE555078447EDFD0A9 /* Pods_Runner.framework */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 35 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 36 | 5F31A6CE555078447EDFD0A9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 38 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | 770D75C4FD062C57431D378B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 41 | 92D06B0AA7671CFD536A30CE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 42 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 43 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 44 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 48 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | BAC967EAB4F197166412C89B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 35463D8686DA93758B2EFC70 /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 9740EEB11CF90186004384FC /* Flutter */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 68 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 69 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 70 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 71 | ); 72 | name = Flutter; 73 | sourceTree = ""; 74 | }; 75 | 97C146E51CF9000F007C117D = { 76 | isa = PBXGroup; 77 | children = ( 78 | 9740EEB11CF90186004384FC /* Flutter */, 79 | 97C146F01CF9000F007C117D /* Runner */, 80 | 97C146EF1CF9000F007C117D /* Products */, 81 | A02E6F75924FBF84FAB8E778 /* Pods */, 82 | B4A8015565641077090EFD24 /* Frameworks */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | 97C146EF1CF9000F007C117D /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146EE1CF9000F007C117D /* Runner.app */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | 97C146F01CF9000F007C117D /* Runner */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 98 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 99 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 100 | 97C147021CF9000F007C117D /* Info.plist */, 101 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 102 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 103 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 104 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 105 | ); 106 | path = Runner; 107 | sourceTree = ""; 108 | }; 109 | A02E6F75924FBF84FAB8E778 /* Pods */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 770D75C4FD062C57431D378B /* Pods-Runner.debug.xcconfig */, 113 | BAC967EAB4F197166412C89B /* Pods-Runner.release.xcconfig */, 114 | 92D06B0AA7671CFD536A30CE /* Pods-Runner.profile.xcconfig */, 115 | ); 116 | path = Pods; 117 | sourceTree = ""; 118 | }; 119 | B4A8015565641077090EFD24 /* Frameworks */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 5F31A6CE555078447EDFD0A9 /* Pods_Runner.framework */, 123 | ); 124 | name = Frameworks; 125 | sourceTree = ""; 126 | }; 127 | /* End PBXGroup section */ 128 | 129 | /* Begin PBXNativeTarget section */ 130 | 97C146ED1CF9000F007C117D /* Runner */ = { 131 | isa = PBXNativeTarget; 132 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 133 | buildPhases = ( 134 | 8CDF0F25D7801A795114FA80 /* [CP] Check Pods Manifest.lock */, 135 | 9740EEB61CF901F6004384FC /* Run Script */, 136 | 97C146EA1CF9000F007C117D /* Sources */, 137 | 97C146EB1CF9000F007C117D /* Frameworks */, 138 | 97C146EC1CF9000F007C117D /* Resources */, 139 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 140 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 141 | 9D35610C5DAD53BE5474F808 /* [CP] Embed Pods Frameworks */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 1020; 159 | ORGANIZATIONNAME = ""; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | LastSwiftMigration = 1100; 164 | }; 165 | }; 166 | }; 167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 168 | compatibilityVersion = "Xcode 9.3"; 169 | developmentRegion = en; 170 | hasScannedForEncodings = 0; 171 | knownRegions = ( 172 | en, 173 | Base, 174 | ); 175 | mainGroup = 97C146E51CF9000F007C117D; 176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 177 | projectDirPath = ""; 178 | projectRoot = ""; 179 | targets = ( 180 | 97C146ED1CF9000F007C117D /* Runner */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXResourcesBuildPhase section */ 186 | 97C146EC1CF9000F007C117D /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 191 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | /* End PBXResourcesBuildPhase section */ 198 | 199 | /* Begin PBXShellScriptBuildPhase section */ 200 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 201 | isa = PBXShellScriptBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | ); 205 | inputPaths = ( 206 | ); 207 | name = "Thin Binary"; 208 | outputPaths = ( 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | shellPath = /bin/sh; 212 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 213 | }; 214 | 8CDF0F25D7801A795114FA80 /* [CP] Check Pods Manifest.lock */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputFileListPaths = ( 220 | ); 221 | inputPaths = ( 222 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 223 | "${PODS_ROOT}/Manifest.lock", 224 | ); 225 | name = "[CP] Check Pods Manifest.lock"; 226 | outputFileListPaths = ( 227 | ); 228 | outputPaths = ( 229 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | shellPath = /bin/sh; 233 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 234 | showEnvVarsInLog = 0; 235 | }; 236 | 9740EEB61CF901F6004384FC /* Run Script */ = { 237 | isa = PBXShellScriptBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | inputPaths = ( 242 | ); 243 | name = "Run Script"; 244 | outputPaths = ( 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | shellPath = /bin/sh; 248 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 249 | }; 250 | 9D35610C5DAD53BE5474F808 /* [CP] Embed Pods Frameworks */ = { 251 | isa = PBXShellScriptBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | ); 255 | inputFileListPaths = ( 256 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 257 | ); 258 | name = "[CP] Embed Pods Frameworks"; 259 | outputFileListPaths = ( 260 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | shellPath = /bin/sh; 264 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 265 | showEnvVarsInLog = 0; 266 | }; 267 | /* End PBXShellScriptBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | 97C146EA1CF9000F007C117D /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 275 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 276 | ); 277 | runOnlyForDeploymentPostprocessing = 0; 278 | }; 279 | /* End PBXSourcesBuildPhase section */ 280 | 281 | /* Begin PBXVariantGroup section */ 282 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 283 | isa = PBXVariantGroup; 284 | children = ( 285 | 97C146FB1CF9000F007C117D /* Base */, 286 | ); 287 | name = Main.storyboard; 288 | sourceTree = ""; 289 | }; 290 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 291 | isa = PBXVariantGroup; 292 | children = ( 293 | 97C147001CF9000F007C117D /* Base */, 294 | ); 295 | name = LaunchScreen.storyboard; 296 | sourceTree = ""; 297 | }; 298 | /* End PBXVariantGroup section */ 299 | 300 | /* Begin XCBuildConfiguration section */ 301 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ALWAYS_SEARCH_USER_PATHS = NO; 305 | CLANG_ANALYZER_NONNULL = YES; 306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 307 | CLANG_CXX_LIBRARY = "libc++"; 308 | CLANG_ENABLE_MODULES = YES; 309 | CLANG_ENABLE_OBJC_ARC = YES; 310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_COMMA = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNREACHABLE_CODE = YES; 328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 330 | COPY_PHASE_STRIP = NO; 331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 332 | ENABLE_NS_ASSERTIONS = NO; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | GCC_C_LANGUAGE_STANDARD = gnu99; 335 | GCC_NO_COMMON_BLOCKS = YES; 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | GCC_WARN_UNUSED_VARIABLE = YES; 342 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 343 | MTL_ENABLE_DEBUG_INFO = NO; 344 | SDKROOT = iphoneos; 345 | SUPPORTED_PLATFORMS = iphoneos; 346 | TARGETED_DEVICE_FAMILY = "1,2"; 347 | VALIDATE_PRODUCT = YES; 348 | }; 349 | name = Profile; 350 | }; 351 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 352 | isa = XCBuildConfiguration; 353 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 354 | buildSettings = { 355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 356 | CLANG_ENABLE_MODULES = YES; 357 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 358 | DEVELOPMENT_TEAM = T684S67N2Y; 359 | ENABLE_BITCODE = NO; 360 | INFOPLIST_FILE = Runner/Info.plist; 361 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | ); 366 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 367 | PRODUCT_NAME = "$(TARGET_NAME)"; 368 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 369 | SWIFT_VERSION = 5.0; 370 | VERSIONING_SYSTEM = "apple-generic"; 371 | }; 372 | name = Profile; 373 | }; 374 | 97C147031CF9000F007C117D /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ALWAYS_SEARCH_USER_PATHS = NO; 378 | CLANG_ANALYZER_NONNULL = YES; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 384 | CLANG_WARN_BOOL_CONVERSION = YES; 385 | CLANG_WARN_COMMA = YES; 386 | CLANG_WARN_CONSTANT_CONVERSION = YES; 387 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INFINITE_RECURSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 394 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 395 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 396 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 397 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 398 | CLANG_WARN_STRICT_PROTOTYPES = YES; 399 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 400 | CLANG_WARN_UNREACHABLE_CODE = YES; 401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 403 | COPY_PHASE_STRIP = NO; 404 | DEBUG_INFORMATION_FORMAT = dwarf; 405 | ENABLE_STRICT_OBJC_MSGSEND = YES; 406 | ENABLE_TESTABILITY = YES; 407 | GCC_C_LANGUAGE_STANDARD = gnu99; 408 | GCC_DYNAMIC_NO_PIC = NO; 409 | GCC_NO_COMMON_BLOCKS = YES; 410 | GCC_OPTIMIZATION_LEVEL = 0; 411 | GCC_PREPROCESSOR_DEFINITIONS = ( 412 | "DEBUG=1", 413 | "$(inherited)", 414 | ); 415 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 416 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 417 | GCC_WARN_UNDECLARED_SELECTOR = YES; 418 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 419 | GCC_WARN_UNUSED_FUNCTION = YES; 420 | GCC_WARN_UNUSED_VARIABLE = YES; 421 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 422 | MTL_ENABLE_DEBUG_INFO = YES; 423 | ONLY_ACTIVE_ARCH = YES; 424 | SDKROOT = iphoneos; 425 | TARGETED_DEVICE_FAMILY = "1,2"; 426 | }; 427 | name = Debug; 428 | }; 429 | 97C147041CF9000F007C117D /* Release */ = { 430 | isa = XCBuildConfiguration; 431 | buildSettings = { 432 | ALWAYS_SEARCH_USER_PATHS = NO; 433 | CLANG_ANALYZER_NONNULL = YES; 434 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 435 | CLANG_CXX_LIBRARY = "libc++"; 436 | CLANG_ENABLE_MODULES = YES; 437 | CLANG_ENABLE_OBJC_ARC = YES; 438 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 439 | CLANG_WARN_BOOL_CONVERSION = YES; 440 | CLANG_WARN_COMMA = YES; 441 | CLANG_WARN_CONSTANT_CONVERSION = YES; 442 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 443 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 444 | CLANG_WARN_EMPTY_BODY = YES; 445 | CLANG_WARN_ENUM_CONVERSION = YES; 446 | CLANG_WARN_INFINITE_RECURSION = YES; 447 | CLANG_WARN_INT_CONVERSION = YES; 448 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 449 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 450 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 451 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 452 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 453 | CLANG_WARN_STRICT_PROTOTYPES = YES; 454 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 455 | CLANG_WARN_UNREACHABLE_CODE = YES; 456 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 457 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 458 | COPY_PHASE_STRIP = NO; 459 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 460 | ENABLE_NS_ASSERTIONS = NO; 461 | ENABLE_STRICT_OBJC_MSGSEND = YES; 462 | GCC_C_LANGUAGE_STANDARD = gnu99; 463 | GCC_NO_COMMON_BLOCKS = YES; 464 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 465 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 466 | GCC_WARN_UNDECLARED_SELECTOR = YES; 467 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 468 | GCC_WARN_UNUSED_FUNCTION = YES; 469 | GCC_WARN_UNUSED_VARIABLE = YES; 470 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 471 | MTL_ENABLE_DEBUG_INFO = NO; 472 | SDKROOT = iphoneos; 473 | SUPPORTED_PLATFORMS = iphoneos; 474 | SWIFT_COMPILATION_MODE = wholemodule; 475 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 476 | TARGETED_DEVICE_FAMILY = "1,2"; 477 | VALIDATE_PRODUCT = YES; 478 | }; 479 | name = Release; 480 | }; 481 | 97C147061CF9000F007C117D /* Debug */ = { 482 | isa = XCBuildConfiguration; 483 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 484 | buildSettings = { 485 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 486 | CLANG_ENABLE_MODULES = YES; 487 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 488 | DEVELOPMENT_TEAM = T684S67N2Y; 489 | ENABLE_BITCODE = NO; 490 | INFOPLIST_FILE = Runner/Info.plist; 491 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 492 | LD_RUNPATH_SEARCH_PATHS = ( 493 | "$(inherited)", 494 | "@executable_path/Frameworks", 495 | ); 496 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 499 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 500 | SWIFT_VERSION = 5.0; 501 | VERSIONING_SYSTEM = "apple-generic"; 502 | }; 503 | name = Debug; 504 | }; 505 | 97C147071CF9000F007C117D /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 508 | buildSettings = { 509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 510 | CLANG_ENABLE_MODULES = YES; 511 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 512 | DEVELOPMENT_TEAM = T684S67N2Y; 513 | ENABLE_BITCODE = NO; 514 | INFOPLIST_FILE = Runner/Info.plist; 515 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 516 | LD_RUNPATH_SEARCH_PATHS = ( 517 | "$(inherited)", 518 | "@executable_path/Frameworks", 519 | ); 520 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 523 | SWIFT_VERSION = 5.0; 524 | VERSIONING_SYSTEM = "apple-generic"; 525 | }; 526 | name = Release; 527 | }; 528 | /* End XCBuildConfiguration section */ 529 | 530 | /* Begin XCConfigurationList section */ 531 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 532 | isa = XCConfigurationList; 533 | buildConfigurations = ( 534 | 97C147031CF9000F007C117D /* Debug */, 535 | 97C147041CF9000F007C117D /* Release */, 536 | 249021D3217E4FDB00AE95B9 /* Profile */, 537 | ); 538 | defaultConfigurationIsVisible = 0; 539 | defaultConfigurationName = Release; 540 | }; 541 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 542 | isa = XCConfigurationList; 543 | buildConfigurations = ( 544 | 97C147061CF9000F007C117D /* Debug */, 545 | 97C147071CF9000F007C117D /* Release */, 546 | 249021D4217E4FDB00AE95B9 /* Profile */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | /* End XCConfigurationList section */ 552 | }; 553 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 554 | } 555 | --------------------------------------------------------------------------------