Browse Source

first commit

zhaoyadi 4 years ago
commit
635db96fda
100 changed files with 4817 additions and 0 deletions
  1. 7 0
      .gitignore
  2. 2 0
      .idea/.gitignore
  3. 116 0
      .idea/codeStyles/Project.xml
  4. 29 0
      .idea/libraries/Dart_SDK.xml
  5. 9 0
      .idea/libraries/Flutter_Plugins.xml
  6. 9 0
      .idea/libraries/Flutter_for_Android.xml
  7. 9 0
      .idea/misc.xml
  8. 8 0
      .idea/modules.xml
  9. 6 0
      .idea/runConfigurations/example_lib_main_dart.xml
  10. 8 0
      .idea/vcs.xml
  11. 10 0
      .metadata
  12. 13 0
      CHANGELOG.md
  13. 27 0
      LICENSE
  14. 335 0
      README.md
  15. 8 0
      android/.gitignore
  16. 1 0
      android/.idea/.name
  17. BIN
      android/.idea/caches/build_file_checksums.ser
  18. 134 0
      android/.idea/codeStyles/Project.xml
  19. 20 0
      android/.idea/gradle.xml
  20. 40 0
      android/.idea/jarRepositories.xml
  21. 9 0
      android/.idea/misc.xml
  22. 8 0
      android/.idea/modules.xml
  23. 12 0
      android/.idea/runConfigurations.xml
  24. 53 0
      android/build.gradle
  25. 2 0
      android/gradle.properties
  26. 5 0
      android/gradle/wrapper/gradle-wrapper.properties
  27. BIN
      android/libs/arm64-v8a/libiconv.so
  28. BIN
      android/libs/arm64-v8a/libzbar.so
  29. BIN
      android/libs/armeabi-v7a/libiconv.so
  30. BIN
      android/libs/armeabi-v7a/libzbar.so
  31. BIN
      android/libs/armeabi/libiconv.so
  32. BIN
      android/libs/armeabi/libzbar.so
  33. BIN
      android/libs/mips/libiconv.so
  34. BIN
      android/libs/mips/libzbar.so
  35. BIN
      android/libs/mips64/libiconv.so
  36. BIN
      android/libs/mips64/libzbar.so
  37. BIN
      android/libs/x86/libiconv.so
  38. BIN
      android/libs/x86/libzbar.so
  39. BIN
      android/libs/x86_64/libiconv.so
  40. BIN
      android/libs/x86_64/libzbar.so
  41. 1 0
      android/settings.gradle
  42. 9 0
      android/src/main/AndroidManifest.xml
  43. 76 0
      android/src/main/java/cn/bertsir/zbar/Qr/Config.java
  44. 196 0
      android/src/main/java/cn/bertsir/zbar/Qr/Image.java
  45. 111 0
      android/src/main/java/cn/bertsir/zbar/Qr/ImageScanner.java
  46. 44 0
      android/src/main/java/cn/bertsir/zbar/Qr/Modifier.java
  47. 52 0
      android/src/main/java/cn/bertsir/zbar/Qr/Orientation.java
  48. 31 0
      android/src/main/java/cn/bertsir/zbar/Qr/ScanResult.java
  49. 326 0
      android/src/main/java/cn/bertsir/zbar/Qr/Symbol.java
  50. 76 0
      android/src/main/java/cn/bertsir/zbar/Qr/SymbolIterator.java
  51. 93 0
      android/src/main/java/cn/bertsir/zbar/Qr/SymbolSet.java
  52. 283 0
      android/src/main/java/com/rhyme/r_scan/ImageScanHelper.java
  53. 75 0
      android/src/main/java/com/rhyme/r_scan/MethodCallHandlerImpl.java
  54. 95 0
      android/src/main/java/com/rhyme/r_scan/RScanCamera/CameraUtils.java
  55. 475 0
      android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanCamera.java
  56. 160 0
      android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanCameraMethodHandler.java
  57. 49 0
      android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanMessenger.java
  58. 78 0
      android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanPermissions.java
  59. 120 0
      android/src/main/java/com/rhyme/r_scan/RScanPlugin.java
  60. 42 0
      android/src/main/java/com/rhyme/r_scan/RScanResultUtils.java
  61. 206 0
      android/src/main/java/com/rhyme/r_scan/RScanView/FlutterRScanView.java
  62. 22 0
      android/src/main/java/com/rhyme/r_scan/RScanView/RScanViewFactory.java
  63. 12 0
      android/src/main/java/com/rhyme/r_scan/RScanView/RScanViewPlugin.java
  64. 1 0
      example/.flutter-plugins-dependencies
  65. 73 0
      example/.gitignore
  66. 10 0
      example/.metadata
  67. 148 0
      example/README.md
  68. 63 0
      example/android/app/build.gradle
  69. 7 0
      example/android/app/src/debug/AndroidManifest.xml
  70. 34 0
      example/android/app/src/main/AndroidManifest.xml
  71. 13 0
      example/android/app/src/main/java/com/rhyme/r_scan_example/MainActivity.java
  72. 12 0
      example/android/app/src/main/res/drawable/launch_background.xml
  73. BIN
      example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  74. BIN
      example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  75. BIN
      example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  76. BIN
      example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  77. BIN
      example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  78. 8 0
      example/android/app/src/main/res/values/styles.xml
  79. 7 0
      example/android/app/src/profile/AndroidManifest.xml
  80. 29 0
      example/android/build.gradle
  81. 5 0
      example/android/gradle.properties
  82. 6 0
      example/android/gradle/wrapper/gradle-wrapper.properties
  83. 15 0
      example/android/settings.gradle
  84. BIN
      example/images/qrCode.png
  85. 26 0
      example/ios/Flutter/AppFrameworkInfo.plist
  86. 2 0
      example/ios/Flutter/Debug.xcconfig
  87. 2 0
      example/ios/Flutter/Release.xcconfig
  88. 595 0
      example/ios/Runner.xcodeproj/project.pbxproj
  89. 7 0
      example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  90. 91 0
      example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
  91. 10 0
      example/ios/Runner.xcworkspace/contents.xcworkspacedata
  92. 6 0
      example/ios/Runner/AppDelegate.h
  93. 13 0
      example/ios/Runner/AppDelegate.m
  94. 122 0
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
  95. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
  96. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
  97. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
  98. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
  99. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
  100. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+
+build/

+ 2 - 0
.idea/.gitignore

@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml

+ 116 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,116 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 29 - 0
.idea/libraries/Dart_SDK.xml

@@ -0,0 +1,29 @@
+<component name="libraryTable">
+  <library name="Dart SDK">
+    <CLASSES>
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/async" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/cli" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/collection" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/convert" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/core" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/developer" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/ffi" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/html" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/indexed_db" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/io" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/isolate" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/js" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/js_util" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/math" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/mirrors" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/svg" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/typed_data" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/wasm" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/web_audio" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/web_gl" />
+      <root url="file://$PROJECT_DIR$/../../../flutter/bin/cache/dart-sdk/lib/web_sql" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
.idea/libraries/Flutter_Plugins.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Flutter Plugins" type="FlutterPluginsLibraryType">
+    <CLASSES>
+      <root url="file://$PROJECT_DIR$" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
.idea/libraries/Flutter_for_Android.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Flutter for Android">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../../envirement/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
.idea/misc.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="io.flutter" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/r_scan.iml" filepath="$PROJECT_DIR$/r_scan.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/runConfigurations/example_lib_main_dart.xml

@@ -0,0 +1,6 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false">
+    <option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
+    <method v="2" />
+  </configuration>
+</component>

+ 8 - 0
.idea/vcs.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/example/ios/.symlinks/plugins/r_scan" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/example/ios/zxingify-objc" vcs="Git" />
+  </component>
+</project>

+ 10 - 0
.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5
+  channel: stable
+
+project_type: plugin

+ 13 - 0
CHANGELOG.md

@@ -0,0 +1,13 @@
+## 0.1.4 add RScanCamera.
+
+## 0.1.3 add the barcode type and the point in result.
+
+## 0.1.2 fix android camera draw.
+
+## 0.1.1 add turn on / turn off flash lamp and get flash lamp status.
+
+## 0.1.0 add ios platform and finish.
+
+## 0.0.1 init project,and android platform finish.
+
+

+ 27 - 0
LICENSE

@@ -0,0 +1,27 @@
+// Copyright 2019 The rhyme_lph Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * 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.
+//    * Neither the name of rhyme_lph authors. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.

+ 335 - 0
README.md

