├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── CamcodePlugin.h │ ├── SwiftCamcodePlugin.swift │ └── CamcodePlugin.m ├── .gitignore └── camcode.podspec ├── android ├── settings.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── example │ │ └── camcode │ │ └── CamcodePlugin.kt ├── .classpath ├── .settings │ └── org.eclipse.buildship.core.prefs ├── build.gradle ├── .project ├── gradlew.bat └── gradlew ├── example ├── android │ ├── settings_aar.gradle │ ├── app │ │ ├── .settings │ │ │ └── org.eclipse.buildship.core.prefs │ │ ├── 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 │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── .classpath │ │ ├── .project │ │ └── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── settings.gradle │ ├── build.gradle │ └── .project ├── 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 ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ ├── js │ │ └── barcode.js │ └── index.html ├── assets │ └── images │ │ ├── barcode.png │ │ └── barcode.svg ├── README.md ├── .gitignore ├── pubspec.yaml ├── lib │ └── main.dart └── pubspec.lock ├── .devcontainer └── devcontainer.json ├── lib ├── dart_ui_stub │ ├── dart_ui_real.dart │ ├── dart_ui.dart │ └── dart_ui_fake.dart ├── barcode.dart ├── barcode_results.dart ├── cam_code_scanner.dart └── camcode_web.dart ├── firebase.json ├── .gitignore ├── .github ├── workflows │ └── web.yml └── dependabot.yml ├── pubspec.yaml ├── CHANGELOG.md ├── LICENSE ├── .vscode └── launch.json ├── analysis_options.yaml ├── README.md ├── pubspec.lock └── test └── barcode_results_test.dart /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'camcode' 2 | -------------------------------------------------------------------------------- /example/android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "cirrusci/flutter", 3 | "forwardPorts": [3000] 4 | } -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/assets/images/barcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/assets/images/barcode.png -------------------------------------------------------------------------------- /example/assets/images/barcode.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/assets/images/barcode.svg -------------------------------------------------------------------------------- /example/android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /ios/Classes/CamcodePlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface CamcodePlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /lib/dart_ui_stub/dart_ui_real.dart: -------------------------------------------------------------------------------- 1 | // stub dart_ui for ui.platformViewRegistry exposition on compile time 2 | export 'dart:ui'; 3 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/dart_ui_stub/dart_ui.dart: -------------------------------------------------------------------------------- 1 | // stub dart_ui for ui.platformViewRegistry exposition on compile time 2 | export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart'; 3 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiotrFLEURY/camcode/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/PiotrFLEURY/camcode/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 6 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "example/build/web", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /lib/dart_ui_stub/dart_ui_fake.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html' as html; 2 | 3 | // stub dart_ui for ui.platformViewRegistry exposition on compile time 4 | // ignore: camel_case_types 5 | class platformViewRegistry { 6 | static void registerViewFactory( 7 | String viewTypeId, html.Element Function(int viewId) viewFactory) {} 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 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | .idea/ 9 | .metadata 10 | .packages 11 | camcode.iml 12 | example/.dart_tool 13 | example/.idea 14 | example/.flutter-plugin 15 | example/.flutter-plugins-dependencies 16 | example/build/ 17 | example/.metadata 18 | example/.packages 19 | example/camcode_example.iml 20 | 21 | .firebase/ 22 | .firebaserc -------------------------------------------------------------------------------- /example/android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /example/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=C\:/Program Files/Java/jdk-13.0.1 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /.github/workflows/web.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | name: Build web 4 | jobs: 5 | build: 6 | name: Build Web 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: subosito/flutter-action@v2 11 | - run: | 12 | flutter pub get 13 | flutter test 14 | flutter format --set-exit-if-changed . 15 | flutter analyze 16 | cd example 17 | flutter build web -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir=../example/android 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=C\:/Program Files/Java/jdk-13.0.1 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pub" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /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 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Classes/SwiftCamcodePlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | public class SwiftCamcodePlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "camcode", binaryMessenger: registrar.messenger()) 7 | let instance = SwiftCamcodePlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | result("iOS " + UIDevice.current.systemVersion) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/Classes/CamcodePlugin.m: -------------------------------------------------------------------------------- 1 | #import "CamcodePlugin.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 "camcode-Swift.h" 9 | #endif 10 | 11 | @implementation CamcodePlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftCamcodePlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # camcode_example 2 | 3 | Demonstrates how to use the camcode plugin. 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/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/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "camcode_example", 3 | "short_name": "camcode_example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "Demonstrates how to use the camcode plugin.", 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 | } -------------------------------------------------------------------------------- /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 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/web/js/barcode.js: -------------------------------------------------------------------------------- 1 | function detectBarcode(dataUrl, callback) { 2 | Quagga.decodeSingle({ 3 | decoder: { 4 | readers: [ 5 | "code_128_reader", 6 | "ean_reader", 7 | "ean_8_reader", 8 | "code_39_reader", 9 | "code_39_vin_reader", 10 | "code_93_reader" 11 | ] // List of active readers 12 | }, 13 | locate: true, // try to locate the barcode in the image 14 | src: dataUrl // or 'data:image/jpg;base64,' + data 15 | }, function (result) { 16 | if (result && result.codeResult) { 17 | console.log("result", result.codeResult.code); 18 | callback(result.codeResult.code); 19 | } else { 20 | console.log("not detected"); 21 | } 22 | }); 23 | } -------------------------------------------------------------------------------- /lib/barcode.dart: -------------------------------------------------------------------------------- 1 | @JS() 2 | library barcode; 3 | 4 | import 'package:js/js.dart'; 5 | 6 | /// Call the barcode the Javascript detection method 7 | /// Parameters: 8 | /// - dataUrl: a valid HTML image data url 9 | /// - callback: the function called on barcode result 10 | /// Requires a Javascript file containing a method called "detectBarcode" with the 2 arguments 11 | /// function detectBarcode(dataUrl, callback) { 12 | /// 13 | /// call here your favorite javascript barcode scan library 14 | /// input must be an image dataUrl 15 | /// output must be a single String 16 | /// 17 | /// callback(barcode); 18 | /// 19 | /// } 20 | @JS('detectBarcode') 21 | external void detectBarcode(String dataUrl, BarcodeDetectionCallback callback); 22 | 23 | /// The method called on barcode result 24 | typedef BarcodeDetectionCallback = void Function(String result); 25 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: camcode 2 | description: A camera barcode scanner for Flutter Web using your favorite Javascript library 3 | version: 3.0.0 4 | repository: https://github.com/PiotrFLEURY/camcode 5 | homepage: https://camcode-59c70.web.app/ 6 | 7 | flutter: 8 | plugin: 9 | platforms: 10 | android: 11 | package: com.example.camcode 12 | pluginClass: CamcodePlugin 13 | ios: 14 | pluginClass: CamcodePlugin 15 | web: 16 | pluginClass: CamcodeWeb 17 | fileName: camcode_web.dart 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | flutter_web_plugins: 23 | sdk: flutter 24 | js: ^0.6.2 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | every_test: ^1.0.0 30 | pedantic: ^1.9.0 31 | 32 | environment: 33 | sdk: ">=2.17.0 <3.0.0" 34 | flutter: ">=1.22.6" -------------------------------------------------------------------------------- /example/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1633097203752 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.example.camcode' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.3.50' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:4.1.0' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | compileSdkVersion 30 29 | 30 | sourceSets { 31 | main.java.srcDirs += 'src/main/kotlin' 32 | } 33 | defaultConfig { 34 | minSdkVersion 16 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 40 | } 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/camcode.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint camcode.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'camcode' 7 | s.version = '0.0.1' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A new flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '8.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | camcode 4 | Project android_ created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 0 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1633177377080 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.0.0 2 | 3 | - Upgrade to Flutter 3 4 | 5 | ## 2.2.1 6 | 7 | - Improve scan performance 8 | 9 | ## 2.2.0 10 | 11 | - Add camera selection option 12 | - Add point of interest 13 | 14 | ## 2.1.0 15 | 16 | - Add releaseResources method 17 | - Improve scan reliability using multiple results instead of one 18 | 19 | ## 2.0.1 20 | 21 | - IOS black screen fixed 22 | - Improve accuracy with better camera resolution 23 | 24 | ## 2.0.0 25 | 26 | - Null safety migration 27 | 28 | ## 1.0.5 29 | 30 | - Fix overflow 31 | 32 | ## 1.0.4 33 | 34 | - Add pedantic file content to analysis_options.yaml 35 | - Fix new discovered analysis errors 36 | 37 | ## 1.0.3 38 | 39 | - Add missing documentation 40 | - Fix analysis errors 41 | - Add dart_ui stub to be compliant with static analysis on compile time 42 | 43 | ## 1.0.2 44 | 45 | - Clean README 46 | - Set correct version of flutter 47 | 48 | ## 1.0.1 49 | 50 | - Fix camera resource release 51 | - Fix pubspec descrition, repository, homepage 52 | - Fix analysis errors 53 | 54 | ## 1.0.0 55 | 56 | - Plugin created 57 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/example/camcode/CamcodePlugin.kt: -------------------------------------------------------------------------------- 1 | package com.example.camcode 2 | 3 | import io.flutter.embedding.engine.plugins.FlutterPlugin 4 | import io.flutter.plugin.common.MethodCall 5 | import io.flutter.plugin.common.MethodChannel 6 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 7 | import io.flutter.plugin.common.MethodChannel.Result 8 | 9 | /** CamcodePlugin */ 10 | class CamcodePlugin : FlutterPlugin, MethodCallHandler { 11 | /// The MethodChannel that will the communication between Flutter and native Android 12 | /// 13 | /// This local reference serves to register the plugin with the Flutter Engine and unregister it 14 | /// when the Flutter Engine is detached from the Activity 15 | private lateinit var channel: MethodChannel 16 | 17 | override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 18 | channel = MethodChannel(flutterPluginBinding.binaryMessenger, "camcode") 19 | channel.setMethodCallHandler(this) 20 | } 21 | 22 | override fun onMethodCall(call: MethodCall, result: Result) { 23 | if (call.method == "getPlatformVersion") { 24 | result.success("Android ${android.os.Build.VERSION.RELEASE}") 25 | } else { 26 | result.notImplemented() 27 | } 28 | } 29 | 30 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 31 | channel.setMethodCallHandler(null) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Piotr FLEURY 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.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 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /.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": "camcode", 9 | "request": "launch", 10 | "type": "dart" 11 | }, 12 | { 13 | "name": "camcode (profile mode)", 14 | "request": "launch", 15 | "type": "dart", 16 | "flutterMode": "profile" 17 | }, 18 | { 19 | "name": "camcode (release mode)", 20 | "request": "launch", 21 | "type": "dart", 22 | "flutterMode": "release" 23 | }, 24 | { 25 | "name": "example (web)", 26 | "cwd": "example", 27 | "request": "launch", 28 | "type": "dart", 29 | "args": [ 30 | "-d", 31 | "chrome", 32 | "--web-port=3000", 33 | "--web-hostname=0.0.0.0", 34 | ] 35 | }, 36 | { 37 | "name": "example (profile mode)", 38 | "cwd": "example", 39 | "request": "launch", 40 | "type": "dart", 41 | "flutterMode": "profile" 42 | }, 43 | { 44 | "name": "example (release mode)", 45 | "cwd": "example", 46 | "request": "launch", 47 | "type": "dart", 48 | "flutterMode": "release" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | linter: 2 | rules: 3 | - always_declare_return_types 4 | - always_require_non_null_named_parameters 5 | - annotate_overrides 6 | - avoid_empty_else 7 | - avoid_init_to_null 8 | - avoid_null_checks_in_equality_operators 9 | - avoid_relative_lib_imports 10 | - avoid_return_types_on_setters 11 | - avoid_shadowing_type_parameters 12 | - avoid_types_as_parameter_names 13 | - camel_case_extensions 14 | - curly_braces_in_flow_control_structures 15 | - empty_catches 16 | - empty_constructor_bodies 17 | - library_names 18 | - library_prefixes 19 | - no_duplicate_case_values 20 | - null_closures 21 | - omit_local_variable_types 22 | - prefer_adjacent_string_concatenation 23 | - prefer_collection_literals 24 | - prefer_conditional_assignment 25 | - prefer_contains 26 | - prefer_equal_for_default_values 27 | - prefer_final_fields 28 | - prefer_for_elements_to_map_fromIterable 29 | - prefer_generic_function_type_aliases 30 | - prefer_if_null_operators 31 | - prefer_is_empty 32 | - prefer_is_not_empty 33 | - prefer_iterable_whereType 34 | - prefer_single_quotes 35 | - prefer_spread_collections 36 | - recursive_getters 37 | - slash_for_doc_comments 38 | - type_init_formals 39 | - unawaited_futures 40 | - unnecessary_const 41 | - unnecessary_new 42 | - unnecessary_null_in_if_null_operators 43 | - unnecessary_this 44 | - unrelated_type_equality_checks 45 | - use_function_type_syntax_for_parameters 46 | - use_rethrow_when_possible 47 | - valid_regexps -------------------------------------------------------------------------------- /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 | camcode_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 | -------------------------------------------------------------------------------- /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.camcode_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 | -------------------------------------------------------------------------------- /lib/barcode_results.dart: -------------------------------------------------------------------------------- 1 | /// Store and count every potential result 2 | /// Once a barcode was identified minimalResultCount times, it is considered as a valid result 3 | class BarcodeResults { 4 | /// Set to true if you want to get the first scanned value 5 | /// with no concordance check 6 | bool singleShot; 7 | 8 | /// Number of identic scanned value to get before consider getting result 9 | int minimalResultCount; 10 | 11 | /// list of barcode results 12 | final Map _barcodeResults = {}; 13 | 14 | BarcodeResults({ 15 | this.singleShot = false, 16 | this.minimalResultCount = 2, 17 | }); 18 | 19 | /// clears all barcode results 20 | void clear() { 21 | _barcodeResults.clear(); 22 | } 23 | 24 | /// return the actual barcode results count 25 | int get resultCount => _barcodeResults.values.reduce((a, b) => a + b); 26 | 27 | /// Consider that we have a barcode result once enough identic results are found 28 | bool get gotResult => _containsSingleShotResult || _containesConcordance; 29 | 30 | /// return true if singleShot mode is enabled and resultCount is positive 31 | bool get _containsSingleShotResult => singleShot && resultCount > 0; 32 | 33 | /// return true if results contains at least minimalResultCount 34 | /// of the same barcode 35 | bool get _containesConcordance => 36 | resultCount >= 2 && 37 | _barcodeResults.values.any( 38 | (singleBarcodeCount) => singleBarcodeCount >= minimalResultCount, 39 | ); 40 | 41 | /// adds a new barcode result 42 | void add(String barcode) { 43 | final _currentBarcodeCount = _barcodeResults[barcode] ?? 0; 44 | _barcodeResults[barcode] = _currentBarcodeCount + 1; 45 | } 46 | 47 | /// returns the count of a barcode 48 | int countOf(String barcode) => _barcodeResults[barcode] ?? 0; 49 | 50 | /// returns the barcode with the most results 51 | String get mostFrequentBarcode => _barcodeResults.keys.reduce( 52 | (a, b) => countOf(a) > countOf(b) ? a : b, 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # camcode 2 | 3 | A camera barcode scan library for Flutter Web 4 | 5 | ![Web build status](https://github.com/PiotrFLEURY/camcode/actions/workflows/web.yml/badge.svg) 6 | 7 | # Getting Started 8 | 9 | ## Add a javascript file for barcode scan 10 | 11 | ``` 12 | function detectBarcode(dataUrl, callback) { 13 | 14 | // call here your favorite javascript barcode scan library 15 | // input must be an image dataUrl 16 | // output must be a single String 17 | 18 | // don't forget to trigger the call back in order to get the result 19 | callback(barcode); 20 | } 21 | ``` 22 | 23 | ## Import javascript files into your index.html 24 | 25 | ``` 26 | 27 | // the javascript file with the detectBarcode function 28 | ``` 29 | 30 | ## Use it 31 | 32 | ``` 33 | import 'package:camcode/cam_code_scanner.dart'; 34 | 35 | showDialog( 36 | context: context, 37 | builder: (context) => CamCodeScanner( 38 | width: MediaQuery.of(context).size.width, 39 | height: MediaQuery.of(context).size.height, 40 | refreshDelayMillis: 200, 41 | onBarcodeResult: (barcode) { 42 | // do whatever you want 43 | }, 44 | minimalResultCount: 2, 45 | ), 46 | ); 47 | ``` 48 | 49 | # More options 50 | 51 | ## Manually release resources 52 | 53 | Sometimes, depending on your camcode usage, you may need to release resources manually. 54 | 55 | 1- To do so, create first a controller for the scanner 56 | 57 | ```dart 58 | // Create a controller to send instructions to scanner 59 | final CamCodeScannerController _controller = CamCodeScannerController(); 60 | ``` 61 | 62 | 2- Then, add it to the `CamCodeScanner` 63 | 64 | ```dart 65 | CamCodeScanner( 66 | width: ..., 67 | height: ..., 68 | refreshDelayMillis: ..., 69 | onBarcodeResult: (barcode) { 70 | ... 71 | }, 72 | controller: _controller, 73 | ), 74 | ``` 75 | 76 | 3- And finally, just call `releaseResources()` method when required 77 | 78 | ```dart 79 | ElevatedButton( 80 | onPressed: () { 81 | _controller.releaseResources(); 82 | }, 83 | child: Text('Release resources'), 84 | ), 85 | ``` 86 | 87 | > Calling this method will close the camera and stop the scanner process 88 | -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | camcode_example 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /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/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: camcode_example 2 | description: Demonstrates how to use the camcode plugin. 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 | environment: 9 | sdk: ">=2.17.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | camcode: 16 | # When depending on this package from a real application you should use: 17 | # camcode: ^x.y.z 18 | # See https://dart.dev/tools/pub/dependencies#version-constraints 19 | # The example app is bundled with the plugin so we use a path dependency on 20 | # the parent directory to use the current plugin's version. 21 | path: ../ 22 | 23 | # The following adds the Cupertino Icons font to your application. 24 | # Use with the CupertinoIcons class for iOS style icons. 25 | cupertino_icons: ^1.0.2 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | # For information on the generic Dart part of this file, see the 32 | # following page: https://dart.dev/tools/pub/pubspec 33 | 34 | # The following section is specific to Flutter. 35 | flutter: 36 | 37 | # The following line ensures that the Material Icons font is 38 | # included with your application, so that you can use the icons in 39 | # the material Icons class. 40 | uses-material-design: true 41 | 42 | # To add assets to your application, add an assets section, like this: 43 | assets: 44 | - assets/images/ 45 | # - images/a_dot_ham.jpeg 46 | 47 | # An image asset can refer to one or more resolution-specific "variants", see 48 | # https://flutter.dev/assets-and-images/#resolution-aware. 49 | 50 | # For details regarding adding assets from package dependencies, see 51 | # https://flutter.dev/assets-and-images/#from-packages 52 | 53 | # To add custom fonts to your application, add a fonts section here, 54 | # in this "flutter" section. Each entry in this list should have a 55 | # "family" key with the font family name, and a "fonts" key with a 56 | # list giving the asset and other descriptors for the font. For 57 | # example: 58 | # fonts: 59 | # - family: Schyler 60 | # fonts: 61 | # - asset: fonts/Schyler-Regular.ttf 62 | # - asset: fonts/Schyler-Italic.ttf 63 | # style: italic 64 | # - family: Trajan Pro 65 | # fonts: 66 | # - asset: fonts/TrajanPro.ttf 67 | # - asset: fonts/TrajanPro_Bold.ttf 68 | # weight: 700 69 | # 70 | # For details regarding fonts from package dependencies, 71 | # see https://flutter.dev/custom-fonts/#from-packages 72 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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.9.0" 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.2.1" 25 | clock: 26 | dependency: transitive 27 | description: 28 | name: clock 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.1" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.16.0" 39 | every_test: 40 | dependency: "direct dev" 41 | description: 42 | name: every_test 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.0.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.3.1" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | flutter_web_plugins: 64 | dependency: "direct main" 65 | description: flutter 66 | source: sdk 67 | version: "0.0.0" 68 | js: 69 | dependency: "direct main" 70 | description: 71 | name: js 72 | url: "https://pub.dartlang.org" 73 | source: hosted 74 | version: "0.6.4" 75 | matcher: 76 | dependency: transitive 77 | description: 78 | name: matcher 79 | url: "https://pub.dartlang.org" 80 | source: hosted 81 | version: "0.12.12" 82 | material_color_utilities: 83 | dependency: transitive 84 | description: 85 | name: material_color_utilities 86 | url: "https://pub.dartlang.org" 87 | source: hosted 88 | version: "0.1.5" 89 | meta: 90 | dependency: transitive 91 | description: 92 | name: meta 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "1.8.0" 96 | path: 97 | dependency: transitive 98 | description: 99 | name: path 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.8.2" 103 | pedantic: 104 | dependency: "direct dev" 105 | description: 106 | name: pedantic 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.11.1" 110 | sky_engine: 111 | dependency: transitive 112 | description: flutter 113 | source: sdk 114 | version: "0.0.99" 115 | source_span: 116 | dependency: transitive 117 | description: 118 | name: source_span 119 | url: "https://pub.dartlang.org" 120 | source: hosted 121 | version: "1.9.0" 122 | stack_trace: 123 | dependency: transitive 124 | description: 125 | name: stack_trace 126 | url: "https://pub.dartlang.org" 127 | source: hosted 128 | version: "1.10.0" 129 | stream_channel: 130 | dependency: transitive 131 | description: 132 | name: stream_channel 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "2.1.0" 136 | string_scanner: 137 | dependency: transitive 138 | description: 139 | name: string_scanner 140 | url: "https://pub.dartlang.org" 141 | source: hosted 142 | version: "1.1.1" 143 | term_glyph: 144 | dependency: transitive 145 | description: 146 | name: term_glyph 147 | url: "https://pub.dartlang.org" 148 | source: hosted 149 | version: "1.2.1" 150 | test_api: 151 | dependency: transitive 152 | description: 153 | name: test_api 154 | url: "https://pub.dartlang.org" 155 | source: hosted 156 | version: "0.4.12" 157 | vector_math: 158 | dependency: transitive 159 | description: 160 | name: vector_math 161 | url: "https://pub.dartlang.org" 162 | source: hosted 163 | version: "2.1.2" 164 | sdks: 165 | dart: ">=2.17.0 <3.0.0" 166 | flutter: ">=1.22.6" 167 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:camcode/cam_code_scanner.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp( 6 | MaterialApp( 7 | routes: { 8 | '/': (context) => MyApp(), 9 | }, 10 | initialRoute: '/', 11 | ), 12 | ); 13 | } 14 | 15 | class MyApp extends StatefulWidget { 16 | @override 17 | _MyAppState createState() => _MyAppState(); 18 | } 19 | 20 | class _MyAppState extends State { 21 | String barcodeValue = 'Press button to scan a barcode'; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return MaterialApp( 26 | home: Scaffold( 27 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 28 | floatingActionButton: FloatingActionButton( 29 | child: Icon(Icons.scanner), 30 | onPressed: () => openScanner(context, _onResult), 31 | ), 32 | appBar: AppBar( 33 | title: const Text('CamCode example app'), 34 | ), 35 | body: Center( 36 | child: Text(barcodeValue), 37 | ), 38 | ), 39 | ); 40 | } 41 | 42 | void _onResult(String result) { 43 | setState(() { 44 | barcodeValue = result; 45 | }); 46 | } 47 | 48 | void openScanner(BuildContext context, Function(String) onResult) { 49 | showDialog( 50 | context: context, 51 | builder: (context) => CamCodeScannerPage(_onResult), 52 | ); 53 | } 54 | } 55 | 56 | class CamCodeScannerPage extends StatefulWidget { 57 | final Function(String) onResult; 58 | 59 | CamCodeScannerPage(this.onResult); 60 | 61 | @override 62 | _CamCodeScannerPageState createState() => _CamCodeScannerPageState(); 63 | } 64 | 65 | class _CamCodeScannerPageState extends State { 66 | /// Create a controller to send instructions to scanner 67 | final CamCodeScannerController _controller = CamCodeScannerController(); 68 | 69 | /// List of availables cameras 70 | final List cameraNames = []; 71 | 72 | /// currently selected camera 73 | late String _selectedCamera; 74 | 75 | @override 76 | void initState() { 77 | super.initState(); 78 | _fetchDeviceList(); 79 | } 80 | 81 | void _fetchDeviceList() async { 82 | /// Get list of available cameras 83 | final cameras = await _controller.fetchDeviceList(); 84 | setState(() { 85 | cameraNames.addAll(cameras); 86 | _selectedCamera = cameras.first; 87 | }); 88 | } 89 | 90 | @override 91 | Widget build(BuildContext context) { 92 | return Scaffold( 93 | body: Stack( 94 | children: [ 95 | CamCodeScanner( 96 | width: MediaQuery.of(context).size.width, 97 | height: MediaQuery.of(context).size.height, 98 | refreshDelayMillis: 16, 99 | onBarcodeResult: (barcode) { 100 | Navigator.of(context).pop(); 101 | widget.onResult(barcode); 102 | }, 103 | controller: _controller, 104 | showDebugFrames: false, 105 | minimalResultCount: 1, 106 | ), 107 | Positioned( 108 | bottom: 48.0, 109 | left: 48.0, 110 | child: Row( 111 | children: [ 112 | ElevatedButton( 113 | onPressed: () { 114 | _controller.releaseResources(); 115 | }, 116 | child: Text('Release resources'), 117 | ), 118 | cameraNames.isEmpty 119 | ? Container() 120 | : DropdownButton( 121 | items: cameraNames 122 | .map( 123 | (name) => DropdownMenuItem( 124 | child: Text(name), 125 | value: name, 126 | ), 127 | ) 128 | .toList(), 129 | onChanged: (String? value) { 130 | if (value != null) { 131 | _controller.selectDevice(value); 132 | setState(() { 133 | _selectedCamera = value; 134 | }); 135 | } 136 | }, 137 | value: _selectedCamera, 138 | ), 139 | ], 140 | ), 141 | ), 142 | ], 143 | ), 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /test/barcode_results_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:camcode/barcode_results.dart'; 2 | import 'package:every_test/every_test.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | 5 | void main() { 6 | group( 7 | 'result count', 8 | () { 9 | test( 10 | 'should get result if got 3 times the same', 11 | () { 12 | // GIVEN 13 | final barcodeResults = BarcodeResults(); 14 | barcodeResults.add('123456789'); 15 | barcodeResults.add('123456789'); 16 | barcodeResults.add('123456789'); 17 | 18 | // WHEN 19 | final gotResult = barcodeResults.gotResult; 20 | 21 | // THEN 22 | expect(gotResult, true); 23 | }, 24 | ); 25 | 26 | test( 27 | 'should get result if got 3 same results in a list of random results', 28 | () { 29 | // GIVEN 30 | final barcodeResults = BarcodeResults(); 31 | barcodeResults.add('123456789'); 32 | barcodeResults.add('987654321'); 33 | barcodeResults.add('123456789'); 34 | barcodeResults.add('987654321'); 35 | barcodeResults.add('123456789'); 36 | 37 | // WHEN 38 | final gotResult = barcodeResults.gotResult; 39 | 40 | // THEN 41 | expect(gotResult, true); 42 | }, 43 | ); 44 | test( 45 | 'should not get result if got 3 different barcodes', 46 | () { 47 | // GIVEN 48 | final barcodeResults = BarcodeResults(); 49 | barcodeResults.add('123'); 50 | barcodeResults.add('456'); 51 | barcodeResults.add('789'); 52 | 53 | // WHEN 54 | final gotResult = barcodeResults.gotResult; 55 | 56 | // THEN 57 | expect(gotResult, false); 58 | }, 59 | ); 60 | }, 61 | ); 62 | group('mostFequent', () { 63 | test('most frequent barcode', () { 64 | // GIVEN 65 | final barcodeResults = BarcodeResults(); 66 | barcodeResults.add('123456789'); 67 | barcodeResults.add('987654321'); 68 | barcodeResults.add('123456789'); 69 | barcodeResults.add('987654321'); 70 | barcodeResults.add('123456789'); 71 | 72 | // WHEN 73 | final mostFrequent = barcodeResults.mostFrequentBarcode; 74 | 75 | // THEN 76 | expect(mostFrequent, '123456789'); 77 | }); 78 | }); 79 | 80 | group('singleShot', () { 81 | test('singleShot enabled', () { 82 | // GIVEN 83 | final barcodeResults = BarcodeResults(singleShot: true); 84 | barcodeResults.add('42424242'); 85 | 86 | // WHEN 87 | final gotResult = barcodeResults.gotResult; 88 | 89 | // THEN 90 | expect(gotResult, true); 91 | }); 92 | 93 | test('singleShot disabled', () { 94 | // GIVEN 95 | final barcodeResults = BarcodeResults(singleShot: false); 96 | barcodeResults.add('42424242'); 97 | 98 | // WHEN 99 | final gotResult = barcodeResults.gotResult; 100 | 101 | // THEN 102 | expect(gotResult, false); 103 | }); 104 | 105 | test('singleShot default', () { 106 | // GIVEN 107 | final barcodeResults = BarcodeResults(); 108 | barcodeResults.add('42424242'); 109 | 110 | // WHEN 111 | final gotResult = barcodeResults.gotResult; 112 | 113 | // THEN 114 | expect(gotResult, false); 115 | }); 116 | }); 117 | 118 | everyTest( 119 | 'minimalResultCount', 120 | of: (params) { 121 | // GIVEN 122 | final _minimalResulCount = params['minimalResultCount'] as int; 123 | final List barcodes = params['barcodes']; 124 | final barcodeResults = 125 | BarcodeResults(minimalResultCount: _minimalResulCount); 126 | barcodes.forEach((it) { 127 | barcodeResults.add(it); 128 | }); 129 | 130 | // WHEN 131 | return barcodeResults.gotResult; 132 | }, 133 | expects: [ 134 | // THEN 135 | param({ 136 | 'minimalResultCount': 1, 137 | 'barcodes': ['123456'] 138 | }).gives(false), 139 | param({ 140 | 'minimalResultCount': 2, 141 | 'barcodes': ['123456', '123456'] 142 | }).gives(true), 143 | param({ 144 | 'minimalResultCount': 2, 145 | 'barcodes': ['123456', '123456', '123456'] 146 | }).gives(true), 147 | param({ 148 | 'minimalResultCount': 2, 149 | 'barcodes': ['123456'] 150 | }).gives(false), 151 | param({ 152 | 'minimalResultCount': 4, 153 | 'barcodes': ['123456', '123456', '123456'] 154 | }).gives(false), 155 | ], 156 | ); 157 | } 158 | -------------------------------------------------------------------------------- /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.8.2" 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 | camcode: 19 | dependency: "direct main" 20 | description: 21 | path: ".." 22 | relative: true 23 | source: path 24 | version: "3.0.0" 25 | characters: 26 | dependency: transitive 27 | description: 28 | name: characters 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.3.1" 39 | clock: 40 | dependency: transitive 41 | description: 42 | name: clock 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0" 46 | collection: 47 | dependency: transitive 48 | description: 49 | name: collection 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.16.0" 53 | cupertino_icons: 54 | dependency: "direct main" 55 | description: 56 | name: cupertino_icons 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.0.2" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.3.0" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | flutter_web_plugins: 78 | dependency: transitive 79 | description: flutter 80 | source: sdk 81 | version: "0.0.0" 82 | js: 83 | dependency: transitive 84 | description: 85 | name: js 86 | url: "https://pub.dartlang.org" 87 | source: hosted 88 | version: "0.6.4" 89 | matcher: 90 | dependency: transitive 91 | description: 92 | name: matcher 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "0.12.11" 96 | material_color_utilities: 97 | dependency: transitive 98 | description: 99 | name: material_color_utilities 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "0.1.4" 103 | meta: 104 | dependency: transitive 105 | description: 106 | name: meta 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.7.0" 110 | path: 111 | dependency: transitive 112 | description: 113 | name: path 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.8.1" 117 | sky_engine: 118 | dependency: transitive 119 | description: flutter 120 | source: sdk 121 | version: "0.0.99" 122 | source_span: 123 | dependency: transitive 124 | description: 125 | name: source_span 126 | url: "https://pub.dartlang.org" 127 | source: hosted 128 | version: "1.8.2" 129 | stack_trace: 130 | dependency: transitive 131 | description: 132 | name: stack_trace 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "1.10.0" 136 | stream_channel: 137 | dependency: transitive 138 | description: 139 | name: stream_channel 140 | url: "https://pub.dartlang.org" 141 | source: hosted 142 | version: "2.1.0" 143 | string_scanner: 144 | dependency: transitive 145 | description: 146 | name: string_scanner 147 | url: "https://pub.dartlang.org" 148 | source: hosted 149 | version: "1.1.0" 150 | term_glyph: 151 | dependency: transitive 152 | description: 153 | name: term_glyph 154 | url: "https://pub.dartlang.org" 155 | source: hosted 156 | version: "1.2.0" 157 | test_api: 158 | dependency: transitive 159 | description: 160 | name: test_api 161 | url: "https://pub.dartlang.org" 162 | source: hosted 163 | version: "0.4.9" 164 | vector_math: 165 | dependency: transitive 166 | description: 167 | name: vector_math 168 | url: "https://pub.dartlang.org" 169 | source: hosted 170 | version: "2.1.2" 171 | sdks: 172 | dart: ">=2.17.0 <3.0.0" 173 | flutter: ">=1.22.6" 174 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /lib/cam_code_scanner.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | /// Camera barcode scanner widget 6 | /// Asks for camera access permission 7 | /// Shows camera images stream 8 | /// Captures pictures every 'refreshDelayMillis' 9 | /// Ask your favorite javascript library 10 | /// to identify a barcode in the current picture 11 | class CamCodeScanner extends StatefulWidget { 12 | /// shows the current analysing picture 13 | final bool showDebugFrames; 14 | 15 | /// call back to trigger on barcode result 16 | final Function onBarcodeResult; 17 | 18 | /// width dimension 19 | final double width; 20 | 21 | /// height dimension 22 | final double height; 23 | 24 | /// delay between to picture analysis 25 | final int refreshDelayMillis; 26 | 27 | /// controller to control the camera from outside 28 | final CamCodeScannerController? controller; 29 | 30 | /// The color of the background mask 31 | final Color backgroundColor; 32 | 33 | /// shows the current analysing picture 34 | final bool showScannerLine; 35 | 36 | /// Number of identic scanned value to get before consider getting result 37 | final int minimalResultCount; 38 | 39 | /// Camera barcode scanner widget 40 | /// Params: 41 | /// * showDebugFrames [true|false] - shows the current analysing picture 42 | /// * onBarcodeResult - call back to trigger on barcode result 43 | /// * width, height - dimensions 44 | /// * refreshDelayMillis - delay between to picture analysis 45 | CamCodeScanner({ 46 | this.showDebugFrames = false, 47 | required this.onBarcodeResult, 48 | required this.width, 49 | required this.height, 50 | this.refreshDelayMillis = 1000, 51 | this.controller, 52 | this.backgroundColor = Colors.black54, 53 | this.showScannerLine = true, 54 | this.minimalResultCount = 2, 55 | }); 56 | 57 | @override 58 | _CamCodeScannerState createState() => _CamCodeScannerState(); 59 | } 60 | 61 | class _CamCodeScannerState extends State { 62 | /// communication channel between widget and platform code 63 | final MethodChannel channel = MethodChannel('camcode'); 64 | 65 | /// Webcam widget to insert into the tree 66 | late Widget _webcamWidget; 67 | 68 | /// Debug frame Image widget to insert into the tree 69 | late Widget _imageWidget; 70 | 71 | /// The barcode result 72 | String barcode = ''; 73 | 74 | /// Used to know if camera is loading or initialized 75 | bool initialized = false; 76 | 77 | @override 78 | void initState() { 79 | super.initState(); 80 | 81 | initialize(); 82 | } 83 | 84 | @override 85 | void dispose() { 86 | channel.invokeMethod( 87 | 'releaseResources', 88 | ); 89 | super.dispose(); 90 | } 91 | 92 | /// Calls the platform initialization and wait for result 93 | Future initialize() async { 94 | final time = await channel.invokeMethod( 95 | 'initialize', 96 | [ 97 | widget.width, 98 | widget.height, 99 | widget.refreshDelayMillis, 100 | widget.minimalResultCount, 101 | ], 102 | ); 103 | 104 | // Create video widget 105 | _webcamWidget = HtmlElementView( 106 | key: UniqueKey(), 107 | viewType: 'webcamVideoElement$time', 108 | ); 109 | 110 | _imageWidget = HtmlElementView( 111 | viewType: 'imageElement', 112 | ); 113 | 114 | // Set the initialized flag 115 | setState(() { 116 | initialized = true; 117 | }); 118 | 119 | _waitForResult(); 120 | widget.controller?._channelCompleter.complete(channel); 121 | } 122 | 123 | /// Waits for the platform completer result 124 | void _waitForResult() { 125 | channel.invokeMethod('fetchResult').then((barcode) { 126 | if (barcode != null) { 127 | onBarcodeResult(barcode); 128 | } 129 | }); 130 | } 131 | 132 | /// Method called when a barcode is detected 133 | Future onBarcodeResult(String _barcode) async { 134 | setState(() { 135 | barcode = _barcode; 136 | }); 137 | widget.onBarcodeResult(barcode); 138 | } 139 | 140 | @override 141 | Widget build(BuildContext context) { 142 | return Scaffold( 143 | body: WillPopScope( 144 | onWillPop: () async { 145 | await channel.invokeMethod('releaseResources'); 146 | return true; 147 | }, 148 | child: Builder( 149 | builder: (context) => Center( 150 | child: initialized 151 | ? Stack( 152 | children: [ 153 | SizedBox( 154 | width: widget.width, 155 | height: widget.height, 156 | child: _webcamWidget, 157 | ), 158 | Container( 159 | width: widget.width, 160 | height: (widget.height / 2) - (widget.height / 8), 161 | color: widget.backgroundColor, 162 | child: Text(''), 163 | ), 164 | Positioned( 165 | top: (widget.height / 2) + (widget.height / 8), 166 | left: 0, 167 | child: Container( 168 | width: widget.width, 169 | height: (widget.height / 2) - (widget.height / 8), 170 | color: widget.backgroundColor, 171 | child: Text(''), 172 | ), 173 | ), 174 | if (widget.showDebugFrames) 175 | Positioned( 176 | top: widget.height * .4, 177 | left: 0, 178 | child: SizedBox( 179 | width: widget.width, 180 | height: widget.height * .2, 181 | child: _imageWidget, 182 | ), 183 | ), 184 | if (widget.showScannerLine) 185 | Center( 186 | child: CustomPaint( 187 | size: Size( 188 | widget.width, 189 | widget.height * .2, 190 | ), 191 | painter: ScannerLine( 192 | color: Colors.red, 193 | ), 194 | ), 195 | ), 196 | Align( 197 | alignment: Alignment.bottomCenter, 198 | child: Padding( 199 | padding: const EdgeInsets.all(8.0), 200 | child: Text(barcode), 201 | ), 202 | ), 203 | ], 204 | ) 205 | : CircularProgressIndicator(), 206 | ), 207 | ), 208 | ), 209 | ); 210 | } 211 | } 212 | 213 | /// Custom painter to draw the scanner line 214 | class ScannerLine extends CustomPainter { 215 | /// Color of the line 216 | final Color color; 217 | 218 | ScannerLine({ 219 | this.color = Colors.white, 220 | }); 221 | 222 | @override 223 | void paint(Canvas canvas, Size size) { 224 | final paint = Paint() 225 | ..color = color 226 | ..strokeWidth = 1.0 227 | ..style = PaintingStyle.stroke; 228 | 229 | canvas.drawLine( 230 | Offset(0, size.height / 2), 231 | Offset(size.width, size.height / 2), 232 | paint, 233 | ); 234 | } 235 | 236 | @override 237 | bool shouldRepaint(CustomPainter oldDelegate) { 238 | return true; 239 | } 240 | } 241 | 242 | /// Controller to control the camera from outside 243 | class CamCodeScannerController { 244 | /// Channel to communicate with the platform code 245 | final Completer _channelCompleter = Completer(); 246 | 247 | /// Invoke this method to close the camera and release all resources 248 | Future releaseResources() async { 249 | final _channel = await _channelCompleter.future; 250 | return _channel.invokeMethod( 251 | 'releaseResources', 252 | ); 253 | } 254 | 255 | /// Waits for the device list completer result 256 | Future> fetchDeviceList() async { 257 | final _channel = await _channelCompleter.future; 258 | final devices = 259 | await _channel.invokeMethod?>('fetchDeviceList'); 260 | return devices?.map((e) => e.toString()).toList() ?? []; 261 | } 262 | 263 | /// Selects the device with the given device name 264 | Future selectDevice(String device) async { 265 | final _channel = await _channelCompleter.future; 266 | return _channel.invokeMethod( 267 | 'selectDevice', 268 | device, 269 | ); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /lib/camcode_web.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// In order to *not* need this ignore, consider extracting the "web" version 4 | /// of your plugin as a separate package, instead of inlining it in the same 5 | /// package as the core of your plugin. 6 | /// ignore: avoid_web_libraries_in_flutter 7 | import 'dart:html'; 8 | import 'dart:js'; 9 | import 'package:camcode/barcode_results.dart'; 10 | import 'package:camcode/dart_ui_stub/dart_ui.dart' as ui; 11 | 12 | import 'package:camcode/barcode.dart'; 13 | import 'package:flutter/material.dart'; 14 | import 'package:flutter/services.dart'; 15 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 16 | 17 | /// A web implementation of the Camcode plugin. 18 | class CamcodeWeb { 19 | /// VideoElement used to display the camera image 20 | late VideoElement _webcamVideoElement; 21 | 22 | /// ImageElement used to display taken pictures 23 | late ImageElement imageElement; 24 | 25 | /// timer shceduling the pictures treatment process 26 | late Timer _timer; 27 | 28 | /// used to transmit result to the Widget via MethodChannel 29 | late Completer completer; 30 | 31 | /// bacode results container 32 | final BarcodeResults _barcodeResults = BarcodeResults(); 33 | 34 | /// Canvas element used to draw the barcode result 35 | late CanvasElement _canvasElement; 36 | 37 | /// list of every cameras 38 | final Map _cameraDevices = {}; 39 | 40 | /// ID of the selected device 41 | String? _selectedDeviceId; 42 | 43 | /// Completer to get enumerateDevices result 44 | late Completer> _enumerateDevicesCompleter; 45 | 46 | int frameSize = 1; 47 | int counter = 0; 48 | int maxAttempt = 4; 49 | 50 | /// Registering method 51 | static void registerWith(Registrar registrar) { 52 | final channel = MethodChannel( 53 | 'camcode', 54 | const StandardMethodCodec(), 55 | // ignore: unnecessary_cast 56 | registrar as BinaryMessenger, 57 | ); 58 | 59 | final pluginInstance = CamcodeWeb(); 60 | channel.setMethodCallHandler(pluginInstance.handleMethodCall); 61 | } 62 | 63 | /// handle channel calls 64 | Future handleMethodCall(MethodCall call) async { 65 | switch (call.method) { 66 | case 'initialize': 67 | final List arguments = call.arguments; 68 | return initialize( 69 | arguments[0], 70 | arguments[1], 71 | arguments[2], 72 | arguments[3], 73 | ); 74 | case 'releaseResources': 75 | return releaseResources(); 76 | case 'fetchResult': 77 | return fetchResult(); 78 | case 'fetchDeviceList': 79 | return fetchDevices(); 80 | case 'selectDevice': 81 | return _selectDevice(call.arguments); 82 | default: 83 | throw PlatformException( 84 | code: 'Unimplemented', 85 | details: 'camcode for web doesn\'t implement \'${call.method}\'', 86 | ); 87 | } 88 | } 89 | 90 | /// wait for the result to be completed 91 | Future fetchResult() { 92 | return completer.future; 93 | } 94 | 95 | /// wait for the list of devices to be completed 96 | Future> fetchDevices() { 97 | _enumerateVideoDevices(); 98 | return _enumerateDevicesCompleter.future; 99 | } 100 | 101 | /// Initialize the scanner : 102 | /// - request user permission 103 | /// - request camera stream 104 | /// - initialize video 105 | /// - start video streaming 106 | /// - start picture snapshot timer scheduling 107 | int initialize( 108 | double width, 109 | double height, 110 | int refreshDelayMillis, 111 | int minimalResultCount, 112 | ) { 113 | completer = Completer(); 114 | _enumerateDevicesCompleter = Completer>(); 115 | _barcodeResults.singleShot = minimalResultCount == 1; 116 | _barcodeResults.minimalResultCount = minimalResultCount; 117 | _barcodeResults.clear(); 118 | 119 | // Create a video element which will be provided with stream source 120 | _webcamVideoElement = VideoElement() 121 | ..width = 1920 122 | ..height = 1080 123 | ..style.width = '100%' 124 | ..style.height = '100%' 125 | ..style.objectFit = 'contain' 126 | ..autoplay = true 127 | ..muted = true; 128 | _webcamVideoElement.setAttribute('playsinline', 'true'); 129 | 130 | imageElement = ImageElement() 131 | ..width = 1920 132 | ..height = 1080 133 | ..style.width = '100%' 134 | ..style.height = '100%'; 135 | 136 | _canvasElement = CanvasElement( 137 | width: 1920, 138 | height: 1080, 139 | ); 140 | 141 | final time = DateTime.now().microsecondsSinceEpoch; 142 | 143 | // ignore: undefined_prefixed_name 144 | ui.platformViewRegistry.registerViewFactory( 145 | 'webcamVideoElement$time', 146 | (int viewId) => _webcamVideoElement, 147 | ); 148 | // ignore: undefined_prefixed_name 149 | ui.platformViewRegistry.registerViewFactory( 150 | 'imageElement', 151 | (int viewId) => imageElement, 152 | ); 153 | 154 | // Access the webcam stream 155 | _setupMediaStream(width, height); 156 | 157 | Future.delayed(Duration(seconds: 1), () { 158 | _scan(refreshDelayMillis); 159 | }); 160 | 161 | return time; 162 | } 163 | 164 | /// Fetch media device stream and affect it to the video element 165 | void _setupMediaStream(double width, double height) { 166 | if (window.location.protocol.contains('https')) { 167 | var options = _configureOptions(width, height); 168 | window.navigator.mediaDevices 169 | ?.getUserMedia(options) 170 | .then((MediaStream stream) { 171 | _webcamVideoElement.srcObject = stream; 172 | }); 173 | } else { 174 | window.navigator.getUserMedia(video: true).then((MediaStream stream) { 175 | _webcamVideoElement.srcObject = stream; 176 | }); 177 | } 178 | } 179 | 180 | /// configure constraint options to fetch media device stream 181 | dynamic _configureOptions(double width, double height) { 182 | var options; 183 | if (window.navigator.userAgent.contains('Mobi')) { 184 | options = { 185 | 'audio': false, 186 | 'video': { 187 | 'deviceId': 188 | _selectedDeviceId != null ? {'exact': _selectedDeviceId} : null, 189 | 'facingMode': {'exact': 'environment'}, 190 | } 191 | }; 192 | } else { 193 | options = { 194 | 'audio': false, 195 | 'video': { 196 | 'deviceId': 197 | _selectedDeviceId != null ? {'exact': _selectedDeviceId} : null, 198 | } 199 | }; 200 | } 201 | return options; 202 | } 203 | 204 | /// Selects a device with the given label 205 | void _selectDevice(String? deviceLabel) { 206 | _selectedDeviceId = _cameraDevices[deviceLabel]; 207 | _setupMediaStream( 208 | _webcamVideoElement.width.toDouble(), 209 | _webcamVideoElement.height.toDouble(), 210 | ); 211 | } 212 | 213 | /// Enumerate all video devices 214 | void _enumerateVideoDevices() { 215 | window.navigator.mediaDevices?.enumerateDevices().then((devices) { 216 | for (final device in devices) { 217 | if (device.kind == 'videoinput') { 218 | _cameraDevices[device.label] = device.deviceId; 219 | } 220 | } 221 | _enumerateDevicesCompleter.complete(_cameraDevices.keys.toList()); 222 | }); 223 | } 224 | 225 | /// Scan loop 226 | Future _scan(int refreshDelayMillis) async { 227 | counter = 0; 228 | _timer = Timer.periodic( 229 | Duration( 230 | milliseconds: refreshDelayMillis, 231 | ), 232 | (timer) { 233 | _takePicture(); 234 | }, 235 | ); 236 | } 237 | 238 | /// Takes a picture of the current camera image 239 | /// and process it for barcode identification 240 | Future _takePicture() async { 241 | final context = _canvasElement.context2D; 242 | // context.filter = 'grayscale(1)'; 243 | 244 | switch (frameSize) { 245 | case 1: 246 | context.drawImageScaledFromSource( 247 | _webcamVideoElement, 248 | _webcamVideoElement.videoWidth * .2, 249 | _webcamVideoElement.videoHeight * .4, 250 | _webcamVideoElement.videoWidth * .6, 251 | _webcamVideoElement.videoHeight * .2, 252 | 0, 253 | 0, 254 | _webcamVideoElement.width, 255 | _webcamVideoElement.height, 256 | ); 257 | break; 258 | default: 259 | context.drawImageScaledFromSource( 260 | _webcamVideoElement, 261 | 0, 262 | _webcamVideoElement.videoHeight * .4, 263 | _webcamVideoElement.videoWidth, 264 | _webcamVideoElement.videoHeight * .2, 265 | 0, 266 | 0, 267 | _webcamVideoElement.width, 268 | _webcamVideoElement.height, 269 | ); 270 | break; 271 | } 272 | 273 | debugPrint( 274 | 'Webcam taille : ${_webcamVideoElement.height} & ${_webcamVideoElement.width}'); 275 | debugPrint( 276 | 'Webcam video taille : ${_webcamVideoElement.videoHeight} & ${_webcamVideoElement.videoWidth}'); 277 | 278 | final dataUrl = _canvasElement.toDataUrl('image/jpeg', 1.0); 279 | imageElement.src = dataUrl; 280 | detectBarcode(dataUrl, allowInterop((result) => onBarcodeResult(result))); 281 | 282 | counter++; 283 | 284 | if (counter >= maxAttempt) { 285 | counter = 0; 286 | frameSize = frameSize == 0 ? 1 : 0; 287 | } 288 | } 289 | 290 | /// Method called on barcode result to finish the process and send result 291 | Future onBarcodeResult(String _barcode) async { 292 | _barcodeResults.add(_barcode); 293 | if (_barcodeResults.gotResult) { 294 | releaseResources(); 295 | if (!completer.isCompleted) { 296 | completer.complete(_barcodeResults.mostFrequentBarcode); 297 | _barcodeResults.clear(); 298 | } 299 | } 300 | } 301 | 302 | /// Release resources to avoid leaks 303 | void releaseResources() { 304 | _timer.cancel(); 305 | _webcamVideoElement.pause(); 306 | _webcamVideoElement.srcObject?.getTracks().forEach((track) { 307 | track.stop(); 308 | track.enabled = false; 309 | }); 310 | _webcamVideoElement.srcObject = null; 311 | _canvasElement.remove(); 312 | _webcamVideoElement.remove(); 313 | imageElement.remove(); 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.camcodeExample; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.camcodeExample; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.camcodeExample; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | --------------------------------------------------------------------------------