@@ -0,0 +1,335 @@
+# r_scan
+[![pub package](https://img.shields.io/pub/v/r_scan.svg)](https://pub.dartlang.org/packages/r_scan)
+
+![](screen/r_scan.png)
+
+A flutter plugin about qr code or bar code scan , it can scan from file、url、memory and camera qr code or bar code .Welcome to feedback your issue.
+
+## Getting Started
+
+###  Depend on it
+
+Add this to your package's pubspec.yaml file:
+```yaml
+dependencies:
+  r_scan: last version
+```
+
+### Android Platform
+require `read storage permission` and `camera permission`, use `permission_handler` plugin.
+```dart
+import 'package:permission_handler/permission_handler.dart';
+
+Future<bool> canReadStorage() async {
+    if(Platform.isIOS) return true;
+    var status = await PermissionHandler()
+        .checkPermissionStatus(PermissionGroup.storage);
+    if (status != PermissionStatus.granted) {
+      var future = await PermissionHandler()
+          .requestPermissions([PermissionGroup.storage]);
+      for (final item in future.entries) {
+        if (item.value != PermissionStatus.granted) {
+          return false;
+        }
+      }
+    } else {
+      return true;
+    }
+    return true;
+  }
+
+Future<bool> canOpenCamera() async {
+    var status =
+        await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
+    if (status != PermissionStatus.granted) {
+      var future = await PermissionHandler()
+          .requestPermissions([PermissionGroup.camera]);
+      for (final item in future.entries) {
+        if (item.value != PermissionStatus.granted) {
+          return false;
+        }
+      }
+    } else {
+      return true;
+    }
+    return true;
+  }
+```
+
+### IOS Platform
+add the permissions in your Info.plist
+```plist
+    <key>NSCameraUsageDescription</key>
+	<string>扫描二维码时需要使用您的相机</string>
+	<key>NSPhotoLibraryUsageDescription</key>
+	<string>扫描二维码时需要访问您的相册</string>
+	<key>io.flutter.embedded_views_preview</key>
+    <true/>
+```
+no another.
+
+
+## Usage
+### 1.scan Image File
+
+```dart
+
+final result=await RScan.scanImagePath('your file path');
+
+```
+
+### 2.scan Image url
+
+```dart
+
+final result=await RScan.scanImagePath('your image url');
+
+```
+
+### 3.scan Image memory
+
+```dart
+
+ ByteData data=await rootBundle.load('images/qrCode.png');
+ final result=await RScan.scanImageMemory(data.buffer.asUint8List());
+
+```
+
+### 4.scan camera(new! please upgrade this plugin to v0.1,4)
+
+- Step First: Get available cameras
+```dart
+List<RScanCameraDescription> rScanCameras = await availableRScanCameras();;
+```
+if you want to get it in main() method, you can use this code.
+```dart
+List<RScanCameraDescription> rScanCameras;
+
+void main() async {
+  WidgetsFlutterBinding.ensureInitialized();
+  rScanCameras = await availableRScanCameras();
+  runApp(...);
+}
+```
+- Step Second:Use it.
+```dart
+class RScanCameraDialog extends StatefulWidget {
+  @override
+  _RScanCameraDialogState createState() => _RScanCameraDialogState();
+}
+
+class _RScanCameraDialogState extends State<RScanCameraDialog> {
+  RScanCameraController _controller;
+  bool isFirst = true;
+
+  @override
+  void initState() {
+    super.initState();
+    if (rScanCameras != null && rScanCameras.length > 0) {
+      _controller = RScanCameraController(
+          rScanCameras[1], RScanCameraResolutionPreset.max)
+        ..addListener(() {
+          final result = _controller.result;
+          if (result != null) {
+            if (isFirst) {
+              Navigator.of(context).pop(result);
+              isFirst = false;
+            }
+          }
+        })
+        ..initialize().then((_) {
+          if (!mounted) {
+            return;
+          }
+          setState(() {});
+        });
+    }
+  }
+
+  @override
+  void dispose() {
+    _controller?.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    if (rScanCameras == null || rScanCameras.length == 0) {
+      return Scaffold(
+        body: Container(
+          alignment: Alignment.center,
+          child: Text('not have available camera'),
+        ),
+      );
+    }
+    if (!_controller.value.isInitialized) {
+      return Container();
+    }
+    return Scaffold(
+      backgroundColor: Colors.black,
+      body: Stack(
+        children: <Widget>[
+          ScanImageView(
+            child: AspectRatio(
+              aspectRatio: _controller.value.aspectRatio,
+              child: RScanCamera(_controller),
+            ),
+          ),
+          Align(
+              alignment: Alignment.bottomCenter,
+              child: FutureBuilder(
+                future: getFlashMode(),
+                builder: _buildFlashBtn,
+              ))
+        ],
+      ),
+    );
+  }
+  Future<bool> getFlashMode() async {
+    bool isOpen = false;
+    try {
+      isOpen = await _controller.getFlashMode();
+    } catch (_) {}
+    return isOpen;
+  }
+
+  Widget _buildFlashBtn(BuildContext context, AsyncSnapshot<bool> snapshot) {
+    return snapshot.hasData
+        ? Padding(
+      padding:  EdgeInsets.only(bottom:24+MediaQuery.of(context).padding.bottom),
+      child: IconButton(
+          icon: Icon(snapshot.data ? Icons.flash_on : Icons.flash_off),
+          color: Colors.white,
+          iconSize: 46,
+          onPressed: () {
+            if (snapshot.data) {
+              _controller.setFlashMode(false);
+            } else {
+              _controller.setFlashMode(true);
+            }
+            setState(() {});
+          }),
+    )
+        : Container();
+  }
+}
+```
+
+### 5.scan view(Deprecated)
+
+```dart
+import 'package:flutter/material.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:r_scan/r_scan.dart';
+
+class RScanDialog extends StatefulWidget {
+  @override
+  _RScanDialogState createState() => _RScanDialogState();
+}
+
+class _RScanDialogState extends State<RScanDialog> {
+  RScanController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+    initController();
+  }
+  bool isFirst=true;
+
+
+  Future<void> initController() async {
+    _controller = RScanController();
+    _controller.addListener(() {
+
+      final result = _controller.result;
+      if (result != null) {
+        if(isFirst){
+          Navigator.of(context).pop(result);
+          isFirst=false;
+        }
+      }
+    });
+  }
+
+  @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      home: Scaffold(
+        backgroundColor: Colors.black,
+        body: FutureBuilder<bool>(
+          future: canOpenCameraView(),
+          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
+            if (snapshot.hasData && snapshot.data == true) {
+              return ScanImageView(
+                child: RScanView(
+                  controller: _controller,
+                ),
+              );
+            } else {
+              return Container();
+            }
+          },
+        ),
+      ),
+    );
+  }
+
+  Future<bool> canOpenCameraView() async {
+    var status =
+        await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
+    if (status != PermissionStatus.granted) {
+      var future = await PermissionHandler()
+          .requestPermissions([PermissionGroup.camera]);
+      for (final item in future.entries) {
+        if (item.value != PermissionStatus.granted) {
+          return false;
+        }
+      }
+    } else {
+      return true;
+    }
+    return true;
+  }
+}
+
+```
+
+### 6. open flash lamp / get flash lamp status.
+You can use `RScanController` class.
+```dart
+//turn off the flash lamp.
+await _controller.setFlashMode(false);
+
+//turn on the flash lamp.
+await _controller.setFlashMode(true);
+
+// get the flash lamp status.
+
+bool isOpen = await _controller.getFlashMode();
+
+```
+
+### 7. RScanResult
+
+when you scan finish,will return the RScanResult...
+
+```dart
+class RScanResult {
+  /// barcode type
+  final RScanBarType type;
+
+  ///barcode message
+  final String message;
+
+  ///barcode points include [x , y]
+  final List<RScanPoint> points;
+}
+
+```

+ 8 - 0
android/.gitignore

@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures

+ 1 - 0
android/.idea/.name

@@ -0,0 +1 @@
+r_scan

BIN
android/.idea/caches/build_file_checksums.ser


+ 134 - 0
android/.idea/codeStyles/Project.xml

@@ -0,0 +1,134 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <JetCodeStyleSettings>
+      <option name="PACKAGES_TO_USE_STAR_IMPORTS">
+        <value>
+          <package name="java.util" alias="false" withSubpackages="false" />
+          <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
+          <package name="io.ktor" alias="false" withSubpackages="true" />
+        </value>
+      </option>
+      <option name="PACKAGES_IMPORT_LAYOUT">
+        <value>
+          <package name="" alias="false" withSubpackages="true" />
+          <package name="java" alias="false" withSubpackages="true" />
+          <package name="javax" alias="false" withSubpackages="true" />
+          <package name="kotlin" alias="false" withSubpackages="true" />
+          <package name="" alias="true" withSubpackages="true" />
+        </value>
+      </option>
+    </JetCodeStyleSettings>
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 20 - 0
android/.idea/gradle.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="testRunner" value="PLATFORM" />
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleHome" value="D:/gradle-6.6.1" />
+        <option name="gradleJvm" value="1.8" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 40 - 0
android/.idea/jarRepositories.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\m2repository" />
+      <option name="name" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\m2repository" />
+      <option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/m2repository" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\android\m2repository" />
+      <option name="name" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\android\m2repository" />
+      <option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="BintrayJCenter" />
+      <option name="name" value="BintrayJCenter" />
+      <option name="url" value="https://jcenter.bintray.com/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\google\m2repository" />
+      <option name="name" value="C:\Users\p'c\AppData\Local\Android\Sdk\extras\google\m2repository" />
+      <option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/google/m2repository" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="Google" />
+      <option name="name" value="Google" />
+      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+    </remote-repository>
+  </component>
+</project>

+ 9 - 0
android/.idea/misc.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 8 - 0
android/.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/r_scan.iml" filepath="$PROJECT_DIR$/.idea/modules/r_scan.iml" group="r_scan" />
+    </modules>
+  </component>
+</project>

+ 12 - 0
android/.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 53 - 0
android/build.gradle

@@ -0,0 +1,53 @@
+group 'com.rhyme.r_scan'
+version '1.0'
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.2.1'
+    }
+}
+
+rootProject.allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 28
+
+    defaultConfig {
+        minSdkVersion 21
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+    compileOptions {
+        sourceCompatibility = 1.8
+        targetCompatibility = 1.8
+    }
+    sourceSets {
+        main {
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+
+    def camerax_version = "1.0.0-alpha05"
+    implementation "androidx.camera:camera-core:${camerax_version}"
+    implementation "androidx.camera:camera-camera2:${camerax_version}"
+
+    implementation 'com.google.zxing:core:3.4.1'
+}

+ 2 - 0
android/gradle.properties

@@ -0,0 +1,2 @@
+org.gradle.jvmargs=-Xmx1536M
+

+ 5 - 0
android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

BIN
android/libs/arm64-v8a/libiconv.so


BIN
android/libs/arm64-v8a/libzbar.so


BIN
android/libs/armeabi-v7a/libiconv.so


BIN
android/libs/armeabi-v7a/libzbar.so


BIN
android/libs/armeabi/libiconv.so


BIN
android/libs/armeabi/libzbar.so


BIN
android/libs/mips/libiconv.so


BIN
android/libs/mips/libzbar.so


BIN
android/libs/mips64/libiconv.so


BIN
android/libs/mips64/libzbar.so


BIN
android/libs/x86/libiconv.so


BIN
android/libs/x86/libzbar.so


BIN
android/libs/x86_64/libiconv.so


BIN
android/libs/x86_64/libzbar.so


+ 1 - 0
android/settings.gradle

@@ -0,0 +1 @@
+rootProject.name = 'r_scan'

+ 9 - 0
android/src/main/AndroidManifest.xml

@@ -0,0 +1,9 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.rhyme.r_scan">
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+</manifest>

+ 76 - 0
android/src/main/java/cn/bertsir/zbar/Qr/Config.java

@@ -0,0 +1,76 @@
+/*------------------------------------------------------------------------
+ *  Config
+ *
+ *  Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Decoder configuration options.
+ */
+public class Config {
+    /**
+     * Enable symbology/feature.
+     */
+    public static final int ENABLE = 0;
+    /**
+     * Enable check digit when optional.
+     */
+    public static final int ADD_CHECK = 1;
+    /**
+     * Return check digit when present.
+     */
+    public static final int EMIT_CHECK = 2;
+    /**
+     * Enable full ASCII character set.
+     */
+    public static final int ASCII = 3;
+
+    /**
+     * Minimum data length for valid decode.
+     */
+    public static final int MIN_LEN = 0x20;
+    /**
+     * Maximum data length for valid decode.
+     */
+    public static final int MAX_LEN = 0x21;
+
+    /**
+     * Required video consistency frames.
+     */
+    public static final int UNCERTAINTY = 0x40;
+
+    /**
+     * Enable scanner to collect position data.
+     */
+    public static final int POSITION = 0x80;
+
+    /**
+     * Image scanner vertical scan density.
+     */
+    public static final int X_DENSITY = 0x100;
+    /**
+     * Image scanner horizontal scan density.
+     */
+    public static final int Y_DENSITY = 0x101;
+}

+ 196 - 0
android/src/main/java/cn/bertsir/zbar/Qr/Image.java

@@ -0,0 +1,196 @@
+/*------------------------------------------------------------------------
+ *  Image
+ *
+ *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * stores image data samples along with associated format and size
+ * metadata.
+ */
+@SuppressWarnings("JniMissingFunction")
+public class Image {
+    /**
+     * C pointer to a zbar_symbol_t.
+     */
+    private long peer;
+    private Object data;
+
+    static {
+        System.loadLibrary("zbar");
+        init();
+    }
+
+    private static native void init();
+
+    public Image() {
+        peer = create();
+    }
+
+    public Image(int width, int height) {
+        this();
+        setSize(width, height);
+    }
+
+    public Image(int width, int height, String format) {
+        this();
+        setSize(width, height);
+        setFormat(format);
+    }
+
+    public Image(String format) {
+        this();
+        setFormat(format);
+    }
+
+    Image(long peer) {
+        this.peer = peer;
+    }
+
+    /**
+     * Create an associated peer instance.
+     */
+    private native long create();
+
+    protected void finalize() {
+        destroy();
+    }
+
+    /**
+     * Clean up native data associated with an instance.
+     */
+    public synchronized void destroy() {
+        if (peer != 0) {
+            destroy(peer);
+            peer = 0;
+        }
+    }
+
+    /**
+     * Destroy the associated peer instance.
+     */
+    private native void destroy(long peer);
+
+    /**
+     * Image format conversion.
+     *
+     * @returns a @em new image with the sample data from the original
+     * image converted to the requested format fourcc.  the original
+     * image is unaffected.
+     */
+    public Image convert(String format) {
+        long newpeer = convert(peer, format);
+        if (newpeer == 0)
+            return (null);
+        return (new Image(newpeer));
+    }
+
+    private native long convert(long peer, String format);
+
+    /**
+     * Retrieve the image format fourcc.
+     */
+    public native String getFormat();
+
+    /**
+     * Specify the fourcc image format code for image sample data.
+     */
+    public native void setFormat(String format);
+
+    /**
+     * Retrieve a "sequence" (page/frame) number associated with this
+     * image.
+     */
+    public native int getSequence();
+
+    /**
+     * Associate a "sequence" (page/frame) number with this image.
+     */
+    public native void setSequence(int seq);
+
+    /**
+     * Retrieve the width of the image.
+     */
+    public native int getWidth();
+
+    /**
+     * Retrieve the height of the image.
+     */
+    public native int getHeight();
+
+    /**
+     * Retrieve the size of the image.
+     */
+    public native int[] getSize();
+
+    /**
+     * Specify the pixel size of the image.
+     */
+    public native void setSize(int width, int height);
+
+    /**
+     * Specify the pixel size of the image.
+     */
+    public native void setSize(int[] size);
+
+    /**
+     * Retrieve the crop region of the image.
+     */
+    public native int[] getCrop();
+
+    /**
+     * Specify the crop region of the image.
+     */
+    public native void setCrop(int x, int y, int width, int height);
+
+    /**
+     * Specify the crop region of the image.
+     */
+    public native void setCrop(int[] crop);
+
+    /**
+     * Retrieve the image sample data.
+     */
+    public native byte[] getData();
+
+    /**
+     * Specify image sample data.
+     */
+    public native void setData(byte[] data);
+
+    /**
+     * Specify image sample data.
+     */
+    public native void setData(int[] data);
+
+    /**
+     * Retrieve the decoded results associated with this image.
+     */
+    public SymbolSet getSymbols() {
+        return (new SymbolSet(getSymbols(peer)));
+    }
+
+    private native long getSymbols(long peer);
+
+}

+ 111 - 0
android/src/main/java/cn/bertsir/zbar/Qr/ImageScanner.java

@@ -0,0 +1,111 @@
+/*------------------------------------------------------------------------
+ *  ImageScanner
+ *
+ *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Read barcodes from 2-D images.
+ */
+@SuppressWarnings("JniMissingFunction")
+public class ImageScanner {
+    /**
+     * C pointer to a zbar_image_scanner_t.
+     */
+    private long peer;
+
+    static {
+        System.loadLibrary("zbar");
+        init();
+    }
+
+    private static native void init();
+
+    public ImageScanner() {
+        peer = create();
+    }
+
+    /**
+     * Create an associated peer instance.
+     */
+    private native long create();
+
+    protected void finalize() {
+        destroy();
+    }
+
+    /**
+     * Clean up native data associated with an instance.
+     */
+    public synchronized void destroy() {
+        if (peer != 0) {
+            destroy(peer);
+            peer = 0;
+        }
+    }
+
+    /**
+     * Destroy the associated peer instance.
+     */
+    private native void destroy(long peer);
+
+    /**
+     * Set config for indicated symbology (0 for all) to specified value.
+     */
+    public native void setConfig(int symbology, int config, int value)
+            throws IllegalArgumentException;
+
+    /**
+     * Parse configuration string and apply to image scanner.
+     */
+    public native void parseConfig(String config);
+
+    /**
+     * Enable or disable the inter-image result cache (default disabled).
+     * Mostly useful for scanning video frames, the cache filters duplicate
+     * results from consecutive images, while adding some consistency
+     * checking and hysteresis to the results.  Invoking this method also
+     * clears the cache.
+     */
+    public native void enableCache(boolean enable);
+
+    /**
+     * Retrieve decode results for last scanned image.
+     *
+     * @returns the SymbolSet result container
+     */
+    public SymbolSet getResults() {
+        return (new SymbolSet(getResults(peer)));
+    }
+
+    private native long getResults(long peer);
+
+    /**
+     * Scan for symbols in provided Image.
+     * The image format must currently be "Y800" or "GRAY".
+     *
+     * @returns the number of symbols successfully decoded from the image.
+     */
+    public native int scanImage(Image image);
+}

+ 44 - 0
android/src/main/java/cn/bertsir/zbar/Qr/Modifier.java

@@ -0,0 +1,44 @@
+/*------------------------------------------------------------------------
+ *  Modifier
+ *
+ *  Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Decoder symbology modifiers.
+ */
+public class Modifier {
+    /**
+     * barcode tagged as GS1 (EAN.UCC) reserved
+     * (eg, FNC1 before first data character).
+     * data may be parsed as a sequence of GS1 AIs
+     */
+    public static final int GS1 = 0;
+
+    /**
+     * barcode tagged as AIM reserved
+     * (eg, FNC1 after first character or digit pair)
+     */
+    public static final int AIM = 1;
+}

+ 52 - 0
android/src/main/java/cn/bertsir/zbar/Qr/Orientation.java

@@ -0,0 +1,52 @@
+/*------------------------------------------------------------------------
+ *  Orientation
+ *
+ *  Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Decoded symbol coarse orientation.
+ */
+public class Orientation {
+    /**
+     * Unable to determine orientation.
+     */
+    public static final int UNKNOWN = -1;
+    /**
+     * Upright, read left to right.
+     */
+    public static final int UP = 0;
+    /**
+     * sideways, read top to bottom
+     */
+    public static final int RIGHT = 1;
+    /**
+     * upside-down, read right to left
+     */
+    public static final int DOWN = 2;
+    /**
+     * sideways, read bottom to top
+     */
+    public static final int LEFT = 3;
+}

+ 31 - 0
android/src/main/java/cn/bertsir/zbar/Qr/ScanResult.java

@@ -0,0 +1,31 @@
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Created by Bert on 2019-08-19.
+ * Mail: bertsir@163.com
+ */
+public class ScanResult {
+
+    public String content;
+    public int type;
+
+    public static final int CODE_QR = 1;//二维码
+    public static final int CODE_BAR = 2;//条形码
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+}

+ 326 - 0
android/src/main/java/cn/bertsir/zbar/Qr/Symbol.java

@@ -0,0 +1,326 @@
+/*------------------------------------------------------------------------
+ *  Symbol
+ *
+ *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Immutable container for decoded result symbols associated with an image
+ * or a composite symbol.
+ */
+@SuppressWarnings("JniMissingFunction")
+public class Symbol {
+    /**
+     * No symbol decoded.
+     */
+    public static final int NONE = 0;
+    /**
+     * Symbol detected but not decoded.
+     */
+    public static final int PARTIAL = 1;
+
+    /**
+     * EAN-8.
+     */
+    public static final int EAN8 = 8;
+    /**
+     * UPC-E.
+     */
+    public static final int UPCE = 9;
+    /**
+     * ISBN-10 (from EAN-13).
+     */
+    public static final int ISBN10 = 10;
+    /**
+     * UPC-A.
+     */
+    public static final int UPCA = 12;
+    /**
+     * EAN-13.
+     */
+    public static final int EAN13 = 13;
+    /**
+     * ISBN-13 (from EAN-13).
+     */
+    public static final int ISBN13 = 14;
+    /**
+     * Interleaved 2 of 5.
+     */
+    public static final int I25 = 25;
+    /**
+     * DataBar (RSS-14).
+     */
+    public static final int DATABAR = 34;
+    /**
+     * DataBar Expanded.
+     */
+    public static final int DATABAR_EXP = 35;
+    /**
+     * Codabar.
+     */
+    public static final int CODABAR = 38;
+    /**
+     * Code 39.
+     */
+    public static final int CODE39 = 39;
+    /**
+     * PDF417.
+     */
+    public static final int PDF417 = 57;
+    /**
+     * QR Code.
+     */
+    public static final int QRCODE = 64;
+    /**
+     * Code 93.
+     */
+    public static final int CODE93 = 93;
+    /**
+     * Code 128.
+     */
+    public static final int CODE128 = 128;
+
+    /**
+     * 裁剪的X轴
+     */
+    public static int cropX = 0;
+
+    /**
+     * 裁剪的Y轴
+     */
+    public static int cropY = 0;
+
+    /**
+     * 裁剪的宽
+     */
+    public static int cropWidth = 0;
+
+    /**
+     * 裁剪的高
+     */
+    public static int cropHeight = 0;
+
+    /**
+     * 屏幕的宽
+     */
+    public static int screenWidth = 0;
+
+    /**
+     * 屏幕的高
+     */
+    public static int screenHeight = 0;
+
+
+    /**
+     * 识别类型
+     */
+    public static int scanType = 0;//1二维码 2UPCA条形码 3全部类型 4用户指定类型
+
+    /**
+     * 识别码类
+     */
+    public static int scanFormat = 0;
+
+    /**
+     * 是否只识别框中内容
+     */
+    public static boolean is_only_scan_center = false;
+
+    /**
+     * 是否自动拉近
+     */
+    public static boolean is_auto_zoom = false;
+
+
+    /**
+     * 双识别引擎
+     */
+    public static boolean doubleEngine = false;
+
+
+    /**
+     * 持续扫描
+     */
+    public static boolean looperScan = false;
+
+
+    /**
+     * 持续扫描间隔时间
+     */
+    public static int looperWaitTime = 0;
+
+
+    /**
+     * C pointer to a zbar_symbol_t.
+     */
+    private long peer;
+
+    /**
+     * Cached attributes.
+     */
+    private int type;
+
+    static {
+        System.loadLibrary("zbar");
+        init();
+    }
+
+    private static native void init();
+
+    /**
+     * Symbols are only created by other package methods.
+     */
+    Symbol(long peer) {
+        this.peer = peer;
+    }
+
+    protected void finalize() {
+        destroy();
+    }
+
+    /**
+     * Clean up native data associated with an instance.
+     */
+    public synchronized void destroy() {
+        if (peer != 0) {
+            destroy(peer);
+            peer = 0;
+        }
+    }
+
+    /**
+     * Release the associated peer instance.
+     */
+    private native void destroy(long peer);
+
+    /**
+     * Retrieve type of decoded symbol.
+     */
+    public int getType() {
+        if (type == 0)
+            type = getType(peer);
+        return (type);
+    }
+
+    private native int getType(long peer);
+
+    /**
+     * Retrieve symbology boolean configs settings used during decode.
+     */
+    public native int getConfigMask();
+
+    /**
+     * Retrieve symbology characteristics detected during decode.
+     */
+    public native int getModifierMask();
+
+    /**
+     * Retrieve data decoded from symbol as a String.
+     */
+    public native String getData();
+
+    /**
+     * Retrieve raw data bytes decoded from symbol.
+     */
+    public native byte[] getDataBytes();
+
+    /**
+     * Retrieve a symbol confidence metric.  Quality is an unscaled,
+     * relative quantity: larger values are better than smaller
+     * values, where "large" and "small" are application dependent.
+     */
+    public native int getQuality();
+
+    /**
+     * Retrieve current cache count.  When the cache is enabled for
+     * the image_scanner this provides inter-frame reliability and
+     * redundancy information for video streams.
+     *
+     * @returns < 0 if symbol is still uncertain
+     * @returns 0 if symbol is newly verified
+     * @returns > 0 for duplicate symbols
+     */
+    public native int getCount();
+
+    /**
+     * Retrieve an approximate, axis-aligned bounding box for the
+     * symbol.
+     */
+    public int[] getBounds() {
+        int n = getLocationSize(peer);
+        if (n <= 0)
+            return (null);
+
+        int[] bounds = new int[4];
+        int xmin = Integer.MAX_VALUE;
+        int xmax = Integer.MIN_VALUE;
+        int ymin = Integer.MAX_VALUE;
+        int ymax = Integer.MIN_VALUE;
+
+        for (int i = 0; i < n; i++) {
+            int x = getLocationX(peer, i);
+            if (xmin > x) xmin = x;
+            if (xmax < x) xmax = x;
+
+            int y = getLocationY(peer, i);
+            if (ymin > y) ymin = y;
+            if (ymax < y) ymax = y;
+        }
+        bounds[0] = xmin;
+        bounds[1] = ymin;
+        bounds[2] = xmax - xmin;
+        bounds[3] = ymax - ymin;
+        return (bounds);
+    }
+
+    private native int getLocationSize(long peer);
+
+    private native int getLocationX(long peer, int idx);
+
+    private native int getLocationY(long peer, int idx);
+
+    public int[] getLocationPoint(int idx) {
+        int[] p = new int[2];
+        p[0] = getLocationX(peer, idx);
+        p[1] = getLocationY(peer, idx);
+        return (p);
+    }
+
+    /**
+     * Retrieve general axis-aligned, orientation of decoded
+     * symbol.
+     */
+    public native int getOrientation();
+
+    /**
+     * Retrieve components of a composite result.
+     */
+    public SymbolSet getComponents() {
+        return (new SymbolSet(getComponents(peer)));
+    }
+
+    private native long getComponents(long peer);
+
+    native long next();
+}

+ 76 - 0
android/src/main/java/cn/bertsir/zbar/Qr/SymbolIterator.java

@@ -0,0 +1,76 @@
+/*------------------------------------------------------------------------
+ *  SymbolIterator
+ *
+ *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Iterator over a SymbolSet.
+ */
+public class SymbolIterator
+        implements java.util.Iterator<Symbol> {
+    /**
+     * Next symbol to be returned by the iterator.
+     */
+    private Symbol current;
+
+    /**
+     * SymbolIterators are only created by internal interface methods.
+     */
+    SymbolIterator(Symbol first) {
+        current = first;
+    }
+
+    /**
+     * Returns true if the iteration has more elements.
+     */
+    public boolean hasNext() {
+        return (current != null);
+    }
+
+    /**
+     * Retrieves the next element in the iteration.
+     */
+    public Symbol next() {
+        if (current == null)
+            throw (new java.util.NoSuchElementException
+                    ("access past end of SymbolIterator"));
+
+        Symbol result = current;
+        long sym = current.next();
+        if (sym != 0)
+            current = new Symbol(sym);
+        else
+            current = null;
+        return (result);
+    }
+
+    /**
+     * Raises UnsupportedOperationException.
+     */
+    public void remove() {
+        throw (new UnsupportedOperationException
+                ("SymbolIterator is immutable"));
+    }
+}

+ 93 - 0
android/src/main/java/cn/bertsir/zbar/Qr/SymbolSet.java

@@ -0,0 +1,93 @@
+/*------------------------------------------------------------------------
+ *  SymbolSet
+ *
+ *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ *  This file is part of the ZBar Bar Code Reader.
+ *
+ *  The ZBar Bar Code Reader is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU Lesser Public License as
+ *  published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  The ZBar Bar Code Reader is distributed in the hope that it will be
+ *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser Public License
+ *  along with the ZBar Bar Code Reader; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *  Boston, MA  02110-1301  USA
+ *
+ *  http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+package cn.bertsir.zbar.Qr;
+
+/**
+ * Immutable container for decoded result symbols associated with an image
+ * or a composite symbol.
+ */
+@SuppressWarnings("JniMissingFunction")
+public class SymbolSet
+        extends java.util.AbstractCollection<Symbol> {
+    /**
+     * C pointer to a zbar_symbol_set_t.
+     */
+    private long peer;
+
+    static {
+        System.loadLibrary("zbar");
+        init();
+    }
+
+    private static native void init();
+
+    /**
+     * SymbolSets are only created by other package methods.
+     */
+    SymbolSet(long peer) {
+        this.peer = peer;
+    }
+
+    protected void finalize() {
+        destroy();
+    }
+
+    /**
+     * Clean up native data associated with an instance.
+     */
+    public synchronized void destroy() {
+        if (peer != 0) {
+            destroy(peer);
+            peer = 0;
+        }
+    }
+
+    /**
+     * Release the associated peer instance.
+     */
+    private native void destroy(long peer);
+
+    /**
+     * Retrieve an iterator over the Symbol elements in this collection.
+     */
+    public java.util.Iterator<Symbol> iterator() {
+        long sym = firstSymbol(peer);
+        if (sym == 0)
+            return (new SymbolIterator(null));
+
+        return (new SymbolIterator(new Symbol(sym)));
+    }
+
+    /**
+     * Retrieve the number of elements in the collection.
+     */
+    public native int size();
+
+    /**
+     * Retrieve C pointer to first symbol in the set.
+     */
+    private native long firstSymbol(long peer);
+}

+ 283 - 0
android/src/main/java/com/rhyme/r_scan/ImageScanHelper.java

@@ -0,0 +1,283 @@
+package com.rhyme.r_scan;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.util.Log;
+
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.RGBLuminanceSource;
+import com.google.zxing.Result;
+import com.google.zxing.common.GlobalHistogramBinarizer;
+import com.google.zxing.common.HybridBinarizer;
+import com.google.zxing.qrcode.QRCodeReader;
+
+import java.io.File;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+
+public class ImageScanHelper extends ContextWrapper {
+
+    private MultiFormatReader reader = new MultiFormatReader();
+    private Executor executor = Executors.newSingleThreadExecutor();
+    private Handler handler = new Handler();
+
+    public ImageScanHelper(Context base) {
+        super(base);
+    }
+
+    private static byte[] yuvs;
+
+    /**
+     * 根据Bitmap的ARGB值生成YUV420SP数据。
+     *
+     * @param inputWidth  image width
+     * @param inputHeight image height
+     * @param scaled      bmp
+     * @return YUV420SP数组
+     */
+    public byte[] getYUV420sp(int inputWidth, int inputHeight, Bitmap scaled) {
+        int[] argb = new int[inputWidth * inputHeight];
+        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);
+        /**
+         * 需要转换成偶数的像素点,否则编码YUV420的时候有可能导致分配的空间大小不够而溢出。
+         */
+        int requiredWidth = inputWidth % 2 == 0 ? inputWidth : inputWidth + 1;
+        int requiredHeight = inputHeight % 2 == 0 ? inputHeight : inputHeight + 1;
+        int byteLength = requiredWidth * requiredHeight * 3 / 2;
+        if (yuvs == null || yuvs.length < byteLength) {
+            yuvs = new byte[byteLength];
+        } else {
+            Arrays.fill(yuvs, (byte) 0);
+        }
+        encodeYUV420SP(yuvs, argb, inputWidth, inputHeight);
+        scaled.recycle();
+        return yuvs;
+    }
+
+    /**
+     * RGB转YUV420sp
+     *
+     * @param yuv420sp inputWidth * inputHeight * 3 / 2
+     * @param argb     inputWidth * inputHeight
+     * @param width    image width
+     * @param height   image height
+     */
+    private void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
+        // 帧图片的像素大小
+        final int frameSize = width * height;
+        // ---YUV数据---
+        int Y, U, V;
+        // Y的index从0开始
+        int yIndex = 0;
+        // UV的index从frameSize开始
+        int uvIndex = frameSize;
+        // ---颜色数据---
+        int R, G, B;
+        int rgbIndex = 0;
+        // ---循环所有像素点,RGB转YUV---
+        for (int j = 0; j < height; j++) {
+            for (int i = 0; i < width; i++) {
+                R = (argb[rgbIndex] & 0xff0000) >> 16;
+                G = (argb[rgbIndex] & 0xff00) >> 8;
+                B = (argb[rgbIndex] & 0xff);
+                //
+                rgbIndex++;
+                // well known RGB to YUV algorithm
+                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
+                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
+                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
+                Y = Math.max(0, Math.min(Y, 255));
+                U = Math.max(0, Math.min(U, 255));
+                V = Math.max(0, Math.min(V, 255));
+                // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
+                // meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other
+                // pixel AND every other scan line.
+                // ---Y---
+                yuv420sp[yIndex++] = (byte) Y;
+                // ---UV---
+                if ((j % 2 == 0) && (i % 2 == 0)) {
+                    //
+                    yuv420sp[uvIndex++] = (byte) V;
+                    //
+                    yuv420sp[uvIndex++] = (byte) U;
+                }
+            }
+        }
+    }
+
+    private Result scanBitmapToResult(Bitmap bitmap) {
+        int height = bitmap.getHeight();
+        int width = bitmap.getWidth();
+        Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
+        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
+        byte[] array = getYUV420sp(width, height, bitmap);
+        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(array,
+                width,
+                height,
+                0,
+                0,
+                width,
+                height,
+                false);
+        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
+        try {
+            return reader.decode(binaryBitmap, hints);
+        } catch (NotFoundException e) {
+//            e.printStackTrace();
+            binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
+            try {
+                return reader.decode(binaryBitmap, hints);
+            } catch (NotFoundException ex) {
+//                ex.printStackTrace();
+            }
+        } finally {
+            bitmap.recycle();
+        }
+        return null;
+    }
+
+    private void scanBitmap(Bitmap bitmap, MethodChannel.Result result) {
+        Result scanResult = scanBitmapToResult(bitmap);
+        if (scanResult != null) {
+            Log.d("result", "analyze: decode:" + scanResult.toString());
+        }
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                result.success(RScanResultUtils.toMap(scanResult));
+            }
+        });
+    }
+
+    public void scanImagePath(MethodCall call, final MethodChannel.Result result) {
+        final String path = call.argument("path");
+        if (path == null) {
+            result.error("1001", "please enter your file path", null);
+            return;
+        }
+        final File file = new File(path);
+        if (file.isFile()) {
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    Bitmap bitmap = BitmapFactory.decodeFile(path);
+                    scanBitmap(bitmap, result);
+                }
+            });
+        } else {
+            result.success("");
+        }
+    }
+
+    public void scanImageUrl(MethodCall call, final MethodChannel.Result result) {
+        final String url = call.argument("url");
+        if (url == null) {
+            result.error("1002", "please enter your url", null);
+            return;
+        }
+        executor.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    URL myUrl = new URL(url);
+                    Bitmap bitmap;
+
+                    if (url.startsWith("https")) {
+                        HttpsURLConnection connection = (HttpsURLConnection) myUrl.openConnection();
+                        connection.setReadTimeout(6 * 60 * 1000);
+                        connection.setConnectTimeout(6 * 60 * 1000);
+                        TrustManager[] tm = {new MyX509TrustManager()};
+                        SSLContext sslContext = SSLContext.getInstance("TLS");
+                        sslContext.init(null, tm, new java.security.SecureRandom());
+                        // 从上述SSLContext对象中得到SSLSocketFactory对象
+                        SSLSocketFactory ssf = sslContext.getSocketFactory();
+                        connection.setSSLSocketFactory(ssf);
+                        connection.connect();
+                        bitmap = BitmapFactory.decodeStream(connection.getInputStream());
+                    } else {
+                        HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
+                        connection.setReadTimeout(6 * 60 * 1000);
+                        connection.setConnectTimeout(6 * 60 * 1000);
+                        connection.connect();
+                        bitmap = BitmapFactory.decodeStream(connection.getInputStream());
+                    }
+                    scanBitmap(bitmap, result);
+                } catch (Exception e) {
+                    Log.d("result", "analyze: error");
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            result.success(null);
+                        }
+                    });
+                }
+            }
+        });
+    }
+
+    public void scanImageMemory(MethodCall call, final MethodChannel.Result result) {
+        final byte[] uint8list = call.argument("uint8list");
+        if (uint8list == null) {
+            result.error("1003", "uint8list is not null", null);
+            return;
+        }
+        executor.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Bitmap bitmap = BitmapFactory.decodeByteArray(uint8list, 0, uint8list.length);
+                    scanBitmap(bitmap, result);
+                } catch (Exception e) {
+                    Log.d("result", "analyze: error");
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            result.success(null);
+                        }
+                    });
+                }
+            }
+        });
+    }
+
+    private class MyX509TrustManager implements X509TrustManager {
+
+        // 检查客户端证书
+        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+        }
+
+        // 检查服务器端证书
+        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+        }
+
+        // 返回受信任的X509证书数组
+        public X509Certificate[] getAcceptedIssuers() {
+            return null;
+        }
+    }
+}

+ 75 - 0
android/src/main/java/com/rhyme/r_scan/MethodCallHandlerImpl.java

@@ -0,0 +1,75 @@
+package com.rhyme.r_scan;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+import com.rhyme.r_scan.RScanCamera.RScanCameraMethodHandler;
+import com.rhyme.r_scan.RScanCamera.RScanPermissions;
+import com.rhyme.r_scan.RScanView.RScanViewPlugin;
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.platform.PlatformViewRegistry;
+import io.flutter.view.TextureRegistry;
+
+public class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
+    private ImageScanHelper scanHelper;
+    private final Activity activity;
+    private final BinaryMessenger messenger;
+    private final RScanPermissions cameraPermissions;
+    private final RScanPermissions.PermissionsRegistry permissionsRegistry;
+    private final TextureRegistry textureRegistry;
+    private final MethodChannel methodChannel;
+    private final PlatformViewRegistry platformViewRegistry;
+
+    public MethodCallHandlerImpl(
+            Activity activity,
+            BinaryMessenger messenger,
+            RScanPermissions cameraPermissions,
+            RScanPermissions.PermissionsRegistry permissionsAdder,
+            TextureRegistry textureRegistry,
+            PlatformViewRegistry platformViewRegistry) {
+        this.activity = activity;
+        this.messenger = messenger;
+        this.cameraPermissions = cameraPermissions;
+        this.permissionsRegistry = permissionsAdder;
+        this.textureRegistry = textureRegistry;
+        this.platformViewRegistry = platformViewRegistry;
+
+        scanHelper = new ImageScanHelper(activity);
+        methodChannel = new MethodChannel(messenger, "com.rhyme_lph/r_scan");
+        methodChannel.setMethodCallHandler(this);
+
+        //注册老方式
+        RScanViewPlugin.registerWith(this.platformViewRegistry, this.messenger);
+
+        //注册新的方式
+        new RScanCameraMethodHandler(
+                activity,
+                messenger,
+                cameraPermissions,
+                permissionsAdder,
+                textureRegistry
+        );
+
+    }
+
+    void stopListening() {
+        methodChannel.setMethodCallHandler(null);
+    }
+
+    @Override
+    public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
+        if (call.method.equals("scanImagePath")) {
+            scanHelper.scanImagePath(call, result);
+        } else if (call.method.equals("scanImageUrl")) {
+            scanHelper.scanImageUrl(call, result);
+        } else if (call.method.equals("scanImageMemory")) {
+            scanHelper.scanImageMemory(call, result);
+        } else {
+            result.notImplemented();
+        }
+    }
+}

+ 95 - 0
android/src/main/java/com/rhyme/r_scan/RScanCamera/CameraUtils.java

@@ -0,0 +1,95 @@
+package com.rhyme.r_scan.RScanCamera;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.media.CamcorderProfile;
+import android.util.Size;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CameraUtils {
+
+    public static List<Map<String, Object>> getAvailableCameras(Activity activity)
+            throws CameraAccessException {
+        CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+        String[] cameraNames = cameraManager.getCameraIdList();
+        List<Map<String, Object>> cameras = new ArrayList<>();
+        for (String cameraName : cameraNames) {
+            HashMap<String, Object> details = new HashMap<>();
+            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName);
+            details.put("name", cameraName);
+
+            int lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
+            switch (lensFacing) {
+                case CameraMetadata.LENS_FACING_FRONT:
+                    details.put("lensFacing", "front");
+                    break;
+                case CameraMetadata.LENS_FACING_BACK:
+                    details.put("lensFacing", "back");
+                    break;
+                case CameraMetadata.LENS_FACING_EXTERNAL:
+                    details.put("lensFacing", "external");
+                    break;
+            }
+            cameras.add(details);
+        }
+        return cameras;
+    }
+
+    static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset(
+            String cameraName, RScanCamera.ResolutionPreset preset) {
+        int cameraId = Integer.parseInt(cameraName);
+        switch (preset) {
+            // All of these cases deliberately fall through to get the best available profile.
+            case max:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
+                }
+            case ultraHigh:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_2160P);
+                }
+            case veryHigh:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_1080P);
+                }
+            case high:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_720P);
+                }
+            case medium:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_480P);
+                }
+            case low:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_QVGA);
+                }
+            default:
+                if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW)) {
+                    return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_LOW);
+                } else {
+                    throw new IllegalArgumentException(
+                            "No capture session available for current capture session.");
+                }
+        }
+    }
+
+    static Size computeBestPreviewSize(String cameraName, RScanCamera.ResolutionPreset preset) {
+        if (preset.ordinal() > RScanCamera.ResolutionPreset.high.ordinal()) {
+            preset = RScanCamera.ResolutionPreset.high;
+        }
+
+        CamcorderProfile profile =
+                getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset);
+        return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
+    }
+
+}

+ 475 - 0
android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanCamera.java

@@ -0,0 +1,475 @@
+package com.rhyme.r_scan.RScanCamera;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.media.Image;
+import android.media.ImageReader;
+import android.media.MediaRecorder;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.Result;
+import com.google.zxing.common.GlobalHistogramBinarizer;
+import com.google.zxing.common.HybridBinarizer;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+
+import cn.bertsir.zbar.Qr.Config;
+import cn.bertsir.zbar.Qr.ImageScanner;
+import cn.bertsir.zbar.Qr.Symbol;
+import cn.bertsir.zbar.Qr.SymbolSet;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.view.TextureRegistry;
+
+import static com.rhyme.r_scan.RScanCamera.CameraUtils.computeBestPreviewSize;
+
+class RScanCamera {
+    private final String TAG = "RScanCamera";
+
+    private final TextureRegistry.SurfaceTextureEntry flutterTexture;
+    private final CameraManager cameraManager;
+    private final String cameraName;
+    private final Size previewSize;
+
+    private CameraDevice cameraDevice;
+    private CameraCaptureSession cameraCaptureSession;
+    private ImageReader imageStreamReader;
+    private MultiFormatReader reader = new MultiFormatReader();
+    private RScanMessenger rScanMessenger;
+    private CaptureRequest.Builder captureRequestBuilder;
+    private boolean isPlay = true;
+    private long lastCurrentTimestamp = 0L;//最后一次的扫描
+    private Handler handler = new Handler();
+    private Executor executor = Executors.newSingleThreadExecutor();
+    private boolean isAutoOpenFlash = false;
+
+    // 上次环境亮度记录的索引
+    private int mAmbientBrightnessDarkIndex = 0;
+    // 环境亮度历史记录的数组,255 是代表亮度最大值
+    private static final long[] AMBIENT_BRIGHTNESS_DARK_LIST = new long[]{255, 255, 255, 255};
+    // 亮度低的阀值
+    private static final int AMBIENT_BRIGHTNESS_DARK = 600;
+
+    void startScan() {
+        isPlay = true;
+    }
+
+    void stopScan() {
+        isPlay = false;
+    }
+
+    void enableTorch(boolean b) throws CameraAccessException {
+        if (b) {
+            captureRequestBuilder.set(
+                    CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
+            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
+
+        } else {
+            captureRequestBuilder.set(
+                    CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
+            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
+
+        }
+    }
+
+    void setAutoFlash(boolean b) {
+        isAutoOpenFlash = b;
+    }
+
+
+    boolean isTorchOn() {
+        try {
+            return captureRequestBuilder.get(CaptureRequest.FLASH_MODE) != CaptureRequest.FLASH_MODE_OFF;
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    // Mirrors camera.dart
+    public enum ResolutionPreset {
+        low,
+        medium,
+        high,
+        veryHigh,
+        ultraHigh,
+        max,
+    }
+
+    RScanCamera(
+            final Activity activity,
+            final TextureRegistry.SurfaceTextureEntry flutterTexture,
+            final RScanMessenger rScanMessenger,
+            final String cameraName,
+            final String resolutionPreset) {
+        if (activity == null) {
+            throw new IllegalStateException("No activity available!");
+        }
+
+        this.cameraName = cameraName;
+        this.flutterTexture = flutterTexture;
+        this.rScanMessenger = rScanMessenger;
+        this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+
+        //获取预览大小
+        ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset);
+        previewSize = computeBestPreviewSize(cameraName, preset);
+
+    }
+
+
+    @SuppressLint("MissingPermission")
+    void open(@NonNull final MethodChannel.Result result) throws CameraAccessException {
+
+        // Used to steam image byte data to dart side.
+        imageStreamReader =
+                ImageReader.newInstance(
+                        previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
+
+
+        cameraManager.openCamera(
+                cameraName,
+                new CameraDevice.StateCallback() {
+                    @Override
+                    public void onOpened(@NonNull CameraDevice device) {
+                        cameraDevice = device;
+                        try {
+                            startPreview();
+                        } catch (CameraAccessException e) {
+                            result.error("CameraAccess", e.getMessage(), null);
+                            close();
+                            return;
+                        }
+                        Map<String, Object> reply = new HashMap<>();
+                        reply.put("textureId", flutterTexture.id());
+                        reply.put("previewWidth", previewSize.getWidth());
+                        reply.put("previewHeight", previewSize.getHeight());
+                        result.success(reply);
+                    }
+
+                    @Override
+                    public void onClosed(@NonNull CameraDevice camera) {
+//                        rScanMessenger.sendCameraClosingEvent();
+                        super.onClosed(camera);
+                    }
+
+                    @Override
+                    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
+                        close();
+//                        rScanMessenger.send(DartMessenger.EventType.ERROR, "The camera was disconnected.");
+                    }
+
+                    @Override
+                    public void onError(@NonNull CameraDevice cameraDevice, int errorCode) {
+                        close();
+//                        String errorDescription;
+//                        switch (errorCode) {
+//                            case ERROR_CAMERA_IN_USE:
+//                                errorDescription = "The camera device is in use already.";
+//                                break;
+//                            case ERROR_MAX_CAMERAS_IN_USE:
+//                                errorDescription = "Max cameras in use";
+//                                break;
+//                            case ERROR_CAMERA_DISABLED:
+//                                errorDescription = "The camera device could not be opened due to a device policy.";
+//                                break;
+//                            case ERROR_CAMERA_DEVICE:
+//                                errorDescription = "The camera device has encountered a fatal error";
+//                                break;
+//                            case ERROR_CAMERA_SERVICE:
+//                                errorDescription = "The camera service has encountered a fatal error.";
+//                                break;
+//                            default:
+//                                errorDescription = "Unknown camera error";
+//                        }
+//                        rScanMessenger.send(DartMessenger.EventType.ERROR, errorDescription);
+                    }
+                },
+                null);
+
+    }
+
+
+    private void createCaptureSession(
+            Surface... surfaces)
+            throws CameraAccessException {
+        // Close any existing capture session.
+        closeCaptureSession();
+
+        // Create a new capture builder.
+        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+
+        // Build Flutter surface to render to
+        SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture();
+        surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
+        Surface flutterSurface = new Surface(surfaceTexture);
+        captureRequestBuilder.addTarget(flutterSurface);
+
+        List<Surface> remainingSurfaces = Arrays.asList(surfaces);
+        // If it is not preview mode, add all surfaces as targets.
+        for (Surface surface : remainingSurfaces) {
+            captureRequestBuilder.addTarget(surface);
+        }
+
+        // Prepare the callback
+        CameraCaptureSession.StateCallback callback =
+                new CameraCaptureSession.StateCallback() {
+                    @Override
+                    public void onConfigured(@NonNull CameraCaptureSession session) {
+                        try {
+                            if (cameraDevice == null) {
+//                                rScanMessenger.send(
+//                                        DartMessenger.EventType.ERROR, "The camera was closed during configuration.");
+                                return;
+                            }
+                            cameraCaptureSession = session;
+//                            captureRequestBuilder.set(
+//                                    CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+                            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
+                        } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) {
+//                            rScanMessenger.send(DartMessenger.EventType.ERROR, e.getMessage());
+                        }
+                    }
+
+                    @Override
+                    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
+//                        rScanMessenger.send(
+//                                DartMessenger.EventType.ERROR, "Failed to configure camera session.");
+                    }
+                };
+
+        // Collect all surfaces we want to render to.
+        List<Surface> surfaceList = new ArrayList<>();
+        surfaceList.add(flutterSurface);
+        surfaceList.addAll(remainingSurfaces);
+        // Start the session
+        cameraDevice.createCaptureSession(surfaceList, callback, null);
+    }
+
+
+    private void startPreview() throws CameraAccessException {
+        startPreviewWithImageStream();
+    }
+
+    private void setAutoOpenFlash(int width, int height, byte[] array) {
+        if (!isAutoOpenFlash) return;
+        //像素点的总亮度
+        long pixelLightCount = 0L;
+        //像素点总数
+        long pixelCount = width * height;
+        //采集步长
+        int step = 10;
+//        if(Math.abs(array.length - pixelCount * 1.5f) < 0.00001f){
+        for (int i = 0; i < pixelCount; i++) {
+            pixelLightCount += (long) array[i] & 0xFFL;
+        }
+        long cameraLight = pixelLightCount / (pixelCount / step);
+        int lightSize = AMBIENT_BRIGHTNESS_DARK_LIST.length;
+        AMBIENT_BRIGHTNESS_DARK_LIST[mAmbientBrightnessDarkIndex = mAmbientBrightnessDarkIndex % lightSize] = cameraLight;
+        mAmbientBrightnessDarkIndex++;
+        boolean isDarkEnv = true;
+        // 判断在时间范围 AMBIENT_BRIGHTNESS_WAIT_SCAN_TIME * lightSize 内是不是亮度过暗
+        for (long ambientBrightness : AMBIENT_BRIGHTNESS_DARK_LIST) {
+            if (ambientBrightness > AMBIENT_BRIGHTNESS_DARK) {
+                isDarkEnv = false;
+                break;
+            }
+        }
+        Log.d(TAG, "decodeImage: light:" + cameraLight);
+        if (isDarkEnv && !isTorchOn()) {
+            try {
+                enableTorch(Boolean.TRUE);
+            } catch (CameraAccessException e) {
+                e.printStackTrace();
+            }
+        }
+//        }
+    }
+
+    ///  这是唯一修改的地方
+    private String decodeByZBar(Image image){
+        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+        byte[] array = new byte[buffer.remaining()];
+        buffer.get(array);
+
+        Size size = new Size(image.getWidth(), image.getHeight());
+        cn.bertsir.zbar.Qr.Image barcode = new cn.bertsir.zbar.Qr.Image(size.getWidth(), size.getHeight(), "Y800");
+
+        barcode.setData(array);
+
+        ImageScanner imageScanner = new ImageScanner();
+        imageScanner.setConfig(Symbol.NONE, Config.X_DENSITY, 3);
+        imageScanner.setConfig(Symbol.NONE, Config.Y_DENSITY, 3);
+
+        int result = imageScanner.scanImage(barcode);
+
+        String resultStr = null;
+        int resultType = -1;
+        if (result != 0) {
+            SymbolSet symSet = imageScanner.getResults();
+            for (Symbol sym : symSet) {
+                resultStr = sym.getData();
+                resultType = sym.getType();
+            }
+        }
+
+        if (!TextUtils.isEmpty(resultStr)) {
+            return resultStr;
+        }else{
+            return null;
+        }
+    }
+
+
+    private Result decodeImage(Image image) {
+        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+        byte[] array = new byte[buffer.remaining()];
+        buffer.get(array);
+
+        //图片宽度
+        int width = image.getWidth();
+        //图片高度
+        int height = image.getHeight();
+
+        setAutoOpenFlash(width, height, array);
+
+        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(array,
+                width,
+                height,
+                0,
+                0,
+                width,
+                height,
+                false);
+        BinaryBitmap binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
+        try {
+            return reader.decode(binaryBitmap);
+        } catch (Exception e) {
+            binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
+            try {
+                return reader.decode(binaryBitmap);
+            } catch (NotFoundException ex) {
+//                ex.printStackTrace();
+            }
+//            Log.d(TAG, "decodeImage: rotate45");
+//            binaryBitmap = binaryBitmap.rotateCounterClockwise45();
+//            try {
+//                return reader.decodeWithState(binaryBitmap);
+//            } catch (NotFoundException ex) {
+//                Log.d(TAG, "decodeImage: rotate90");
+//                //          Log.d(TAG, "analyze: error ");
+//                binaryBitmap = binaryBitmap.rotateCounterClockwise45();
+//                try {
+//                    return reader.decodeWithState(binaryBitmap);
+//                } catch (NotFoundException ex2) {
+//                    //          Log.d(TAG, "analyze: error ");
+//
+//                }
+//            }
+//          Log.d(TAG, "analyze: error ");
+        } finally {
+            buffer.clear();
+            reader.reset();
+        }
+        return null;
+    }
+
+
+    private void startPreviewWithImageStream()
+            throws CameraAccessException {
+        createCaptureSession(imageStreamReader.getSurface());
+
+        imageStreamReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
+            @Override
+            public void onImageAvailable(ImageReader imageReader) {
+                executor.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        long currentTimestamp = System.currentTimeMillis();
+                        if (currentTimestamp - lastCurrentTimestamp >= 1L && isPlay == Boolean.TRUE) {
+                            Image image = imageReader.acquireLatestImage();
+                            if (image == null) return;
+                            if (ImageFormat.YUV_420_888 != image.getFormat()) {
+                                Log.d(TAG, "analyze: " + image.getFormat());
+                                return;
+                            }
+//                            final Result result = decodeImage(image);
+
+                            // 修复添加的代码
+                            final String result = decodeByZBar(image);
+
+                            if (result != null) {
+                                handler.post(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        rScanMessenger.send(result);
+                                    }
+                                });
+                            }
+                            lastCurrentTimestamp = currentTimestamp;
+                            image.close();
+                        }
+                    }
+
+                });
+            }
+        }, handler);
+
+    }
+
+
+    private void closeCaptureSession() {
+        if (cameraCaptureSession != null) {
+            cameraCaptureSession.close();
+            cameraCaptureSession = null;
+        }
+    }
+
+    void close() {
+        closeCaptureSession();
+
+        if (cameraDevice != null) {
+            cameraDevice.close();
+            cameraDevice = null;
+        }
+        if (imageStreamReader != null) {
+            imageStreamReader.close();
+            imageStreamReader = null;
+        }
+    }
+
+    void dispose() {
+        close();
+        flutterTexture.release();
+    }
+
+}

+ 160 - 0
android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanCameraMethodHandler.java

@@ -0,0 +1,160 @@
+package com.rhyme.r_scan.RScanCamera;
+
+
+import android.app.Activity;
+import android.hardware.camera2.CameraAccessException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.CameraX;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.view.TextureRegistry;
+
+public class RScanCameraMethodHandler implements MethodChannel.MethodCallHandler {
+    private static final String scanViewType = "com.rhyme_lph/r_scan_camera";
+    private final TextureRegistry textureRegistry;
+    private final Activity activity;
+    private final RScanPermissions rScanPermissions;
+    private final RScanPermissions.PermissionsRegistry permissionsRegistry;
+    private final BinaryMessenger messenger;
+    private RScanCamera rScanCamera;
+
+
+    public RScanCameraMethodHandler(
+            Activity activity,
+            BinaryMessenger messenger,
+            RScanPermissions rScanPermissions,
+            RScanPermissions.PermissionsRegistry permissionsAdder,
+            TextureRegistry textureRegistry) {
+        this.activity = activity;
+        this.messenger = messenger;
+
+        this.rScanPermissions = rScanPermissions;
+        this.permissionsRegistry = permissionsAdder;
+        this.textureRegistry = textureRegistry;
+
+        MethodChannel methodChannel = new MethodChannel(messenger, scanViewType + "/method");
+        methodChannel.setMethodCallHandler(this);
+
+//        Log.d(TAG, "FlutterRScanView: " + outMetrics.toString());
+//        mPreview = buildPreView(outMetrics.widthPixels, outMetrics.heightPixels);
+//        CameraX.bindToLifecycle(this, mPreview, buildImageAnalysis());
+
+
+    }
+
+    @Override
+    public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
+        switch (call.method) {
+            case "availableCameras":
+                try {
+                    result.success(CameraUtils.getAvailableCameras(activity));
+                } catch (Exception e) {
+                    handleException(e, result);
+                }
+                break;
+            case "initialize":
+                if (rScanCamera != null) {
+                    rScanCamera.close();
+                }
+                //请求权限
+                rScanPermissions.requestPermissions(
+                        activity,
+                        permissionsRegistry,
+                        (String errCode, String errDesc) -> {
+                            if (errCode == null) {
+                                try {
+                                    instantiateCamera(call, result);
+                                } catch (Exception e) {
+                                    handleException(e, result);
+                                }
+                            } else {
+                                result.error(errCode, errDesc, null);
+                            }
+                        });
+                break;
+            case "startScan":
+                if (rScanCamera != null) {
+                    rScanCamera.startScan();
+                }
+                result.success(null);
+                break;
+            case "stopScan":
+                if (rScanCamera != null) {
+                    rScanCamera.stopScan();
+                }
+                result.success(null);
+                break;
+            case "setAutoFlashMode":
+                Boolean isAuto = call.<Boolean>argument("isAuto");
+                if (rScanCamera != null) {
+                    rScanCamera.setAutoFlash(isAuto == Boolean.TRUE);
+                    result.success(true);
+                } else {
+                    result.success(true);
+                }
+                break;
+            case "setFlashMode":
+                Boolean isOpen = call.<Boolean>argument("isOpen");
+                if (rScanCamera != null) {
+                    try {
+                        rScanCamera.enableTorch(isOpen == Boolean.TRUE);
+                    } catch (CameraAccessException e) {
+                        e.printStackTrace();
+                    }
+                    result.success(true);
+                } else {
+                    result.success(true);
+                }
+                break;
+            case "getFlashMode":
+                if (rScanCamera != null) {
+                    result.success(rScanCamera.isTorchOn());
+                } else {
+                    result.success(false);
+                }
+                break;
+            case "dispose": {
+                if (rScanCamera != null) {
+                    rScanCamera.dispose();
+                }
+                result.success(null);
+                break;
+            }
+            default:
+                result.notImplemented();
+                break;
+        }
+    }
+
+    //初始化相机
+    private void instantiateCamera(MethodCall call, MethodChannel.Result result) throws CameraAccessException {
+        String cameraName = call.argument("cameraName");
+        String resolutionPreset = call.argument("resolutionPreset");
+        TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture =
+                textureRegistry.createSurfaceTexture();
+
+        RScanMessenger rScanMessenger = new RScanMessenger(messenger, flutterSurfaceTexture.id());
+
+        rScanCamera = new RScanCamera(activity, flutterSurfaceTexture, rScanMessenger, cameraName, resolutionPreset);
+        rScanCamera.open(result);
+    }
+
+    // We move catching CameraAccessException out of onMethodCall because it causes a crash
+    // on plugin registration for sdks incompatible with Camera2 (< 21). We want this plugin to
+    // to be able to compile with <21 sdks for apps that want the camera and support earlier version.
+    @SuppressWarnings("ConstantConditions")
+    private void handleException(Exception exception, MethodChannel.Result result) {
+        if (exception instanceof CameraAccessException) {
+            result.error("CameraAccess", exception.getMessage(), null);
+        }
+        throw (RuntimeException) exception;
+    }
+
+}

+ 49 - 0
android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanMessenger.java

@@ -0,0 +1,49 @@
+package com.rhyme.r_scan.RScanCamera;
+
+import androidx.annotation.Nullable;
+
+import com.google.zxing.Result;
+import com.rhyme.r_scan.RScanResultUtils;
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.EventChannel;
+
+class RScanMessenger {
+    @Nullable
+    private EventChannel.EventSink eventSink;
+    private static final String scanViewType = "com.rhyme_lph/r_scan_camera";
+
+
+    RScanMessenger(BinaryMessenger messenger, long eventChannelId) {
+        new EventChannel(messenger, scanViewType+"_" + eventChannelId+"/event")
+                .setStreamHandler(
+                        new EventChannel.StreamHandler() {
+                            @Override
+                            public void onListen(Object arguments, EventChannel.EventSink sink) {
+                                eventSink = sink;
+                            }
+
+                            @Override
+                            public void onCancel(Object arguments) {
+                                eventSink = null;
+                            }
+                        });
+    }
+
+
+    void send(Result decode) {
+        if (eventSink == null) {
+            return;
+        }
+        eventSink.success(RScanResultUtils.toMap(decode));
+    }
+
+    // 修复所添加的代码
+    void send(String result){
+        if (eventSink == null) {
+            return;
+        }
+        eventSink.success(RScanResultUtils.toMap(result));
+    }
+
+}

+ 78 - 0
android/src/main/java/com/rhyme/r_scan/RScanCamera/RScanPermissions.java

@@ -0,0 +1,78 @@
+package com.rhyme.r_scan.RScanCamera;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener;
+
+public final class RScanPermissions {
+    public interface PermissionsRegistry {
+        void addListener(RequestPermissionsResultListener handler);
+    }
+
+    interface ResultCallback {
+        void onResult(String errorCode, String errorDescription);
+    }
+
+    private static final int CAMERA_REQUEST_ID = 9796;
+    private boolean ongoing = false;
+
+    void requestPermissions(
+            Activity activity,
+            PermissionsRegistry permissionsRegistry,
+            final ResultCallback callback) {
+        if (ongoing) {
+            callback.onResult("cameraPermission", "Camera permission request ongoing");
+        }
+        if (!hasCameraPermission(activity)) {
+            permissionsRegistry.addListener(
+                    new RScanRequestPermissionsListener(new ResultCallback() {
+                        @Override
+                        public void onResult(String errorCode, String errorDescription) {
+                            ongoing = false;
+                            callback.onResult(errorCode, errorDescription);
+                        }
+                    }));
+            ongoing = true;
+            ActivityCompat.requestPermissions(
+                    activity, new String[]{permission.CAMERA},
+                    CAMERA_REQUEST_ID);
+        } else {
+            // Permissions already exist. Call the callback with success.
+            callback.onResult(null, null);
+        }
+    }
+
+    private boolean hasCameraPermission(Activity activity) {
+        return ContextCompat.checkSelfPermission(activity, permission.CAMERA)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+
+    private static class RScanRequestPermissionsListener
+            implements RequestPermissionsResultListener {
+
+        final ResultCallback callback;
+
+        private RScanRequestPermissionsListener(ResultCallback callback) {
+            this.callback = callback;
+        }
+
+        @Override
+        public boolean onRequestPermissionsResult(int id, String[] permissions, int[] grantResults) {
+            if (id == CAMERA_REQUEST_ID) {
+                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+                    callback.onResult("rScanPermission", "MediaRecorderCamera permission not granted");
+                } else {
+                    callback.onResult(null, null);
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+}

+ 120 - 0
android/src/main/java/com/rhyme/r_scan/RScanPlugin.java

@@ -0,0 +1,120 @@
+package com.rhyme.r_scan;
+
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+import com.rhyme.r_scan.RScanCamera.RScanPermissions;
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.embedding.engine.plugins.activity.ActivityAware;
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.PluginRegistry.Registrar;
+import io.flutter.plugin.platform.PlatformViewRegistry;
+import io.flutter.view.TextureRegistry;
+
+/**
+ * RScanPlugin
+ */
+//public class RScanPlugin implements MethodChannel.MethodCallHandler {
+//    private ImageScanHelper scanHelper;
+//
+//    private RScanPlugin(Registrar registrar) {
+//        scanHelper = new ImageScanHelper(registrar.context());
+//    }
+//
+//    public static void registerWith(Registrar registrar) {
+//        final MethodChannel channel = new MethodChannel(registrar.messenger(), "r_scan");
+//        channel.setMethodCallHandler(new RScanPlugin(registrar));
+//        RScanViewPlugin.registerWith(registrar);
+//    }
+//
+//    @Override
+//    public void onMethodCall(MethodCall call, Result result) {
+//        if (call.method.equals("scanImagePath")) {
+//            scanHelper.scanImagePath(call,result);
+//        } else if(call.method.equals("scanImageUrl")){
+//            scanHelper.scanImageUrl(call,result);
+//        } else if(call.method.equals("scanImageMemory")){
+//            scanHelper.scanImageMemory(call,result);
+//        } else {
+//            result.notImplemented();
+//        }
+//    }
+//}
+
+/**
+ * RScanPlugin
+ */
+public class RScanPlugin implements FlutterPlugin, ActivityAware {
+    private MethodCallHandlerImpl methodCallHandler;
+    private FlutterPluginBinding flutterPluginBinding;
+
+
+    public static void registerWith(Registrar registrar) {
+        RScanPlugin plugin = new RScanPlugin();
+        plugin.maybeStartListening(
+                registrar.activity(),
+                registrar.messenger(),
+                registrar::addRequestPermissionsResultListener,
+                registrar.view(), registrar.platformViewRegistry());
+
+    }
+
+    private void maybeStartListening(
+            Activity activity,
+            BinaryMessenger messenger,
+            RScanPermissions.PermissionsRegistry permissionsRegistry,
+            TextureRegistry textureRegistry, PlatformViewRegistry platformViewRegistry) {
+        methodCallHandler =
+                new MethodCallHandlerImpl(
+                        activity, messenger, new RScanPermissions(), permissionsRegistry, textureRegistry, platformViewRegistry);
+    }
+
+    @Override
+    public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
+        this.flutterPluginBinding = binding;
+
+    }
+
+    @Override
+    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
+        this.flutterPluginBinding = null;
+
+    }
+
+    @Override
+    public void onAttachedToActivity(ActivityPluginBinding binding) {
+
+        maybeStartListening(
+                binding.getActivity(),
+                flutterPluginBinding.getBinaryMessenger(),
+                binding::addRequestPermissionsResultListener,
+                flutterPluginBinding.getTextureRegistry(),
+                flutterPluginBinding.getPlatformViewRegistry());
+    }
+
+    @Override
+    public void onDetachedFromActivityForConfigChanges() {
+        onDetachedFromActivity();
+
+    }
+
+    @Override
+    public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
+        onAttachedToActivity(binding);
+
+    }
+
+    @Override
+    public void onDetachedFromActivity() {
+        if (methodCallHandler == null) {
+            // Could be on too low of an SDK to have started listening originally.
+            return;
+        }
+        methodCallHandler.stopListening();
+        methodCallHandler = null;
+    }
+}

+ 42 - 0
android/src/main/java/com/rhyme/r_scan/RScanResultUtils.java

@@ -0,0 +1,42 @@
+package com.rhyme.r_scan;
+
+import com.google.zxing.Result;
+import com.google.zxing.ResultPoint;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RScanResultUtils {
+
+
+    public static Map<String,Object> toMap(Result result){
+        if(result == null) return  null;
+        Map<String,Object> data = new HashMap<>();
+        data.put("message",result.getText());
+        data.put("type",result.getBarcodeFormat().ordinal());
+        if(result.getResultPoints()!=null){
+            List<Map<String,Object>>  resultPoints = new ArrayList<>();
+            for (ResultPoint point :result.getResultPoints()){
+                Map<String,Object> pointMap = new HashMap<>();
+                pointMap.put("X",point.getX());
+                pointMap.put("Y",point.getY());
+                resultPoints.add(pointMap);
+            }
+            data.put("points",resultPoints);
+        }
+        return  data;
+    }
+
+
+    public static Map<String, Object> toMap(String result) {
+        if (result == null) return null;
+        Map<String, Object> data = new HashMap<>();
+        data.put("message", result);
+        data.put("type", null);
+        data.put("points", new ArrayList<>());
+
+        return data;
+    }
+}

+ 206 - 0
android/src/main/java/com/rhyme/r_scan/RScanView/FlutterRScanView.java

@@ -0,0 +1,206 @@
+package com.rhyme.r_scan.RScanView;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Rational;
+import android.util.Size;
+import android.view.TextureView;
+import android.view.View;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.CameraX;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.ImageAnalysisConfig;
+import androidx.camera.core.ImageProxy;
+import androidx.camera.core.Preview;
+import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.SessionConfig;
+import androidx.camera.core.UseCase;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.Result;
+import com.google.zxing.common.HybridBinarizer;
+import com.rhyme.r_scan.RScanResultUtils;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.platform.PlatformView;
+
+public class FlutterRScanView implements PlatformView, LifecycleOwner, EventChannel.StreamHandler, MethodChannel.MethodCallHandler {
+    private static final String TAG = "FlutterRScanView";
+
+    private LifecycleRegistry lifecycleRegistry;
+    private TextureView textureView;
+    private boolean isPlay;
+    private static final String scanViewType = "com.rhyme_lph/r_scan_view";
+    private EventChannel.EventSink eventSink;
+    private long lastCurrentTimestamp = 0L;//最后一次的扫描
+    private Preview mPreview;
+
+    FlutterRScanView(Context context, BinaryMessenger messenger, int i, Object o) {
+        Map map = (Map) o;
+        Boolean _isPlay = (Boolean) map.get("isPlay");
+        isPlay = _isPlay == Boolean.TRUE;
+
+        new EventChannel(messenger, scanViewType + "_" + i + "/event")
+                .setStreamHandler(this);
+        MethodChannel methodChannel = new MethodChannel(messenger, scanViewType + "_" + i + "/method");
+        methodChannel.setMethodCallHandler(this);
+        textureView = new TextureView(context);
+        lifecycleRegistry = new LifecycleRegistry(this);
+        DisplayMetrics outMetrics = new DisplayMetrics();
+
+        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        manager.getDefaultDisplay().getMetrics(outMetrics);
+        Log.d(TAG, "FlutterRScanView: " + outMetrics.toString());
+        mPreview = buildPreView(outMetrics.widthPixels, outMetrics.heightPixels);
+        CameraX.bindToLifecycle(this, mPreview, buildImageAnalysis());
+
+    }
+
+    @Override
+    public View getView() {
+        if (lifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED) {
+            lifecycleRegistry.markState(Lifecycle.State.RESUMED);
+        }
+        return textureView;
+    }
+
+    @Override
+    public void dispose() {
+        Log.d("CameraX", "dispose");
+        lifecycleRegistry.markState(Lifecycle.State.DESTROYED);
+        CameraX.unbindAll();
+    }
+
+    @Override
+    public void onListen(Object o, EventChannel.EventSink eventSink) {
+        this.eventSink = eventSink;
+    }
+
+    @Override
+    public void onMethodCall(MethodCall methodCall, @NonNull MethodChannel.Result result) {
+        switch (methodCall.method) {
+            case "startScan":
+                isPlay = true;
+                result.success(null);
+                break;
+            case "stopScan":
+                isPlay = false;
+                result.success(null);
+                break;
+            case "setFlashMode":
+                Boolean isOpen = methodCall.<Boolean>argument("isOpen");
+                mPreview.enableTorch(isOpen == Boolean.TRUE);
+                result.success(true);
+                break;
+            case "getFlashMode":
+                result.success(mPreview.isTorchOn());
+                break;
+            default:
+                result.notImplemented();
+                break;
+        }
+    }
+
+    @Override
+    public void onCancel(Object o) {
+        Log.d("CameraX", "onCancel");
+        eventSink = null;
+    }
+
+    @NonNull
+    @Override
+    public Lifecycle getLifecycle() {
+        Log.d("CameraX", "getLifecycle" + lifecycleRegistry.getCurrentState().name());
+        return lifecycleRegistry;
+    }
+
+    private Preview buildPreView(int width, int height) {
+        PreviewConfig config = new PreviewConfig.Builder()
+                .setTargetAspectRatio(Rational.parseRational(width + ":" + height))
+                .setTargetResolution(new Size(width, height))
+                .build();
+        Preview preview = new Preview(config);
+        preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
+            @Override
+            public void onUpdated(@NonNull Preview.PreviewOutput output) {
+                if (textureView != null) {
+                    textureView.setSurfaceTexture(output.getSurfaceTexture());
+                }
+            }
+        });
+        return preview;
+    }
+
+    private UseCase buildImageAnalysis() {
+        ImageAnalysisConfig config = new ImageAnalysisConfig.Builder()
+                .setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
+                .build();
+
+        ImageAnalysis analysis = new ImageAnalysis(config);
+        analysis.setAnalyzer(new QRCodeAnalyzer());
+
+        return analysis;
+    }
+
+
+    private class QRCodeAnalyzer implements ImageAnalysis.Analyzer {
+        private static final String TAG = "QRCodeAnalyzer";
+        private MultiFormatReader reader = new MultiFormatReader();
+
+        @Override
+        public void analyze(ImageProxy image, int rotationDegrees) {
+            long currentTimestamp = System.currentTimeMillis();
+            if (currentTimestamp - lastCurrentTimestamp >= 1L && isPlay == Boolean.TRUE) {
+                if (ImageFormat.YUV_420_888 != image.getFormat()) {
+                    Log.d(TAG, "analyze: " + image.getFormat());
+                    return;
+                }
+                ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+                byte[] array = new byte[buffer.remaining()];
+                buffer.get(array);
+                int height = image.getHeight();
+                int width = image.getWidth();
+                PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(array,
+                        width,
+                        height,
+                        0,
+                        0,
+                        width,
+                        height,
+                        false);
+                BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
+                try {
+                    final Result decode = reader.decode(binaryBitmap);
+                    if (decode != null && eventSink != null) {
+                        textureView.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                if (eventSink != null)
+                                    eventSink.success(RScanResultUtils.toMap(decode));
+                            }
+                        });
+                    }
+                } catch (Exception e) {
+                    buffer.clear();
+//                    Log.d(TAG, "analyze: error ");
+                }
+                lastCurrentTimestamp = currentTimestamp;
+            }
+        }
+    }
+}

+ 22 - 0
android/src/main/java/com/rhyme/r_scan/RScanView/RScanViewFactory.java

@@ -0,0 +1,22 @@
+package com.rhyme.r_scan.RScanView;
+
+import android.content.Context;
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.StandardMessageCodec;
+import io.flutter.plugin.platform.PlatformView;
+import io.flutter.plugin.platform.PlatformViewFactory;
+
+public class RScanViewFactory extends PlatformViewFactory {
+    private final BinaryMessenger messenger;
+
+    RScanViewFactory(BinaryMessenger messenger) {
+        super(StandardMessageCodec.INSTANCE);
+        this.messenger=messenger;
+    }
+
+    @Override
+    public PlatformView create(Context context, int i, Object o) {
+        return new FlutterRScanView(context,messenger,i,o);
+    }
+}

+ 12 - 0
android/src/main/java/com/rhyme/r_scan/RScanView/RScanViewPlugin.java

@@ -0,0 +1,12 @@
+package com.rhyme.r_scan.RScanView;
+
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.platform.PlatformViewRegistry;
+
+public class RScanViewPlugin {
+
+    public static void registerWith(PlatformViewRegistry platformViewRegistry, BinaryMessenger messenger) {
+        platformViewRegistry
+                .registerViewFactory("com.rhyme_lph/r_scan_view", new RScanViewFactory(messenger));
+    }
+}

+ 1 - 0
example/.flutter-plugins-dependencies

@@ -0,0 +1 @@
+{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"image_picker","path":"C:\\\\Users\\\\p'c\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\image_picker-0.6.7+11\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\Users\\\\p'c\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\permission_handler-3.3.0\\\\","dependencies":[]},{"name":"r_scan","path":"D:\\\\flutter_plugins\\\\r_scan\\\\","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"C:\\\\Users\\\\p'c\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\flutter_plugin_android_lifecycle-1.0.11\\\\","dependencies":[]},{"name":"image_picker","path":"C:\\\\Users\\\\p'c\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\image_picker-0.6.7+11\\\\","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"permission_handler","path":"C:\\\\Users\\\\p'c\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\permission_handler-3.3.0\\\\","dependencies":[]},{"name":"r_scan","path":"D:\\\\flutter_plugins\\\\r_scan\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"permission_handler","dependencies":[]},{"name":"r_scan","dependencies":[]}],"date_created":"2020-10-13 13:55:30.086287","version":"1.22.1"}

+ 73 - 0
example/.gitignore

@@ -0,0 +1,73 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Android related
+**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

+ 10 - 0
example/.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5
+  channel: stable
+
+project_type: app

+ 148 - 0
example/README.md

@@ -0,0 +1,148 @@
+```dart
+import 'package:flutter/material.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:r_scan/r_scan.dart';
+
+class RScanDialog extends StatefulWidget {
+  @override
+  _RScanDialogState createState() => _RScanDialogState();
+}
+
+class _RScanDialogState extends State<RScanDialog> {
+  RScanController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+    initController();
+  }
+  bool isFirst=true;
+
+
+  Future<void> initController() async {
+    _controller = RScanController();
+    _controller.addListener(() {
+
+      final result = _controller.result;
+      if (result != null) {
+        if(isFirst){
+          Navigator.of(context).pop(result);
+          isFirst=false;
+        }
+      }
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      home: Scaffold(
+        backgroundColor: Colors.black,
+        body: FutureBuilder<bool>(
+          future: canOpenCameraView(),
+          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
+            if (snapshot.hasData && snapshot.data == true) {
+              return Stack(
+                children: <Widget>[
+                  ScanImageView(
+                    child: RScanView(
+                      controller: _controller,
+                    ),
+                  ),
+                  Positioned(
+                      top: 16,
+                      right: 16,
+                      child: FutureBuilder(future: getFlashMode(),builder: _buildFlashBtn,))
+                ],
+              );
+            } else {
+              return Container();
+            }
+          },
+        ),
+      ),
+    );
+  }
+
+  Future<bool> getFlashMode()async{
+    bool isOpen = false;
+    try{
+      isOpen = await _controller.getFlashMode();
+
+    }catch(_){
+
+    }
+    return isOpen;
+  }
+
+  Future<bool> canOpenCameraView() async {
+    var status =
+        await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
+    if (status != PermissionStatus.granted) {
+      var future = await PermissionHandler()
+          .requestPermissions([PermissionGroup.camera]);
+      for (final item in future.entries) {
+        if (item.value != PermissionStatus.granted) {
+          return false;
+        }
+      }
+    } else {
+      return true;
+    }
+    return true;
+  }
+
+  Widget _buildFlashBtn(BuildContext context, AsyncSnapshot<bool> snapshot) {
+    return snapshot.hasData?IconButton(icon: Icon(snapshot.data?Icons.flash_on:Icons.flash_off),color: Colors.white, onPressed: (){
+      if(snapshot.data){
+        _controller.setFlashMode(false);
+      }else{
+        _controller.setFlashMode(true);
+      }
+      setState(() {});
+    }):Container();
+
+  }
+}
+
+class ScanImageView extends StatefulWidget {
+  final Widget child;
+
+  const ScanImageView({Key key, this.child}) : super(key: key);
+
+  @override
+  _ScanImageViewState createState() => _ScanImageViewState();
+}
+
+class _ScanImageViewState extends State<ScanImageView>
+    with TickerProviderStateMixin {
+  AnimationController controller;
+
+  @override
+  void initState() {
+    super.initState();
+    controller = AnimationController(
+        vsync: this, duration: Duration(milliseconds: 1000));
+    controller.repeat(reverse: true);
+  }
+
+  @override
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AnimatedBuilder(
+        animation: controller,
+        builder: (BuildContext context, Widget child) => CustomPaint(
+              foregroundPainter:
+                  _ScanPainter(controller.value, Colors.white, Colors.green),
+              child: widget.child,
+              willChange: true,
+            ));
+  }
+}
+
+```

+ 63 - 0
example/android/app/build.gradle

@@ -0,0 +1,63 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withReader('UTF-8') { reader ->
+        localProperties.load(reader)
+    }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+    flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+    flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+    compileSdkVersion 28
+
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+
+    defaultConfig {
+        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+        applicationId "com.rhyme.r_scan_example"
+        minSdkVersion 21
+        targetSdkVersion 28
+        versionCode flutterVersionCode.toInteger()
+        versionName flutterVersionName
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            // TODO: Add your own signing config for the release build.
+            // Signing with the debug keys for now, so `flutter run --release` works.
+            signingConfig signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source '../..'
+}
+
+dependencies {
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
+
+
+}

+ 7 - 0
example/android/app/src/debug/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.rhyme.r_scan_example">
+    <!-- Flutter needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 34 - 0
example/android/app/src/main/AndroidManifest.xml

@@ -0,0 +1,34 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.rhyme.r_scan_example">
+
+    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
+         calls FlutterMain.startInitialization(this); in its onCreate method.
+         In most cases you can leave this as-is, but you if you want to provide
+         additional functionality it is fine to subclass or reimplement
+         FlutterApplication and put your custom class here. -->
+    <application
+        android:name="io.flutter.app.FlutterApplication"
+        android:label="r_scan_example"
+        android:icon="@mipmap/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:launchMode="singleTop"
+            android:theme="@style/LaunchTheme"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
+            <!-- This keeps the window background of the activity showing
+                 until Flutter renders its first frame. It can be removed if
+                 there is no splash screen (such as the default splash screen
+                 defined in @style/LaunchTheme). -->
+            <meta-data
+                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
+                android:value="true" />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>

+ 13 - 0
example/android/app/src/main/java/com/rhyme/r_scan_example/MainActivity.java

@@ -0,0 +1,13 @@
+package com.rhyme.r_scan_example;
+
+import android.os.Bundle;
+import io.flutter.app.FlutterActivity;
+import io.flutter.plugins.GeneratedPluginRegistrant;
+
+public class MainActivity extends FlutterActivity {
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    GeneratedPluginRegistrant.registerWith(this);
+  }
+}

+ 12 - 0
example/android/app/src/main/res/drawable/launch_background.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@android:color/white" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>

BIN
example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


+ 8 - 0
example/android/app/src/main/res/values/styles.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             Flutter draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+</resources>

+ 7 - 0
example/android/app/src/profile/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.rhyme.r_scan_example">
+    <!-- Flutter needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 29 - 0
example/android/build.gradle

@@ -0,0 +1,29 @@
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.5.3'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 5 - 0
example/android/gradle.properties

@@ -0,0 +1,5 @@
+org.gradle.jvmargs=-Xmx1536M
+
+android.enableR8=true
+android.useAndroidX=true
+android.enableJetifier=true

+ 6 - 0
example/android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Mon Dec 09 00:25:13 CST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

+ 15 - 0
example/android/settings.gradle

@@ -0,0 +1,15 @@
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
+}
+
+plugins.each { name, path ->
+    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+    include ":$name"
+    project(":$name").projectDir = pluginDirectory
+}

BIN
example/images/qrCode.png


+ 26 - 0
example/ios/Flutter/AppFrameworkInfo.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>$(DEVELOPMENT_LANGUAGE)</string>
+  <key>CFBundleExecutable</key>
+  <string>App</string>
+  <key>CFBundleIdentifier</key>
+  <string>io.flutter.flutter.app</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>App</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>1.0</string>
+  <key>MinimumOSVersion</key>
+  <string>8.0</string>
+</dict>
+</plist>

+ 2 - 0
example/ios/Flutter/Debug.xcconfig

@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"

+ 2 - 0
example/ios/Flutter/Release.xcconfig

@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"

+ 595 - 0
example/ios/Runner.xcodeproj/project.pbxproj

@@ -0,0 +1,595 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+		3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
+		3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		810470AE2435D9C3003E0C5D /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+		810470AF2435D9C3003E0C5D /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
+		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+		AB367CF32BD312745F3FEF00 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 86607C23EC26018BD5A5E0BA /* libPods-Runner.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
+				810470AF2435D9C3003E0C5D /* Flutter.framework in Embed Frameworks */,
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
+		1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
+		2A9FCBBC4F439F3A179BF2B1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
+		3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
+		3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
+		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
+		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		86607C23EC26018BD5A5E0BA /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		C8C0F1B451BEAE61203D0F22 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
+		D125DFA9346707D4C45896C5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
+				810470AE2435D9C3003E0C5D /* Flutter.framework in Frameworks */,
+				AB367CF32BD312745F3FEF00 /* libPods-Runner.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		348C5729CF024175064D52B3 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				86607C23EC26018BD5A5E0BA /* libPods-Runner.a */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		8DAF24041BDE92426A8C666A /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				C8C0F1B451BEAE61203D0F22 /* Pods-Runner.debug.xcconfig */,
+				2A9FCBBC4F439F3A179BF2B1 /* Pods-Runner.release.xcconfig */,
+				D125DFA9346707D4C45896C5 /* Pods-Runner.profile.xcconfig */,
+			);
+			path = Pods;
+			sourceTree = "<group>";
+		};
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				3B80C3931E831B6300D905FE /* App.framework */,
+				3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+				9740EEBA1CF902C7004384FC /* Flutter.framework */,
+				9740EEB21CF90195004384FC /* Debug.xcconfig */,
+				7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+				8DAF24041BDE92426A8C666A /* Pods */,
+				348C5729CF024175064D52B3 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+				7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				97C146F11CF9000F007C117D /* Supporting Files */,
+				1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+				1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		97C146F11CF9000F007C117D /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				97C146F21CF9000F007C117D /* main.m */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9A90871AAAD9145157E31247 /* [CP] Check Pods Manifest.lock */,
+				9740EEB61CF901F6004384FC /* Run Script */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+				04951A15DDE3E38D60283046 /* [CP] Embed Pods Frameworks */,
+				D6804AC4E74CE9303D4B4A85 /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Runner;
+			productName = Runner;
+			productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		97C146E61CF9000F007C117D /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1020;
+				ORGANIZATIONNAME = "The Chromium Authors";
+				TargetAttributes = {
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						DevelopmentTeam = W366PUAJFC;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+				9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		04951A15DDE3E38D60283046 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Thin Binary";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
+		};
+		9740EEB61CF901F6004384FC /* Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+		};
+		9A90871AAAD9145157E31247 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		D6804AC4E74CE9303D4B4A85 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+				97C146F31CF9000F007C117D /* main.m in Sources */,
+				1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		249021D3217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Profile;
+		};
+		249021D4217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				DEVELOPMENT_TEAM = W366PUAJFC;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.rhyme.rScanExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Profile;
+		};
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				DEVELOPMENT_TEAM = W366PUAJFC;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.rhyme.rScanExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				DEVELOPMENT_TEAM = W366PUAJFC;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.rhyme.rScanExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+				249021D3217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+				249021D4217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}

+ 7 - 0
example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>

+ 91 - 0
example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1020"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+               BuildableName = "Runner.app"
+               BlueprintName = "Runner"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Profile"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 10 - 0
example/ios/Runner.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
+</Workspace>

+ 6 - 0
example/ios/Runner/AppDelegate.h

@@ -0,0 +1,6 @@
+#import <Flutter/Flutter.h>
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : FlutterAppDelegate
+
+@end

+ 13 - 0
example/ios/Runner/AppDelegate.m

@@ -0,0 +1,13 @@
+#include "AppDelegate.h"
+#include "GeneratedPluginRegistrant.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+  [GeneratedPluginRegistrant registerWithRegistry:self];
+  // Override point for customization after application launch.
+  return [super application:application didFinishLaunchingWithOptions:launchOptions];
+}
+
+@end

+ 122 - 0
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,122 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-83.5x83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "Icon-App-1024x1024@1x.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png


Some files were not shown because too many files changed in this diff