From 2e1c88625b9d824401bca1f0d76db0055cda272c Mon Sep 17 00:00:00 2001 From: yxc118 Date: Wed, 13 Nov 2024 14:45:21 +0800 Subject: [PATCH] flutter_barcode_scanner init Signed-off-by: yxc118 --- .gitignore | 2 +- .idea/codeStyles/Project.xml | 116 ----- .idea/encodings.xml | 4 - .idea/libraries/Dart_SDK.xml | 19 - .idea/libraries/Flutter_Plugins.xml | 10 - .idea/misc.xml | 10 - .idea/modules.xml | 8 - .../example_lib_main_dart.xml | 6 - .idea/vcs.xml | 7 - .idea/workspace.xml | 214 --------- OAT.xml | 90 ++++ ohos/.gitignore | 30 ++ ohos/.metadata | 30 ++ ohos/CHANGELOG.md | 3 + ohos/LICENSE | 21 + ohos/README.md | 82 ++++ ohos/analysis_options.yaml | 4 + ohos/example/.gitignore | 45 ++ ohos/example/README.md | 74 ++++ ohos/example/analysis_options.yaml | 29 ++ ohos/example/lib/main.dart | 96 ++++ ohos/example/ohos/.gitignore | 20 + ohos/example/ohos/AppScope/app.json5 | 10 + .../resources/base/element/string.json | 8 + .../resources/base/media/app_icon.png | Bin 0 -> 6790 bytes ohos/example/ohos/build-profile.json5 | 27 ++ ohos/example/ohos/entry/.gitignore | 7 + ohos/example/ohos/entry/build-profile.json5 | 29 ++ ohos/example/ohos/entry/hvigorfile.ts | 17 + ohos/example/ohos/entry/oh-package.json5 | 11 + .../main/ets/entryability/EntryAbility.ets | 24 + .../ohos/entry/src/main/ets/pages/Index.ets | 38 ++ .../ets/plugins/GeneratedPluginRegistrant.ets | 41 ++ ohos/example/ohos/entry/src/main/module.json5 | 63 +++ .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/string.json | 20 + .../src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes .../resources/base/profile/main_pages.json | 5 + .../main/resources/en_US/element/string.json | 16 + .../main/resources/zh_CN/element/string.json | 16 + .../src/ohosTest/ets/test/Ability.test.ets | 50 +++ .../entry/src/ohosTest/ets/test/List.test.ets | 20 + .../ohosTest/ets/testability/TestAbility.ets | 63 +++ .../ohosTest/ets/testability/pages/Index.ets | 49 +++ .../ets/testrunner/OpenHarmonyTestRunner.ts | 64 +++ .../ohos/entry/src/ohosTest/module.json5 | 51 +++ .../resources/base/element/color.json | 8 + .../resources/base/element/string.json | 16 + .../ohosTest/resources/base/media/icon.png | Bin 0 -> 6790 bytes .../resources/base/profile/test_pages.json | 5 + ohos/example/ohos/hvigor/hvigor-config.json5 | 23 + ohos/example/ohos/hvigorfile.ts | 21 + ohos/example/ohos/oh-package.json5 | 20 + ohos/example/pubspec.yaml | 22 + ohos/example/test/widget_test.dart | 27 ++ ohos/lib/flutter_barcode_scanner_ohos.dart | 75 ++++ ohos/ohos/.gitignore | 9 + ohos/ohos/build-profile.json5 | 10 + ohos/ohos/hvigorfile.ts | 17 + ohos/ohos/index.ets | 17 + ohos/ohos/local.properties | 1 + ohos/ohos/oh-package.json5 | 11 + .../ets/components/plugin/CameraService.ets | 409 ++++++++++++++++++ .../FlutterBarcodeScannerOhosPlugin.ets | 57 +++ .../plugin/MethodCallHandlerImpl.ets | 62 +++ .../ets/components/plugin/PermissionsUtil.ets | 58 +++ .../ets/components/plugin/ScannerUtils.ets | 149 +++++++ .../ets/components/plugin/ScannerView.ets | 315 ++++++++++++++ .../src/main/ets/components/plugin/util.ets | 86 ++++ ohos/ohos/src/main/module.json5 | 10 + .../resources/base/media/camera_switch.png | Bin 0 -> 5671 bytes .../main/resources/base/media/flash_close.png | Bin 0 -> 3805 bytes .../main/resources/base/media/flash_open.png | Bin 0 -> 2797 bytes ohos/pubspec.yaml | 31 ++ .../flutter_barcode_scanner_ohos_test.dart | 39 ++ 75 files changed, 2660 insertions(+), 395 deletions(-) delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/libraries/Dart_SDK.xml delete mode 100644 .idea/libraries/Flutter_Plugins.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/runConfigurations/example_lib_main_dart.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml create mode 100644 OAT.xml create mode 100644 ohos/.gitignore create mode 100644 ohos/.metadata create mode 100644 ohos/CHANGELOG.md create mode 100644 ohos/LICENSE create mode 100644 ohos/README.md create mode 100644 ohos/analysis_options.yaml create mode 100644 ohos/example/.gitignore create mode 100644 ohos/example/README.md create mode 100644 ohos/example/analysis_options.yaml create mode 100644 ohos/example/lib/main.dart create mode 100644 ohos/example/ohos/.gitignore create mode 100644 ohos/example/ohos/AppScope/app.json5 create mode 100644 ohos/example/ohos/AppScope/resources/base/element/string.json create mode 100644 ohos/example/ohos/AppScope/resources/base/media/app_icon.png create mode 100644 ohos/example/ohos/build-profile.json5 create mode 100644 ohos/example/ohos/entry/.gitignore create mode 100644 ohos/example/ohos/entry/build-profile.json5 create mode 100644 ohos/example/ohos/entry/hvigorfile.ts create mode 100644 ohos/example/ohos/entry/oh-package.json5 create mode 100644 ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 ohos/example/ohos/entry/src/main/ets/pages/Index.ets create mode 100644 ohos/example/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets create mode 100644 ohos/example/ohos/entry/src/main/module.json5 create mode 100644 ohos/example/ohos/entry/src/main/resources/base/element/color.json create mode 100644 ohos/example/ohos/entry/src/main/resources/base/element/string.json create mode 100644 ohos/example/ohos/entry/src/main/resources/base/media/icon.png create mode 100644 ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json create mode 100644 ohos/example/ohos/entry/src/main/resources/en_US/element/string.json create mode 100644 ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json create mode 100644 ohos/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets create mode 100644 ohos/example/ohos/entry/src/ohosTest/ets/test/List.test.ets create mode 100644 ohos/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets create mode 100644 ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets create mode 100644 ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts create mode 100644 ohos/example/ohos/entry/src/ohosTest/module.json5 create mode 100644 ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json create mode 100644 ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json create mode 100644 ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png create mode 100644 ohos/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json create mode 100644 ohos/example/ohos/hvigor/hvigor-config.json5 create mode 100644 ohos/example/ohos/hvigorfile.ts create mode 100644 ohos/example/ohos/oh-package.json5 create mode 100644 ohos/example/pubspec.yaml create mode 100644 ohos/example/test/widget_test.dart create mode 100644 ohos/lib/flutter_barcode_scanner_ohos.dart create mode 100644 ohos/ohos/.gitignore create mode 100644 ohos/ohos/build-profile.json5 create mode 100644 ohos/ohos/hvigorfile.ts create mode 100644 ohos/ohos/index.ets create mode 100644 ohos/ohos/local.properties create mode 100644 ohos/ohos/oh-package.json5 create mode 100644 ohos/ohos/src/main/ets/components/plugin/CameraService.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/PermissionsUtil.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/ScannerView.ets create mode 100644 ohos/ohos/src/main/ets/components/plugin/util.ets create mode 100644 ohos/ohos/src/main/module.json5 create mode 100644 ohos/ohos/src/main/resources/base/media/camera_switch.png create mode 100644 ohos/ohos/src/main/resources/base/media/flash_close.png create mode 100644 ohos/ohos/src/main/resources/base/media/flash_open.png create mode 100644 ohos/pubspec.yaml create mode 100644 ohos/test/flutter_barcode_scanner_ohos_test.dart diff --git a/.gitignore b/.gitignore index 3874819..9c154fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .DS_Store .dart_tool/ - +.idea/ .packages .pub/ pubspec.lock diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 681f41a..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - -
- - - - xmlns:android - - ^$ - - - -
-
- - - - xmlns:.* - - ^$ - - - BY_NAME - -
-
- - - - .*:id - - http://schemas.android.com/apk/res/android - - - -
-
- - - - .*:name - - http://schemas.android.com/apk/res/android - - - -
-
- - - - name - - ^$ - - - -
-
- - - - style - - ^$ - - - -
-
- - - - .* - - ^$ - - - BY_NAME - -
-
- - - - .* - - http://schemas.android.com/apk/res/android - - - ANDROID_ATTRIBUTE_ORDER - -
-
- - - - .* - - .* - - - BY_NAME - -
-
-
-
-
-
\ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b2..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml deleted file mode 100644 index 8213d12..0000000 --- a/.idea/libraries/Dart_SDK.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml deleted file mode 100644 index 42254fd..0000000 --- a/.idea/libraries/Flutter_Plugins.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index d9e98bd..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 713cb0a..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_lib_main_dart.xml b/.idea/runConfigurations/example_lib_main_dart.xml deleted file mode 100644 index bac2c8a..0000000 --- a/.idea/runConfigurations/example_lib_main_dart.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 1f805b6..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 7b627c6..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1551293438531 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No facets are configured - - - - - - - - - - - - - - - 1.8 - - - - - - - - flutter_barcode_scanner - - - - - - - - Dart SDK - - - - - - - - \ No newline at end of file diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000..89d22e5 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ohos/.gitignore b/ohos/.gitignore new file mode 100644 index 0000000..96486fd --- /dev/null +++ b/ohos/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# 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 +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/ohos/.metadata b/ohos/.metadata new file mode 100644 index 0000000..67ba15c --- /dev/null +++ b/ohos/.metadata @@ -0,0 +1,30 @@ +# 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. + +version: + revision: a9f2dd7423252ff5fa41c13b0a4233211dd51e59 + channel: unknown + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: a9f2dd7423252ff5fa41c13b0a4233211dd51e59 + base_revision: a9f2dd7423252ff5fa41c13b0a4233211dd51e59 + - platform: ohos + create_revision: a9f2dd7423252ff5fa41c13b0a4233211dd51e59 + base_revision: a9f2dd7423252ff5fa41c13b0a4233211dd51e59 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/ohos/CHANGELOG.md b/ohos/CHANGELOG.md new file mode 100644 index 0000000..c7e133c --- /dev/null +++ b/ohos/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +* Support OpenHarmony \ No newline at end of file diff --git a/ohos/LICENSE b/ohos/LICENSE new file mode 100644 index 0000000..4b97384 --- /dev/null +++ b/ohos/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Amol Gangadhare + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/ohos/README.md b/ohos/README.md new file mode 100644 index 0000000..b93b24a --- /dev/null +++ b/ohos/README.md @@ -0,0 +1,82 @@ +## flutter_barcode_scanner_ohos + +flutter_barcode_scanner_ohos is a plugin for Flutter apps that adds barcode scanning support on Ohos. + +## How to use ? + +To use on ohos, you will need to add the camera permission in module.json5. + +``` +"requestPermissions": [ + { + "name": "ohos.permission.CAMERA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + } + ] +``` + + +After making the changes in Ohos add flutter_barcode_scanner to `pubspec.yaml` +``` +dependencies: + ... + flutter_barcode_scanner: ^2.0.0 +``` +## Usage + +``` + yaml + dependencies: + flutter_barcode_scanner: 2.0.0 + flutter_barcode_scanner_ohos: 1.0.0 + ``` + +### One time scan +1. You need to import the package first. + +``` +import 'package:flutter_barcode_scanner_ohos/flutter_barcode_scanner.dart'; +``` + + +2. Then use the `scanBarcode` method to access barcode scanning. + +``` +String barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + COLOR_CODE, + CANCEL_BUTTON_TEXT, + isShowFlashIcon, + scanMode); +``` + +Here in `scanBarcode`, + +`COLOR_CODE` is hex-color which is the color of line in barcode overlay you can pass color of your choice, + +`CANCEL_BUTTON_TEXT` is a text of cancel button on screen you can pass text of your choice and language, + +`isShowFlashIcon` is bool value used to show or hide the flash icon, + +`scanMode` is a enum in which user can pass any of `{ QR, BARCODE, DEFAULT }`, if nothing is passed it will consider a default value which will be `QR`. +It shows the graphics overlay like for barcode and QR. + +NOTE: Currently, `scanMode` is just to show the graphics overlay for barcode and QR. Any of this mode selected will scan both QR and barcode. + +### Continuous scan +* If you need to scan barcodes continuously without closing camera use `FlutterBarcodeScanner.getBarcodeStreamReceiver` + params will be same like `FlutterBarcodeScanner.scanBarcode` + e.g. + + +``` +FlutterBarcodeScanner.getBarcodeStreamReceiver("#ff6666", "Cancel", false, ScanMode.other) + .listen((barcode) { + /// barcode to be used + }); +``` diff --git a/ohos/analysis_options.yaml b/ohos/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/ohos/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/ohos/example/.gitignore b/ohos/example/.gitignore new file mode 100644 index 0000000..fb32a6c --- /dev/null +++ b/ohos/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# 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/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ +/pubspec.lock + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/ohos/example/README.md b/ohos/example/README.md new file mode 100644 index 0000000..ba488a0 --- /dev/null +++ b/ohos/example/README.md @@ -0,0 +1,74 @@ +## flutter_barcode_scanner_ohos + +flutter_barcode_scanner_ohos is a plugin for Flutter apps that adds barcode scanning support on Ohos. + +## How to use ? + +To use on ohos, you will need to add the camera permission in module.json5. + +``` +"requestPermissions": [ + { + "name": "ohos.permission.CAMERA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + } + ] +``` + + +After making the changes in Ohos add flutter_barcode_scanner to `pubspec.yaml` +``` +dependencies: + ... + flutter_barcode_scanner: ^2.0.0 +``` + +### One time scan +1. You need to import the package first. + +``` +import 'package:flutter_barcode_scanner_ohos/flutter_barcode_scanner.dart'; +``` + + +2. Then use the `scanBarcode` method to access barcode scanning. + +``` +String barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + COLOR_CODE, + CANCEL_BUTTON_TEXT, + isShowFlashIcon, + scanMode); +``` + +Here in `scanBarcode`, + +`COLOR_CODE` is hex-color which is the color of line in barcode overlay you can pass color of your choice, + +`CANCEL_BUTTON_TEXT` is a text of cancel button on screen you can pass text of your choice and language, + +`isShowFlashIcon` is bool value used to show or hide the flash icon, + +`scanMode` is a enum in which user can pass any of `{ QR, BARCODE, DEFAULT }`, if nothing is passed it will consider a default value which will be `QR`. +It shows the graphics overlay like for barcode and QR. + +NOTE: Currently, `scanMode` is just to show the graphics overlay for barcode and QR. Any of this mode selected will scan both QR and barcode. + +### Continuous scan +* If you need to scan barcodes continuously without closing camera use `FlutterBarcodeScanner.getBarcodeStreamReceiver` + params will be same like `FlutterBarcodeScanner.scanBarcode` + e.g. + + +``` +FlutterBarcodeScanner.getBarcodeStreamReceiver("#ff6666", "Cancel", false, ScanMode.other) + .listen((barcode) { + /// barcode to be used + }); +``` diff --git a/ohos/example/analysis_options.yaml b/ohos/example/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/ohos/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/ohos/example/lib/main.dart b/ohos/example/lib/main.dart new file mode 100644 index 0000000..4aaac56 --- /dev/null +++ b/ohos/example/lib/main.dart @@ -0,0 +1,96 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_barcode_scanner_ohos/flutter_barcode_scanner_ohos.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + String _scanBarcode = 'Unknown'; + + @override + void initState() { + super.initState(); + } + + Future startBarcodeScanStream() async { + FlutterBarcodeScanner.getBarcodeStreamReceiver( + '#ff6666', 'Cancel', true, ScanMode.barcode)! + .listen((barcode) => print(barcode)); + } + + Future scanQR() async { + String barcodeScanRes; + // Platform messages may fail, so we use a try/catch PlatformException. + try { + barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + '#ff6666', 'Cancel', true, ScanMode.qr); + print(barcodeScanRes); + } on PlatformException { + barcodeScanRes = 'Failed to get platform version.'; + } + + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) return; + + setState(() { + _scanBarcode = barcodeScanRes; + }); + } + + // Platform messages are asynchronous, so we initialize in an async method. + Future scanBarcodeNormal() async { + String barcodeScanRes; + // Platform messages may fail, so we use a try/catch PlatformException. + try { + barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + '#ff6666', 'Cancel', true, ScanMode.barcode); + print(barcodeScanRes); + } on PlatformException { + barcodeScanRes = 'Failed to get platform version.'; + } + + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) return; + + setState(() { + _scanBarcode = barcodeScanRes; + }); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Barcode scan')), + body: Builder(builder: (BuildContext context) { + return Container( + alignment: Alignment.center, + child: Flex( + direction: Axis.vertical, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () => scanBarcodeNormal(), + child: Text('Start barcode scan')), + ElevatedButton( + onPressed: () => scanQR(), + child: Text('Start QR scan')), + ElevatedButton( + onPressed: () => startBarcodeScanStream(), + child: Text('Start barcode scan stream')), + Text('Scan result : $_scanBarcode\n', + style: TextStyle(fontSize: 20)) + ])); + }))); + } +} diff --git a/ohos/example/ohos/.gitignore b/ohos/example/ohos/.gitignore new file mode 100644 index 0000000..1a4e899 --- /dev/null +++ b/ohos/example/ohos/.gitignore @@ -0,0 +1,20 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +*.har +**/BuildProfile.ets +**/oh-package-lock.json5 +/pubspec.lock + +**/src/main/resources/rawfile/flutter_assets/ +**/libs/arm64-v8a/libapp.so +**/libs/arm64-v8a/libflutter.so +**/libs/arm64-v8a/libvmservice_snapshot.so diff --git a/ohos/example/ohos/AppScope/app.json5 b/ohos/example/ohos/AppScope/app.json5 new file mode 100644 index 0000000..3bcef1d --- /dev/null +++ b/ohos/example/ohos/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.flutter_barcode_scanner_ohos_example", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} \ No newline at end of file diff --git a/ohos/example/ohos/AppScope/resources/base/element/string.json b/ohos/example/ohos/AppScope/resources/base/element/string.json new file mode 100644 index 0000000..4f503ab --- /dev/null +++ b/ohos/example/ohos/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "flutter_barcode_scanner_ohos_example" + } + ] +} diff --git a/ohos/example/ohos/AppScope/resources/base/media/app_icon.png b/ohos/example/ohos/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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 { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', + JSON.stringify(data) ?? ''); + }); + } + + onWindowStageDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy'); + } + + onForeground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground'); + } + + onBackground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground'); + } +} \ No newline at end of file diff --git a/ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets b/ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets new file mode 100644 index 0000000..cef0447 --- /dev/null +++ b/ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import hilog from '@ohos.hilog'; + +@Entry +@Component +struct Index { + aboutToAppear() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear'); + } + @State message: string = 'Hello World' + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button() { + Text('next page') + .fontSize(20) + .fontWeight(FontWeight.Bold) + }.type(ButtonType.Capsule) + .margin({ + top: 20 + }) + .backgroundColor('#0D9FFB') + .width('35%') + .height('5%') + .onClick(()=>{ + }) + } + .width('100%') + } + .height('100%') + } + } \ No newline at end of file diff --git a/ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts new file mode 100644 index 0000000..1def08f --- /dev/null +++ b/ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts @@ -0,0 +1,64 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import hilog from '@ohos.hilog'; +import TestRunner from '@ohos.application.testRunner'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; + +var abilityDelegator = undefined +var abilityDelegatorArguments = undefined + +async function onAbilityCreateCallback() { + hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback'); +} + +async function addAbilityMonitorCallback(err: any) { + hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? ''); +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare '); + } + + async onRun() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run'); + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() + var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility' + let lMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + }; + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback) + var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName + var debug = abilityDelegatorArguments.parameters['-D'] + if (debug == 'true') + { + cmd += ' -D' + } + hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd); + abilityDelegator.executeShellCommand(cmd, + (err: any, d: any) => { + hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? ''); + }) + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end'); + } +} \ No newline at end of file diff --git a/ohos/example/ohos/entry/src/ohosTest/module.json5 b/ohos/example/ohos/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000..fab77ce --- /dev/null +++ b/ohos/example/ohos/entry/src/ohosTest/module.json5 @@ -0,0 +1,51 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "description": "$string:module_test_desc", + "mainElement": "TestAbility", + "deviceTypes": [ + "phone" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:test_pages", + "abilities": [ + { + "name": "TestAbility", + "srcEntry": "./ets/testability/TestAbility.ets", + "description": "$string:TestAbility_desc", + "icon": "$media:icon", + "label": "$string:TestAbility_label", + "exported": true, + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "skills": [ + { + "actions": [ + "action.system.home" + ], + "entities": [ + "entity.system.home" + ] + } + ] + } + ] + } +} diff --git a/ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json b/ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json new file mode 100644 index 0000000..3c71296 --- /dev/null +++ b/ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json b/ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000..65d8fa5 --- /dev/null +++ b/ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_test_desc", + "value": "test ability description" + }, + { + "name": "TestAbility_desc", + "value": "the test ability" + }, + { + "name": "TestAbility_label", + "value": "test label" + } + ] +} \ No newline at end of file diff --git a/ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png b/ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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.19.6 <3.0.0' + +dependencies: + flutter: + sdk: flutter + + flutter_barcode_scanner_ohos: + path: ../ + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + uses-material-design: true diff --git a/ohos/example/test/widget_test.dart b/ohos/example/test/widget_test.dart new file mode 100644 index 0000000..ebb7210 --- /dev/null +++ b/ohos/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_barcode_scanner_ohos_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/ohos/lib/flutter_barcode_scanner_ohos.dart b/ohos/lib/flutter_barcode_scanner_ohos.dart new file mode 100644 index 0000000..1b540e8 --- /dev/null +++ b/ohos/lib/flutter_barcode_scanner_ohos.dart @@ -0,0 +1,75 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +/// Scan mode which is either QR code or BARCODE +enum ScanMode { qr, barcode, other } + +/// Provides access to the barcode scanner. +/// +/// This class is an interface between the native Android and iOS classes and a +/// Flutter project. +class FlutterBarcodeScanner { + static const MethodChannel _channel = + MethodChannel('flutter_barcode_scanner'); + + static const EventChannel _eventChannel = + EventChannel('flutter_barcode_scanner_receiver'); + + static Stream? _onBarcodeReceiver; + + /// Scan with the camera until a barcode is identified, then return. + /// + /// Shows a scan line with [lineColor] over a scan window. A flash icon is + /// displayed if [isShowFlashIcon] is true. The text of the cancel button can + /// be customized with the [cancelButtonText] string. + static Future scanBarcode(String lineColor, String cancelButtonText, + bool isShowFlashIcon, ScanMode scanMode) async { + if (cancelButtonText.isEmpty) { + cancelButtonText = 'Cancel'; + } + + // Pass params to the plugin + Map params = { + 'lineColor': lineColor, + 'cancelButtonText': cancelButtonText, + 'isShowFlashIcon': isShowFlashIcon, + 'isContinuousScan': false, + 'scanMode': scanMode.index + }; + + /// Get barcode scan result + final barcodeResult = + await _channel.invokeMethod('scanBarcode', params) ?? ''; + return barcodeResult; + } + + /// Returns a continuous stream of barcode scans until the user cancels the + /// operation. + /// + /// Shows a scan line with [lineColor] over a scan window. A flash icon is + /// displayed if [isShowFlashIcon] is true. The text of the cancel button can + /// be customized with the [cancelButtonText] string. Returns a stream of + /// detected barcode strings. + static Stream? getBarcodeStreamReceiver(String lineColor, + String cancelButtonText, bool isShowFlashIcon, ScanMode scanMode) { + if (cancelButtonText.isEmpty) { + cancelButtonText = 'Cancel'; + } + + // Pass params to the plugin + Map params = { + 'lineColor': lineColor, + 'cancelButtonText': cancelButtonText, + 'isShowFlashIcon': isShowFlashIcon, + 'isContinuousScan': true, + 'scanMode': scanMode.index + }; + + // Invoke method to open camera, and then create an event channel which will + // return a stream + _channel.invokeMethod('scanBarcode', params); + _onBarcodeReceiver ??= _eventChannel.receiveBroadcastStream(); + return _onBarcodeReceiver; + } +} diff --git a/ohos/ohos/.gitignore b/ohos/ohos/.gitignore new file mode 100644 index 0000000..c0f9ca4 --- /dev/null +++ b/ohos/ohos/.gitignore @@ -0,0 +1,9 @@ +/node_modules +/oh_modules +/.preview +/.idea +/build +/.cxx +/.test +/BuildProfile.ets +/oh-package-lock.json5 diff --git a/ohos/ohos/build-profile.json5 b/ohos/ohos/build-profile.json5 new file mode 100644 index 0000000..79961f9 --- /dev/null +++ b/ohos/ohos/build-profile.json5 @@ -0,0 +1,10 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "targets": [ + { + "name": "default" + } + ] +} diff --git a/ohos/ohos/hvigorfile.ts b/ohos/ohos/hvigorfile.ts new file mode 100644 index 0000000..eb1f1d0 --- /dev/null +++ b/ohos/ohos/hvigorfile.ts @@ -0,0 +1,17 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +export { harTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/ohos/ohos/index.ets b/ohos/ohos/index.ets new file mode 100644 index 0000000..162b60a --- /dev/null +++ b/ohos/ohos/index.ets @@ -0,0 +1,17 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import FlutterBarcodeScannerOhosPlugin from './src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin'; +export default FlutterBarcodeScannerOhosPlugin; diff --git a/ohos/ohos/local.properties b/ohos/ohos/local.properties new file mode 100644 index 0000000..22900c8 --- /dev/null +++ b/ohos/ohos/local.properties @@ -0,0 +1 @@ +hwsdk.dir=D:\\soft\\dev-studio\\DevEcoStudioCur\\DevEco Studio\\sdk \ No newline at end of file diff --git a/ohos/ohos/oh-package.json5 b/ohos/ohos/oh-package.json5 new file mode 100644 index 0000000..0e55b82 --- /dev/null +++ b/ohos/ohos/oh-package.json5 @@ -0,0 +1,11 @@ +{ + "name": "flutter_barcode_scanner_ohos", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "index.ets", + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@ohos/flutter_ohos": "file:./har/flutter.har" + } +} diff --git a/ohos/ohos/src/main/ets/components/plugin/CameraService.ets b/ohos/ohos/src/main/ets/components/plugin/CameraService.ets new file mode 100644 index 0000000..dc9b66d --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/CameraService.ets @@ -0,0 +1,409 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import image from '@ohos.multimedia.image'; +import { camera } from '@kit.CameraKit'; +import { display } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { Any, MethodResult } from '@ohos/flutter_ohos'; +import { detectBarcode, scanBarcode, scanCore } from '@kit.ScanKit'; +import EventChannel, { EventSink, StreamHandler } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel'; +import { MyDebounceSingletonUtil } from './util'; +import { ScanMode } from './ScannerUtils'; + +const TAG = '[CameraService] :'; +const IMG_DEFAULT_SIZE_WIDTH: number = px2vp(display.getDefaultDisplaySync().width); +const IMG_DEFAULT_SIZE_HEIGHT: number = px2vp(display.getDefaultDisplaySync().height); + +/** + * 相机服务 + */ +class CameraService { + private cameraManager: camera.CameraManager | undefined = undefined; + private camerasDevices: Array | undefined = undefined; + private curcamerasDevice: camera.CameraDevice | undefined = undefined; + private cameraInput: camera.CameraInput | undefined = undefined; + private photoOutput: camera.PhotoOutput | undefined = undefined; + private previewOutput: camera.PreviewOutput | undefined = undefined; + private photoSession: camera.PhotoSession | null = null; + private context: Context | null = null; + public imageReceiver: image.ImageReceiver; + + constructor(context: Context, imgReceiver?: image.ImageReceiver) { + this.context = context; + const previewSize: camera.Size = { width: 1920, height: 1080 } as camera.Size; + if (imgReceiver === undefined) { + this.imageReceiver = image.createImageReceiver(previewSize, image.ImageFormat.JPEG, 1); + } else { + this.imageReceiver = image.createImageReceiver(previewSize, imgReceiver.format, imgReceiver.capacity); + } + } + + setSize() { + let maxLen: number = Math.max(IMG_DEFAULT_SIZE_WIDTH, IMG_DEFAULT_SIZE_HEIGHT); + let minLen: number = Math.min(IMG_DEFAULT_SIZE_WIDTH, IMG_DEFAULT_SIZE_HEIGHT); + const RATIO: number = 16 / 9; + const cameraHeight = maxLen; + const cameraWidth = maxLen / RATIO; + let size: image.Size = { + width: cameraWidth, + height: cameraHeight + } + } + + getCameraManager(context: Context): camera.CameraManager { + return camera.getCameraManager(context); + } + + async getImageReceiverSurfaceId(receiver: image.ImageReceiver): Promise { + let ImageReceiverSurfaceId: string | undefined = undefined; + if (receiver !== undefined) { + let ImageReceiverSurfaceId: string = await receiver.getReceivingSurfaceId(); + } else { + console.error('createImageReceiver failed'); + } + return ImageReceiverSurfaceId; + } + + // 创建相机 + async createCamera(cameraManager: camera.CameraManager): Promise { + if (!this.cameraManager) { + this.cameraManager = cameraManager; + } + // 获取支持的相机设备对象 + this.camerasDevices = this.cameraManager!.getSupportedCameras(); + if (!this.camerasDevices) { + return; + } + } + + // 预览流 + getPreviewProfilesObj(): camera.Profile | undefined { + // 获取profile对象 + let profiles: camera.CameraOutputCapability = + this.cameraManager!.getSupportedOutputCapability(this.curcamerasDevice, + camera.SceneMode.NORMAL_PHOTO); // 获取对应相机设备profiles + let previewProfiles: Array = profiles.previewProfiles; + let captureSize: camera.Size = { width: 1920, height: 1080 } as camera.Size; + let previewProfilesObj = previewProfiles.find((profile: camera.Profile) => { + return profile.size.width === captureSize.width && profile.size.height === captureSize.height; + }); + return previewProfilesObj; + } + + // 初始化相机并开始捕获预览流 + async initCamera(XComponentSurfaceId: string, front: boolean = false): Promise { + if (!this.camerasDevices) { + return; + } + // 前置 + if (front) { + this.curcamerasDevice = + this.camerasDevices.find(el => el.cameraPosition === camera.CameraPosition.CAMERA_POSITION_FRONT); + } else { + this.curcamerasDevice = + this.camerasDevices.find(el => el.cameraPosition === camera.CameraPosition.CAMERA_POSITION_BACK); + } + // 获取支持的模式类型 + let sceneModes: Array = this.cameraManager!.getSupportedSceneModes(this.curcamerasDevice); + let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0; + if (!isSupportPhotoMode) { + console.error(TAG + 'photo mode not support'); + return; + } + // 预览流1 + let previewProfilesObj: camera.Profile | undefined = this.getPreviewProfilesObj(); + // 预览流2 + let previewProfilesObj2: camera.Profile | undefined = this.getPreviewProfilesObj(); + // 创建 预览流1 输出对象 + let previewOutput: camera.PreviewOutput = + this.cameraManager!.createPreviewOutput(previewProfilesObj, XComponentSurfaceId); + // 创建 预览流2 输出对象 + let imageReceiverSurfaceId: string = await this.imageReceiver.getReceivingSurfaceId(); + let previewOutput2: camera.PreviewOutput = + this.cameraManager!.createPreviewOutput(previewProfilesObj2, imageReceiverSurfaceId); + // 创建cameraInput对象 + this.cameraInput = this.cameraManager!.createCameraInput(this.curcamerasDevice); + // 打开相机 + await this.cameraInput.open(); + // 会话流程 + this.photoSession = + this.cameraManager!.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession; + // 开始配置会话 + this.photoSession.beginConfig(); + // 把CameraInput加入到会话 + this.photoSession.addInput(this.cameraInput); + // 把 预览流1 加入到会话 + this.photoSession.addOutput(previewOutput); + // 把 预览流2 加入到会话 + this.photoSession.addOutput(previewOutput2); + // 提交配置信息 + await this.photoSession.commitConfig(); + // 会话开始 + await this.photoSession.start(); + // 对焦模式 + this.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); + } + + // 获取预览流并解析 + onImageArrival(receiver: image.ImageReceiver, result: MethodResult | undefined, rescan: boolean = false, + imageStreamSink: EventSink | null, scanMode: ScanMode, + callback: ((r: detectBarcode.DetectResult) => void) | null): void { + receiver.on('imageArrival', () => { + receiver.readNextImage((err: BusinessError, nextImage: image.Image) => { + if (err || nextImage === undefined) { + result!.error("onImageArrival", "nextImage is undefined", null); + console.error(TAG + 'nextImage is undefined'); + return; + } + nextImage.getComponent(image.ComponentType.JPEG, (err: BusinessError, imgComponent: image.Component) => { + if (err || imgComponent === undefined) { + } + if (imgComponent && imgComponent.byteBuffer as ArrayBuffer) { + // do something... + this.decodeImageBuffer(imgComponent, nextImage.size.width, nextImage.size.height, result, rescan, + imageStreamSink, scanMode, callback); + } else { + result!.error("onImageArrival", "byteBuffer is null", null); + console.error(TAG + 'byteBuffer is null'); + } + nextImage.release(); + }) + }) + }) + } + + // 从ImageReceiver获取imgComponent: image.Component,预览流设置的宽高: width, height + decodeImageBuffer(imgComponent: image.Component, width: number, height: number, result: MethodResult | undefined, + rescan: boolean = false, imageStreamSink: EventSink | null, scanMode: ScanMode, + callback: ((r: detectBarcode.DetectResult) => void) | null) { + if (MyDebounceSingletonUtil.getInstance().isDebounced(TAG + 'Debounced', 800)) { + return; + } + const that = this; + let byteImg: detectBarcode.ByteImage = { + byteBuffer: imgComponent.byteBuffer, + width: width, + height: height, + format: detectBarcode.ImageFormat.NV21 + }; + const scanTypes = this.getType(scanMode); + let options: scanBarcode.ScanOptions = { + scanTypes: scanTypes, + enableMultiMode: false, + enableAlbum: false + }; + detectBarcode.decodeImage(byteImg, options).then((detectBarcode: detectBarcode.DetectResult) => { + if (rescan) { + if (detectBarcode.scanResults && detectBarcode.scanResults.length) { + imageStreamSink!.success(detectBarcode.scanResults[0].originalValue); + } + } + callback && callback(detectBarcode); + }).catch((error: BusinessError) => { + if (rescan) { + imageStreamSink!.error("decodeImageBuffer", "The image decode err", null); + } + result!.error("decodeImageBuffer", "The image decode err", null); + console.error(TAG + error.message); + }) + } + + // 获取扫描类型 + getType(scanMode: ScanMode) { + switch (scanMode) { + // 二维码 + case ScanMode.qr: + return [scanCore.ScanType.TWO_D_CODE]; + // 条形码 + case ScanMode.barcode: + return [scanCore.ScanType.ONE_D_CODE]; + default: + return [scanCore.ScanType.FORMAT_UNKNOWN]; + } + } + + // 变焦 + setZoomRatio(scalValue: number) { + // 判断是否支持连续自动变焦模式 + let focusModeStatus: boolean = false; + try { + let status: boolean = this.photoSession!.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); + focusModeStatus = status; + } catch (error) { + let err = error as BusinessError; + console.error(`${TAG}Failed to check whether the focus mode is supported. error: ${JSON.stringify(err)}`); + } + if (focusModeStatus) { + // 设置连续自动变焦模式 + try { + this.photoSession!.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); + } catch (error) { + let err = error as BusinessError; + console.error(`${TAG}Failed to set the focus mode. error: ${JSON.stringify(err)}`); + } + } + // 获取相机支持的可变焦距比范围 + let zoomRatioRange: Array = []; + try { + zoomRatioRange = this.photoSession!.getZoomRatioRange(); + } catch (error) { + let err = error as BusinessError; + console.error(`${TAG}Failed to get the zoom ratio range. error: ${JSON.stringify(err)}`); + } + if (zoomRatioRange.length <= 0) { + return; + } + let ratioValue = 1 + if (scalValue < zoomRatioRange[0]) { + ratioValue = zoomRatioRange[0] + } else if (scalValue > zoomRatioRange[1]) { + ratioValue = zoomRatioRange[1] + } else { + ratioValue = scalValue + } + // 设置可变焦距比 + try { + this.photoSession!.setZoomRatio(ratioValue); + } catch (error) { + let err = error as BusinessError; + console.error(`${TAG}Failed to set the zoom ratio value. error: ${JSON.stringify(err)}`); + } + } + + // 手电筒开关 + setTorchMode(isOpen: boolean) { + if (!this.isTorchSupported()) { + return; + } + const newMode = isOpen ? camera.TorchMode.ON : camera.TorchMode.OFF; + if (!this.isTorchModeSupported(newMode)) { + return; + } + try { + const torchMode = this.cameraManager!.getTorchMode(); + this.cameraManager!.setTorchMode(newMode); + console.info(TAG + ' setTorchMode success'); + } catch (error) { + console.error(TAG + 'setTorchMode err' + JSON.stringify(error)); + } + } + + // 支持手电筒 + isTorchSupported(): boolean { + let isSupported = this.cameraManager!.isTorchSupported(); + return isSupported; + } + + // 支持设置手电筒 + isTorchModeSupported(torchMode: camera.TorchMode): boolean { + let isSupported = this.cameraManager!.isTorchModeSupported(torchMode); + return isSupported; + } + + // 闪光灯开关 + setFlashMode(result: MethodResult, isOpen: boolean): void { + // 设备是否支持闪光灯,可使用方法hasFlash + // 设备是否支持指定的闪光灯模式,可使用方法isFlashModeSupported + if (!this.hasFlash()) { + result.error("setFlashMode hasFlash", "The camera device does not have flash.", null); + return; + } + const newMode = isOpen ? camera.FlashMode.FLASH_MODE_OPEN : camera.FlashMode.FLASH_MODE_CLOSE; + + if (!this.isFlashModeSupported(newMode)) { + result.error("setFlashMode isFlashModeSupported", " The flash mode is unsupported.", null); + return; + } + try { + this.photoSession!.setFlashMode(newMode); + result.success(null); + } catch (error) { + result.error("setFlashMode", "The setFlashMode call failed", null); + } + } + + // 检测是否有闪光灯 + hasFlash(): boolean { + let status: boolean = false; + try { + status = this.photoSession!.hasFlash(); + } catch (error) { + // 失败返回错误码error.code并处理 + let err = error as BusinessError; + console.error(`The hasFlash call failed. error code: ${err.code}`); + } + return status; + } + + //检测闪光灯模式是否支持 + isFlashModeSupported(mode: camera.FlashMode): boolean { + let status: boolean = false; + try { + status = this.photoSession!.isFlashModeSupported(mode); + } catch (error) { + // 失败返回错误码error.code并处理 + let err = error as BusinessError; + console.error(`The isFlashModeSupported call failed. error code: ${err.code}`); + } + return status; + } + + /** + * 对焦模式 + */ + setFocusMode(focusMode: camera.FocusMode): void { + // 检测对焦模式是否支持 + let isSupported = this.photoSession!.isFocusModeSupported(focusMode); + // 设置对焦模式 + if (!isSupported) { + return; + } + this.photoSession!.setFocusMode(focusMode); + } + + /** + * 以指定参数触发一次拍照 + */ + takePicture() { + let photoSetting: camera.PhotoCaptureSetting = { + rotation: camera.ImageRotation.ROTATION_0, + quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM, + mirror: false + }; + this.photoOutput?.capture(photoSetting); + } + + // 切换前置后置前释放相机流 + async preFrontRelease() { + await this.photoSession?.release() + await this.cameraInput?.close(); + await this.photoOutput?.release(); + await this.previewOutput?.release(); + } + + /** + * 释放相机 + */ + async releaseCamera() { + await this.photoSession?.release(); + await this.cameraInput?.close(); + await this.photoOutput?.release(); + await this.previewOutput?.release(); + await this.imageReceiver.release(); + } +} + +export { CameraService } \ No newline at end of file diff --git a/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets b/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets new file mode 100644 index 0000000..f9d770f --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityAware, AbilityPluginBinding, FlutterPlugin, FlutterPluginBinding, } from '@ohos/flutter_ohos'; +import { MethodCallHandlerImpl } from './MethodCallHandlerImpl'; +import { UIAbility } from '@kit.AbilityKit'; + +const TAG: string = '【FlutterBarcodeScannerOhosPlugin】'; + +export default class FlutterBarcodeScannerOhosPlugin implements FlutterPlugin, AbilityAware { + private flutterPluginBinding: FlutterPluginBinding | null = null; + private methodCallHandler: MethodCallHandlerImpl | null = null; + private ability: UIAbility | null = null; + private context: Context | null = null; + + constructor() { + } + + getUniqueClassName(): string { + return "FlutterBarcodeScannerOhosPlugin" + } + + onAttachedToEngine(binding: FlutterPluginBinding): void { + this.flutterPluginBinding = binding; + } + + onDetachedFromEngine(binding: FlutterPluginBinding): void { + this.flutterPluginBinding = null; + } + + onAttachedToAbility(binding: AbilityPluginBinding): void { + if (this.flutterPluginBinding != null) { + this.ability = binding.getAbility(); + this.context = this.ability.context; + this.methodCallHandler = new MethodCallHandlerImpl(this.context, this.flutterPluginBinding.getBinaryMessenger()); + } + } + + onDetachedFromAbility(): void { + if (this.methodCallHandler != null) { + this.methodCallHandler.stopListening(); + this.methodCallHandler = null; + } + } +} \ No newline at end of file diff --git a/ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets b/ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets new file mode 100644 index 0000000..75f8fde --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BinaryMessenger, EventChannel, MethodCall } from '@ohos/flutter_ohos'; +import MethodChannel, { + MethodCallHandler, + MethodResult +} from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel'; +import { ScannerDialog } from './ScannerUtils'; + +const TAG: string = "MethodCallHandlerImpl"; + +export class MethodCallHandlerImpl implements MethodCallHandler { + private methodChannel: MethodChannel; + private imageStreamChannel: EventChannel; + private context: Context; + + constructor(context: Context, messenger: BinaryMessenger) { + this.context = context; + this.methodChannel = new MethodChannel(messenger, 'flutter_barcode_scanner'); + this.imageStreamChannel = new EventChannel(messenger, 'flutter_barcode_scanner_receiver'); + this.methodChannel.setMethodCallHandler(this); + } + + public onMethodCall(call: MethodCall, result: MethodResult): void { + switch (call.method) { + case 'scanBarcode': { + const dialog = new ScannerDialog(this.context); + dialog.show({ + lineColor: call.argument('lineColor'), + cancelButtonText: call.argument('cancelButtonText'), + isContinuousScan: call.argument('isContinuousScan'), + isShowFlashIcon: call.argument('isShowFlashIcon'), + scanMode: call.argument('scanMode'), + }, result, this.imageStreamChannel) + break; + } + case 'dispose': { + break; + } + default: + result.notImplemented(); + break; + } + } + + stopListening(): void { + this.methodChannel.setMethodCallHandler(null); + } +} \ No newline at end of file diff --git a/ohos/ohos/src/main/ets/components/plugin/PermissionsUtil.ets b/ohos/ohos/src/main/ets/components/plugin/PermissionsUtil.ets new file mode 100644 index 0000000..44d8db2 --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/PermissionsUtil.ets @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + bundleManager, + abilityAccessCtrl, + PermissionRequestResult, + Permissions, + Context +} from '@kit.AbilityKit'; + +const TAG = '[PermissionsUtil] :'; + +export class PermissionsUtil { + public static async checkAccessToken(permission: Permissions): Promise { + let atManager = abilityAccessCtrl.createAtManager(); + let grantStatus: abilityAccessCtrl.GrantStatus = -1; + let tokenId: number = 0; + try { + let bundleInfo: bundleManager.BundleInfo = + await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); + let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; + tokenId = appInfo.accessTokenId; + } catch (error) { + console.error(TAG + 'Failed to get bundle info for self. error: %{public}s', + JSON.stringify(error)); + } + try { + grantStatus = await atManager.checkAccessToken(tokenId, permission); + } catch (error) { + console.error(TAG + 'Failed to check access token. error: %{public}s' + JSON.stringify(error)); + } + return grantStatus; + } + + public static async reqPermissionsFromUser(context: Context): Promise { + let atManager = abilityAccessCtrl.createAtManager(); + let grantStatus: PermissionRequestResult = { permissions: [], authResults: [] } + try { + grantStatus = await atManager.requestPermissionsFromUser(context, ['ohos.permission.CAMERA']); + } catch (error) { + console.error(TAG + 'Failed to check access token. error: %{public}s', JSON.stringify(error)); + } + return grantStatus.authResults; + } +} diff --git a/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets b/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets new file mode 100644 index 0000000..fb12297 --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Any from '@ohos/flutter_ohos/src/main/ets/plugin/common/Any'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { window, display, PromptAction } from '@kit.ArkUI'; +import { ComponentContent, promptAction } from '@kit.ArkUI'; +import { EventChannel, MethodResult } from '@ohos/flutter_ohos'; +import { dialogBuilder } from './ScannerView'; + +const width: number = px2vp(display.getDefaultDisplaySync().width) +const height: number = px2vp(display.getDefaultDisplaySync().height) +export enum ScanMode { qr, barcode, other } + +// 扫一扫全局弹窗页面 +class ScannerDialog { + public static contentDialog: ComponentContent | null = null + public static promptAction: PromptAction; + public pageShow: boolean = false; + public pageHide: boolean = false; + private context: Context; + private windowClass: window.Window | null = null; + + constructor(context: Context) { + this.context = context; + } + + show(args: Any, result: MethodResult, imageStreamChannel: EventChannel) { + window.getLastWindow(this.context).then((windowClass) => { + this.windowClass = windowClass; + const uiContext = windowClass.getUIContext(); + // 隐藏导航条 + windowClass.setSpecificSystemBarEnabled('navigationIndicator', false); + // 响应手势返回事件 + windowClass.setDialogBackGestureEnabled(true); + ScannerDialog.contentDialog = new ComponentContent(uiContext, wrapBuilder(dialogBuilder), new Params({ + result: result, + lineColor: args.lineColor, + cancelButtonText: args.cancelButtonText, + isShowFlashIcon: args.isShowFlashIcon, + isContinuousScan: args.isContinuousScan, + scanMode: args.scanMode, + imageStreamChannel: imageStreamChannel, + dialog: this + })); + ScannerDialog.promptAction = uiContext.getPromptAction(); + try { + let options: promptAction.BaseDialogOptions = { + autoCancel: false, + isModal: false, + maskColor: '#000', + maskRect: { + x: 0, + y: 0, + width: width, + height: height + }, + alignment: DialogAlignment.Center, + // 这里设置两个动画,分别对应弹窗显示和隐藏动画 + transition: TransitionEffect.asymmetric( + TransitionEffect.OPACITY.animation({ duration: 1000 }).combine( + TransitionEffect.translate({ x: 1000 }).animation({ duration: 1000 })) + , + TransitionEffect.OPACITY.animation({ delay: 1000, duration: 1000 }).combine( + TransitionEffect.translate({ x: 1000 }).animation({ duration: 1000 })) + ), + onWillDismiss:(dismissDialogAction: DismissDialogAction)=> { + if (dismissDialogAction.reason == DismissReason.PRESS_BACK) { + this.context.eventHub.emit('press_back'); + dismissDialogAction.dismiss() + } + }, + }; + ScannerDialog.promptAction.openCustomDialog(ScannerDialog.contentDialog, options) + } catch (error) { + let message = (error as BusinessError).message; + let code = (error as BusinessError).code; + console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); + } + windowClass.on('windowEvent', (data) => { + if (data === window.WindowEventType.WINDOW_SHOWN) { + this.context.eventHub.emit('page_show'); + } + if (data === window.WindowEventType.WINDOW_HIDDEN) { + this.context.eventHub.emit('page_hide'); + } + if(data===window.WindowEventType.WINDOW_DESTROYED) { + this.context.eventHub.off('page_show'); + this.context.eventHub.off('page_hide'); + } + }); + + }) + } + + hide() { + this.windowClass?.off('windowEvent'); + ScannerDialog.promptAction.closeCustomDialog(ScannerDialog.contentDialog); + } +} + +interface ScannerParams { + result: MethodResult; + lineColor: string; + cancelButtonText: string; + isShowFlashIcon: boolean; + isContinuousScan: boolean; + scanMode: ScanMode; + imageStreamChannel: EventChannel; + dialog: ScannerDialog +} + +class Params { + result: MethodResult; + lineColor: string; + cancelButtonText: string; + isShowFlashIcon: boolean; + isContinuousScan: boolean; + scanMode: ScanMode; + imageStreamChannel: EventChannel; + dialog: ScannerDialog; + + constructor(param: ScannerParams) { + this.result = param.result; + this.lineColor = param.lineColor; + this.cancelButtonText = param.cancelButtonText; + this.isShowFlashIcon = param.isShowFlashIcon; + this.isContinuousScan = param.isContinuousScan; + this.scanMode = param.scanMode; + this.imageStreamChannel = param.imageStreamChannel; + this.dialog = param.dialog; + } +} + +export { + Params, ScannerDialog +} diff --git a/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets b/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets new file mode 100644 index 0000000..a082cc8 --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets @@ -0,0 +1,315 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { camera } from '@kit.CameraKit'; +import { display } from '@kit.ArkUI'; +import { CameraService } from './CameraService' +import { PermissionsUtil } from './PermissionsUtil'; +import { Params, ScanMode, ScannerDialog } from './ScannerUtils'; +import { Any, EventChannel, MethodResult } from '@ohos/flutter_ohos'; +import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'; +import { detectBarcode } from '@kit.ScanKit'; +import { EventSink, StreamHandler } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel'; + +const TAG = '[ScannerView]'; +const width: number = px2vp(display.getDefaultDisplaySync().width) +const height: number = px2vp(display.getDefaultDisplaySync().height) + +@Component +struct ScannerView { + @State result: MethodResult | undefined = undefined; + @State lineColor: string = ''; + @State cancelButtonText: string = 'Cancel'; + @State isShowFlashIcon: boolean = false; + @State isContinuousScan: boolean = false; + @State scanMode: ScanMode = ScanMode.other; + @State imageStreamChannel: EventChannel | null = null; + @State userGrant: boolean = false; + @State surfaceId: string = ''; + @State isOpen: boolean = false; + @State vtb: number = 53; + @State vlr: number = 53; + @State animationOrdinate: number = 0; + @State isFront: boolean = false; + @State timer: number | null = null; + @State scaleValue: number = 0; + private mXComponentController: XComponentController = new XComponentController(); + private context: Context = getContext(this); + private dialog: ScannerDialog = new ScannerDialog(this.context); + private cameraService: CameraService = new CameraService(this.context); + + aboutToAppear(): void { + this.isOpen = false; + this.isFront = false; + this.init(); + this.setDisPlay(); + this.resultInit(); + this.context.eventHub.on('page_show', () => { + this.cameraService.initCamera(this.surfaceId, this.isFront) + }) + this.context.eventHub.on('page_hide', () => { + this.cameraService.preFrontRelease(); + }) + this.context.eventHub.on('press_back', () => { + this.cancel(); + }) + } + + aboutToDisappear(): void { + this.timer = null; + } + + onPageShow(): void { + } + + onPageHide(): void { + } + + // 初始化扫描结果 + resultInit() { + // stream持续扫描向flutter测发送数据 + if (this.isContinuousScan) { + let that = this; + let streamHandler: StreamHandler = { + onListen(args: Any, imageStreamSink: EventSink): void { + that.cameraService.onImageArrival(that.cameraService.imageReceiver, that.result, that.isContinuousScan, + imageStreamSink, that.scanMode, null); + }, + onCancel(args: Any): void { + if (that.cameraService.imageReceiver) { + that.cameraService.imageReceiver.release(); + } + } + } + that.imageStreamChannel!.setStreamHandler(streamHandler) + } else { + this.cameraService.onImageArrival(this.cameraService.imageReceiver, this.result, this.isContinuousScan, + null, this.scanMode, (r: detectBarcode.DetectResult) => { + if (r.scanResults && r.scanResults.length) { + this.result?.success(r.scanResults[0].originalValue); + setTimeout(() => { + this.cancel(); + }, 300); + } + }); + } + } + + setDisPlay() { + this.vtb = (height - 80) / 2 - 100; + this.vlr = width / 2 - 140; + } + + async init() { + const permissions: Array = ['ohos.permission.CAMERA']; + let grantStatus = await PermissionsUtil.checkAccessToken(permissions[0]); + if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { + this.userGrant = true; + } else { + this.requestCameraPermission(); + } + } + + // 扫一扫初始化 + scan() { + const cameraManager = camera.getCameraManager(this.context); + this.cameraService.createCamera(cameraManager); + this.cameraService.initCamera(this.surfaceId); + } + + // 申请权限 + async requestCameraPermission() { + const context = getContext(this); + let grantStatus = await PermissionsUtil.reqPermissionsFromUser(context); + let length: number = grantStatus.length; + for (let i = 0; i < length; i++) { + if (grantStatus[i] === 0) { + this.userGrant = true; + } else { + this.userGrant = false; + } + } + } + + // 扫一扫动画 + setQRCodeScanAnimation() { + this.timer = setInterval(() => { + animateTo({ + duration: 1000, // 动画时间 + tempo: 0.5, // 动画速率 + curve: Curve.EaseInOut, + delay: 5, // 动画延迟时间 + iterations: -1, // 动画是否重复播放 + playMode: PlayMode.Normal, + }, () => { + this.animationOrdinate = 200 // 扫描动画结束Y坐标 + }) + }, 1000) + } + + async cancel() { + this.isOpen = false; + this.cameraService.setTorchMode(this.isOpen); + await this.release(); + this.dialog!.hide(); + } + + async release() { + await this.cameraService.releaseCamera(); + } + + build() { + Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + if (this.userGrant) { + Stack() { + // 相机视口=========================================================================start + Column() { + XComponent({ + id: 'componentId', + type: XComponentType.SURFACE, + controller: this.mXComponentController + }) + .onLoad(() => { + // 获取XComponent的surfaceId + const surfaceId = this.mXComponentController.getXComponentSurfaceId(); + // 设置ViewControl相应字段 + this.surfaceId = surfaceId; + this.setQRCodeScanAnimation(); + this.scan(); + })// 预览流宽、高,默认单位vp,支持px、lpx、vp + .position({ x: 0, y: 0 }) + .width('100%') + .height('100%') + + } + .width('100%') + .height('100%') + // 中间动画方格区域==================================================================start + Column() { + Column() { + // 扫一扫的线 + Column() + .height(1) + .width(280) + .border({ + style: BorderStyle.Solid, + color: { + left: Color.Transparent, + right: Color.Transparent, + top: this.lineColor, + bottom: Color.Transparent + }, + width: 1 + }) + .position({ x: 0, y: 0 }) + .translate({ x: 0, y: this.animationOrdinate }) + } + .border({ style: BorderStyle.Solid, color: Color.Transparent, width: 1 }) + .width(280) + .height(200) + .opacity(1) + } + .height('100%') + .width('100%') + .opacity(0.6) + .border({ + style: BorderStyle.Solid, color: '#666', width: { + left: this.vlr, + right: this.vlr, + top: this.vtb, + bottom: (this.vtb) + } + }) + } + .height('100%') + .width('100%') + .alignContent(Alignment.Center) + .gesture(PinchGesture({ fingers: 2 }) + .onActionStart((event: GestureEvent) => { + }) + .onActionUpdate((event: GestureEvent) => { + if (event) { + this.scaleValue = event.scale; + } + }) + .onActionEnd((event: GestureEvent) => { + // 获取双指缩放比例,设置变焦比 + this.cameraService.setZoomRatio(this.scaleValue); + })) + + // 导航栏 ===================================================================================================start + Flex({ justifyContent: FlexAlign.SpaceBetween, direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { + Column() { + Image($r('app.media.camera_switch')) + .width(40).height(35) + } + .width('33%') + .alignItems(HorizontalAlign.Start) + .onClick(() => { + this.isFront = !this.isFront; + this.cameraService.preFrontRelease().then(() => { + this.cameraService.initCamera(this.surfaceId, this.isFront).then(() => { + if(this.isOpen) { + setTimeout(() => { + this.cameraService.setTorchMode(this.isOpen); + }, 200) + } + }) + }) + }) + if (this.isShowFlashIcon) { + Column() { + Image(this.isOpen ? $r('app.media.flash_open') : $r('app.media.flash_close')) + .width(40) + .height(35) + } + .width('33%') + .onClick(() => { + this.isOpen = !this.isOpen; + this.cameraService.setTorchMode(this.isOpen); + }) + } + Column() { + Text(this.cancelButtonText) + .width('100%') + .height('100%') + .fontColor(Color.White) + .textAlign(TextAlign.End) + } + .width('33%') + .onClick(() => { + this.cancel(); + }) + } + .width('100%') + .height(80) + .padding({ + top: 0, + bottom: 0, + left: 10, + right: 10 + }) + .backgroundColor(Color.Black) + } + } + .width('100%') + .height('100%') + } +} + +@Builder +export function dialogBuilder(params: Params) { + ScannerView(params) +} \ No newline at end of file diff --git a/ohos/ohos/src/main/ets/components/plugin/util.ets b/ohos/ohos/src/main/ets/components/plugin/util.ets new file mode 100644 index 0000000..38bcb5b --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/util.ets @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// 防抖 在一段时间内函数被多次触发,防抖让函数在一段时间后最终只执行一次 +import { detectBarcode } from '@kit.ScanKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { image } from '@kit.ImageKit'; + +export function debounce(func: () => void, delay?: number) { + let timer: number; + return () => { + clearTimeout(timer); + timer = setTimeout(() => { + func(); + }, delay ? delay : 1000); + }; +} + + +export function throttle2(func: () => void, delay?: number) { + let inThrottle: boolean; + return () => { + if (!inThrottle) { + func(); + inThrottle = true; + setTimeout(() => inThrottle = false, delay ? delay : 1000); + } + }; +} +export function throttle1(func: (err: BusinessError, nextImage: image.Image) => void, delay?: number) { + let inThrottle: boolean; + return (err: BusinessError, nextImage: image.Image) => { + if (!inThrottle) { + func(err, nextImage); + inThrottle = true; + setTimeout(() => inThrottle = false, delay ? delay : 1000); + } + }; +} + +export function throttle(func: (detectBarcode: detectBarcode.DetectResult) => void, delay?: number) { + let inThrottle: boolean; + return (detectBarcode: detectBarcode.DetectResult) => { + if (!inThrottle) { + func(detectBarcode); + inThrottle = true; + setTimeout(() => inThrottle = false, delay ? delay : 1000); + } + }; +} +// 防抖 +export class MyDebounceSingletonUtil { + private static instance: MyDebounceSingletonUtil; + private static methodsMap: Map = new Map(); + + public static getInstance(): MyDebounceSingletonUtil { + if (!MyDebounceSingletonUtil.instance) { + MyDebounceSingletonUtil.instance = new MyDebounceSingletonUtil(); + } + return MyDebounceSingletonUtil.instance; + } + + public isDebounced(methodName: string, milliseconds: number): boolean { + const now = Date.now(); + const lastExecutionTime = MyDebounceSingletonUtil.methodsMap.get(methodName); + + if (lastExecutionTime && (now - lastExecutionTime) < milliseconds) { + return true; // 方法在指定时间内已执行过 + } else { + MyDebounceSingletonUtil.methodsMap.set(methodName, now); + return false; // 方法在指定时间内未执行过 + } + } +} \ No newline at end of file diff --git a/ohos/ohos/src/main/module.json5 b/ohos/ohos/src/main/module.json5 new file mode 100644 index 0000000..165a74d --- /dev/null +++ b/ohos/ohos/src/main/module.json5 @@ -0,0 +1,10 @@ +{ + "module": { + "name": "flutter_barcode_scanner_ohos", + "type": "har", + "deviceTypes": [ + "default", + "tablet" + ] + } +} diff --git a/ohos/ohos/src/main/resources/base/media/camera_switch.png b/ohos/ohos/src/main/resources/base/media/camera_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..b0660ba4de4d8d7f63e49908faaf185ae1fe55e5 GIT binary patch literal 5671 zcma)Ac{r49)PH7dlPF^%vNMb&;#KxtmWMHg$d)v=#-6o=29@0~Qe=C3n@}iQgKSgQ zu@;K4iwI-#BC>z;Uf;jpAKxF(b6?kae)oCKea^Y>bN^1#Rg4)o=Q&OQ0JuT(%Qnn$ zk@pBTjj2bZ*Ur{=Pn=c~~`K@kn*5q^vl+jGT?OWf3q56=Z zllVp;AKc*Re~mHDLWDR8OIHZOaHL7)G@gj*lp@HVVDZu!(6~N72Lc1l*lm=49$do= zQ%azQgnzYVGjvs?n?)(s0NE;}WoMv_0}_?L(9m4dWEfu~Q%s77MDbF5xUnm5o*T|C z7+k$S(*M>IM1!X7H7RzVS_hQA9|r#k0Dei|^KR`Eof)Sm%HjNhr88x5+Nr0Dd~*OO z8QXZ4x{6Y^_kP@+oI`YFpH%?JKhdm{83L@LER`s#rTatM4C>>YTUitvK&XVLo-6u~ zBEBxGNtRF6prCrkb`JtfWFEYmzHjs0fWQ4oC=BmzbJ|PhsK6|EXC&IHFo)=u zxl}#ElAHS=1uV>{9@OO73vkSnipnl%XP^D+1VyJQdtXt__kW|^HsE(z`;N&Xl}HJa@} zDwbUROHmWM=kE7cNKLZTenzc(6t(tD5^gtg04-z0Fz14noQ>!+QHhJr1T%BOHxBVF ztduoB*4SSelO(v6h&54CC6KMs(QG|TRVIPrgvwZl^R(0O{}vUslQb2)g(rleS3+Pwj@ z9WC*7b!6)k=s7v~aLbKxb#&maWDqBHr(`z9qWwS;e`pI!-oGjon+J|(+5U32Xm2_} z5sDOpN4N>I#;~|$Nv2Fk&&w_w&2%QpQQs&|1i!a)Ag^l94Sq!}luA!Jxf{9fDo>fX z?LI`;RL2rn?qbJ_u4gp8Ncy)+vKZNDOf!q_Ju@pfke8Ua`coTf@B8E6AFeLD4)@>L zVFj;E(4f8LkZW~Bg?8mm2~6{qP{x=f-Yu>TtqqAqzD4PRZV-bt+%vEtUDfOTvxt9>s0sDXt<-Q#aS< z4j@!b3q#EQ)@5Z6Xc9B+n*fl{%4&4|Zq!II9fpE5#gU?qql)__ijgxRPD1X#e!@nK zW;wOZ&_m&fircD8hjG?AfT4lucqwH^)^x?h-M*!6T6=ADj5GS1sMvqj00%>-Zk<`S zW)$A(db03aFDga@x|u?8L@M6e?J;u%2RVXN@xK>GmBgmt-J-F4o@^zFyLy1Jez@1^ zY?fIV`cy1mM86#NoLpM|f5y7S!0#q5?Af;0(ti}*2#8_%{!$xi3u{Uyx}KPw5kZ(y z;6J&b9D*wPu-VN56)N`~R^ixJrs#>wd6#?i2_;e)FzAkeN~<98w)FR`#yQxQXlz$% zj_Z}`ojai%HpZ01-5G#xP^i%CZ4OsoC}| z%~@C|4+Q1K5&vCA^FIK~{~utCjufCY11*T^1!wz9jWK*j`FnMCo6`VgZ}{!Aoi3}o z5gz8RLPTBIW{-jd1&`AfUWQp^Z)wMpg!sTwGRHbUfcf?TkNLX@5dsxAJ9P(v_XLz= za2|f|!SOScZ*$|PC^gO^pR=zUQIZ@_yzP9X_$npyjvy$t*mM!RP&R+ z$_~Z!?dI~Bb`G1z_{KaI(|bc|h8ot%o({(wn z-n4?p3xn4BW}gpO{IaaTVW`ZdlTIgVcRjUqe%G z*9B@1Gmq;4x<0W6JXhsYch&j#Ih40Qj3Yc0n@(5~MDCQ8nG$uMGDO}!`}S4URNwMX zG)8gg)F_RZ}$O=ynt7Iv$dQ-p9hX&7nbe(IA>hnRSb1`9$J$b z!eb39E!RP^Mksa)qCN6%L;F3cl`Y68A?jzETufK$X}cdg7N9ru?v(?cf@e+mg^4l; zx#c1ts@_8E+3y1Vs*u??l5GaBLXwDd6{U{;>9B6xuhMq}wuvA4IVvHP=_-2j#g;LEN2q$85;ok(Qi+RwV)>~!c1$Tc+xeQOVX661 z7#x3Ne}zt3+m7h_l6cHY=|ny_hY$dZ*n@&n{UraopK;)ndZEQaD1Jy@5Vd%_i9bt6 zg53uErIhX&eaTc!LQtEvg^${Zjgqham&RF9F%qd@NJ-KZ7N7XstVA73o0{|J4g=Jv zL7j@y4a%K?-~(4=KKYTjHaPFk%1r#Z*{Fvk-RDo$Kr+uprp?Dtw)2mAmavnXbPg5S z-S30SPv}kGSCB>W@l}7$V|TCn^Mzkki>+q7J`g=LSD+TkGcXDyC+Vf7yxR6bqInc>itWQxBG0e4JH!;xAnbB15)E?7&kYbG3M= z0({CKWP3Ee@Vow`P6D=I)OR7{V3y=<`1qHtcV_B%+)uMM)4@)c#9eW)S6Tgw%yRP8 zjevjV2j<|&=d5PMsS&FmWal2n^H<9%i0PmD;U2+K z#hwpq*pg9QrU4J3;8}jVzaxA@Qqxz{$5o`M_C2GF`U{&_*MRnm8Tyvh?+?p~dcf?- zP2PS6mk-;$nTcQbkn$>G*_E{aytWZtF@NAOa6%EebtE@k#VNEyM z;fY4#5!mtLg>Ccwc-h*=FtGZHvVB2sp44X;v;i?};9}Fn@^v89)lYGvwOi|`!}Omy z3*lHi9uXqVlf5yD?iU3gu)EPCbM%BnVrk5ccwG{^e6W^D=A|O1a5Jk>PMT0FW;to-0AwR&tGp>=VEb_+=mC0P@{##R|GOg|Q%Z5QTBEl94kb5d~DJAANzTtmO7muCU5 zCoFWYMG(vBmw&vOd?kgFWCBIIeZc_T-!x9W&XGXFmP_`^9R=3?eKvC4n$R zdC9~U;`5;EUC6a8+gCEn&M~(mWjru_7Pj4w%*2C~se|7P&4*a1lhXP`N8C1j+5r&C8Vn7C0>qf%mVx8T6NSVCI>=t zYHwOA|FN`Mp}$l@El!rMnQSPu#mOxT00~rk^7`U zW-OhqXPxh#lA@}KG&Nm`4fyyiBJ&{fWMo>-$xrhBWI3gR993`oYl52KcBv=9rGbn9 z$xg2ocF=2>zT6Qlvh1&z+kz9w=984so(0~+!|m@L-9qM0)MooUWEpT2QE_U>`Uevl z+YrCt+l#f!r$+Gu+URC5*DtR13JLpsPKL^PiYC9-dE&dqkTh!1<*uvo#)KzAVtDVF z@oMIiIlG+*un}5c8gSgQ9fBQ5o1~gpAJpFWDf z4iuP>4~`{?U&J-Sr+U-<>GstE^%6q1d;+a00m5s)G;9|wW)iZW) z0+r;Qn#)gr44`y&#kbaR4P7dyPy0E7EWMlDpBvcm1u2in`u>z{*VjSVQ>RALkZU}F zxGaw!d@U~WIb_P9A_78f?3vt(()WZ_9859K`jQ*wN-43{M0id3VOEZcmQn~0b+BVh zcG(oj>*`)SKhI3lLj^EEOjR>k(PLZI_m^RV&JZTSlSx)GH4gdkoeKB5Qm53J1?Fes zn$<>r&fi{p=0b-sUjd7~v%Pu(@!pKTFnwQCXUX5ku7_f=AlYriA$vs>JrI$lquz-D z8~KFTlu|Rp1Rr#z=CW`Qb>vKyC;8qggqJnR*|&5B?`P^reTxB~0e5}NqZq+4UFVA+ zJI-3iV@O+K%vlNnQf~M5LmjV}j9>wK`=En8p$4IPs-_K$k;jB~G(O4BvwVNf;T7j3 z(XXiN$5M36`52`oLN&86M0ZWFHcB##qZaG4PF`|Rk#D?g6sn=P@BO&g>kiHCzstwq<5JbUny(hs{ft)$m1TLuKBpD9 zJcLGHUccG@JZPhHTETLVO!kQ;WNWLevIPoKZ@dZ5_Rvn^-ywba$_sR59RzUeEB2RU zhwa!Sn72Kv+2rWX_ouln_x24wE4{ro4Ts$`6uGT~3lSMv+`fZNPng$OsC|j%;PX5> zf5G=`@|@FRYYmIs13M0Wl&8oD`wkOB@bnLUyrZ(eh+C*#eKntF>)2Ld!p}Z&I!cX- zlHWNclK&(uGX$%aGKu!Lru{Y*6komvY|E?3&~Is{jb9|oRs{$$lummHH`3#?s&{Yi ziqvSLuSnCn*~7u7(SaO5Af(dDSVoUO-Gzoq{ekqKm~~L32Wfp&yP5i`TYHds^Ptg5 zm3<5LsEy3x5eugZjnxKE^F7a`)?y`vP>7gvY@W;dnL1SG!Uonfa%*-CO1;M%*XX6kWOP6F;UiqL0w4U zl}ZGrFFfAeTQx2J=~D5iqVQC8^t-2mpPhS|5prf1z(*r$ql-~|Vb+B{59+Wcp-rUn$32HqJ zOZIu-L<(!tb9t6g8<M~9^FP^W-_dg}DT2QM| zdMF79SvAu0Nrw~8X8%#Mi^?^9)m@XzjrWR=0`9x|?+k9Op8nKYlJ&(V|L!WBnXsa4 zy;l7k%nZ`23cqsyAs$g<_A%IYlNpNKE9FzeqD*7x)|HbZQB0#35xzUMX3VACKXYFF zk{FZW?6!~VuKizX;KOQH-%Uy7OUWJ(H`J;wf#&vuJn-9B^jcSY%FOvTR=BJ_bHK zH0=x-X4~}5A~0Yc1PTUu;f7(~dSQbApZ)JiGeVb3ipzv~wnJnYjhS9OOEiIk?rIFvX258WF+ad*p+A=@(~w@` zB_jVYn|RVRgT-_$=$d5EMQWQVx3xu|0cJwb!+E=j9?=L1S;I-K^WZy>7i2?JlXGk> zk`D~F3pN3u<-`jv$Kxru!z0QCAfIdY43W?d*e2!7F>u-si(xDGeci8y=eocv_g>jP zY-;6%WhZH_F>r*slMp{XrNP?kZ10JGK=(&$YvF~K($5Z zDyA{NGE8zl`a?Pe0nn>L_rgT*tKd-BoRp0DHaekIu2n2R7~kpKXQSkS2U;L7{= z2?>DzGMDlkaDiO1H#Y{#JFznWAbQ7wN^uPH_?{j9@T9pU_k(jO9#h6(2$I!`6M5YtClYDlB@=R-Z zV7t4q@x?}r_N5Q+v+7rV|NeEhGix(zv+-BtMn|^rXgrK|$^(kqEsl%ZMA)LrMa5m{ z0DN>A2SL8pHG*D*g~1cX+dNpPTpSCN`6*G+h%#1J>8uDN&=jvv>WmB7a`Xe|dxRj! zZdx9>Lm!G!V(*UBHKsFk?0sys*}(r-Tt}UGDexXMfYs9Gp^X4!z8{qR-daRDjnras zHa^r|iCKLa;CQ&R{?8rf#hi$F4wXm~BGqJDkGKMYeqMKZmClJu(5*=;N|Z(AkUQ+N z^r8lNon7)D_60JLxtCaT&wAtu;8C3LhFtsLms@poPKK#c9xhWdQ2q8SBO7mCsg8jA z`rG+;tk(j=k0jqau<%bo`hSm41p5s3G*>L=H_QZ*A3A8bip zc!4F*yhCLdE}Ly|H#_rImrpY}=%s-``zM$%~hi}vCuk$K=z(Qda?FJVBWy+|sZVP*O`>gw5v5oe8s$?UT) zZ)10x^2dCyhHpn{11xOG)73%tC{oJWn@Sb#*9Cz2 zxb$=(u2(HZRh~rFM4?&7D^w;%V!HN@cc`^k13*+)7W=5P1Y<>9-4 zCyer5zKh7n7P791gNK)txSg)|Yrpt{=@alve|NLUX$Qi$Oh(!h%FUgif5>JQQ6=-B z3f#h4KQ_ugI14^fv@H{2R){-@Eu(%+@hSu5WDF&mJDf&Z`4o!h!~S^_viRrg3?;f7 zu27fk$W|paFPWOyqlAyi+`f7nJC(p}OZcu18Pp0mayh~QWl+s*Z_UK21B0^K=*Q6n zX3txz5AQOu#XIWGM|=&f&c%iH_+O|=Q*;<2&{Vo^w)nJPENA){zPchyACR0nr-p&= zKgKR;cS#+01g=i$5gsZ9_4-DVw`C@DAAFLr5bWUXC2A@W`(e>_&vn5*>pT86~ zrv+S@xEE8OOrVk1Unn|=p0r1Nwd25SB~8GTAkv?Ms{ez5S02Zc$en03>nhp?5|nhp z-B+ss=UXSr^0Q_u0}Fc&mdO5cKt&#Vs>1aIHu_uAR27ja@lO{CZo#EeXqIAV=Iw&L zvhbx74Ko9-spHt`^9Q1^d_P1jXH|UaWU_VZUYv^g^;?B(F zDs%hs`4{a+@qk#msi%Jk(!N}-m#+_LZkY(`!`@}2l?YD|S`LLdBE=H}g1}^R0-4>P z!`%_){iD=Omd@alN_ENX9Y1_LV4*BC%5o3LDi_+9eqk$=O{FYD zQ+ut!JP$WBXHM?cw$X#aEpDuDHiOlWU=9}D&#KyOy@nM5*Ux;I~${Ab6=M8nT{(*j(C z?#Gnzo#>KLmX-DVP(JP;^y#`iAakob4x2IUaMN@?1>$(?CD8mwDvqcM%IJ&q2o(CJupg*fgt^; zA9sVz!RcgL|z<`CiBy2VwxCT{`}Hf&p!9H+9KQ^-2hiM7lIv4@-rk6nI}od zZx^VB2+>b&=E*v%Bej}x+=8<-@wzV#Z;JxOHe8)fDUA1MLycxU;B%R^YFW_VZZK8U zR8SF4rh4lFtW<|bO^vpkddp&Et}i~=|H0$&jiG_UVRzpJKVJuqbU`6DG9ya7x%RV@ z+k-d)@6YuDY-HH#hYWewnM^0^dyM&(5@qvP?v!4S+JxA88|b0@ikSZeDzd6rCC%&G z*G5sJzhg&Z!lW&0?AX5zg8&a>?RB)zZ{%_yU@mq7)mgtks%&;YnDbM%a$d9Fp5cZL zzY>ryoXk3|iLXsMWw)Jg@OUFzF(ZB!lPO8PI>zKrUyKSXEmjmQ(S;`z9?&A2MIZF^ zPPo5lM!`>$r*0?k_MlIcT_!&SSxfBUADJ|zKxdL{*_J>6vbD?V5>niD7X5Z|a?CY&YS13NYk<_HVq?Clv6R(8U z?R5LkM-R*UB14gfG^^7%6Yd0F=`7*x#YAS~y9`{cz>kP`!rg9x7;iJvtV@Lai3x#vz7U+H3_%pkS9grS&K-t_W_I=G95s?F94v z9nxx~y6!(*in|%C0sYbCZn_W8>j$9*%2d(Z76uA&o%N}ve2?p|Kd8qiAMU=tz(3@2 zI;Z1?j}6N7Uk?~DR_8WL@+Cl#7en*2P8nei4A41ox?s`LUJc#>AS%L*y}kJwmWgg9 zUrAvO7FXbG1cF{3&3esf%md@3df%}BYz)*|D4zhfrQsAw4Brj#ulo@%A=C5^6a=*z zAFV+7BQhe{az{XM6=p`FS&)&#Z^mYrHv^NLKt~hsV{5gqF*(HmbL(hioH{QR5Or{u z?}(Ru@K3|{;VMki^IAGies*|nsb$i+8c+X-0L^IuSLJFuGf~!QPFx)(!wq zvOWB2mPwK7UY^y;$S;KqI=KdM$*vT*) zK5u6Dx}Y;a+#=VFf|+oEjP%lCgfG9t@ggDH8m0@0_3=jOAf1)s&7=}36Hm&5K$rZ( zj-$rV9>iFdfd_Rmim{jTX%}!=U>)I?0w={qQ#MUKbGL7>A z`ZLoR8laOw5B~=bKGOE86$({C@hbzh$C4q$iWwv5zho-leLR4Gg&WXMij|U|3!?Uc z54{B!bpK-EYkGJ`K!a@aT5_~tsDl*W40tS{+}imHW`zU;KnBW%i}F8H>^M^ZHaAVG z1%}$E%5&jQ`{xp9H3k2GJMX-yVYhv4tK?k?!$WlnqclsZ-6X~#UWOJSxVn1yk zMEhUDY0~`}7E05(N<1zkN|h3^bB5AVygQI61T*rt7d!Wm@Xs+aSz;qcuIoQi5I_d+qOUzd?04B0=gCMs!H&C9nKKi3 zR377Qec4vkmI~&7FQm>m`=)&}#F;bVWs`1yHp3NGB@9O9QDp4T!0SgczAf(|@{%A? zMsZ>$1Qbt=nU9@=xEJmFTd07CZ{q0k%GQamnh@TS-pfr<(-LvJ0r%NMEesJwSU6zx zS56`(5yjKwQB(S^zye_vEke&re5pdqj~1Hb{$|N$h*Y5oc<}ZNUObp_`dF~lWL?=n zN_EfE%zF(Y33tM3&OEh(-9%`)8mUuTr$(-+NgoAERSXzTE1ATq(2eXUDk-ZU^fgu+ z+s*>gg74d{J^>W=te#R#yVaN#9}e<#m)8CA=!Nn_j>iFaNB<^6_@*X3splZKa_YP> zCqZeB>OEODPzGq0)&n_=#^M3a&y~z6^5kHLkXEvH0dw_aaSf!;!yrtI5(ufNS`TNF zV;vY)N;6NeJ?}=trRN?1e-2E-oqi3zN7x&5-Q7G|&%i``#8_oHbb`;a!sm3{OV|(g zH52V;;t*s$EVz81u+VZzpvl+)3DJ(OBQOF}oCi=|h>mC@;?MY)LNQeIQJ7u`{ zJZ;%jY7895ny3XpaW%%mxQ53m{aK5`!FxM#OtgQ^6q$UlHB6%bAlDvRnM+{UE{(8!DZl1T`?> zm;kFuyH*?&Ajp&opHy{TCy4N*xM)ik0%6O!78FSV?}wHhh!CW`?`XzlInbckIkx@( dd>{9BM~KT8j7TQe8=O}G3sW0vx$!B+e*v?pwyFRC literal 0 HcmV?d00001 diff --git a/ohos/ohos/src/main/resources/base/media/flash_open.png b/ohos/ohos/src/main/resources/base/media/flash_open.png new file mode 100644 index 0000000000000000000000000000000000000000..7cdd0b1d5bf1a7f73b4ce0fecccf24cab3d97686 GIT binary patch literal 2797 zcmcJRdpwlcAIHzkFcYCEiE-PBnY39y*Gx?=Pr1z)ByEW@h-B6+*ECWSDQ$-FAW72Z zkzKo}v|ZhbWol7I8JCJOE2FS6l54+bcGJJVzkYu_&v|{%d4Ip>^Zh>OIp>`5^l(vC z)>Z}ps4^LjUT7Dx0F=v^j$6M^WRDj4|9o|qM)MPO zAJ1G;w$oN^4a760jUV9T>AX55(Gt%@G#7H#hpKESJ1$UP9q6N}9q1WrSg<-951)DE zmZI3}l#O>H?eJNh8%;mGZkApYTQ|LT{Mg6))9m`Yw&UE7zE7%;*G#q*PjSxrZ{pzy zbaKrDjP9mx40xR|(6CkwEED4h;N%t_&YX~#+H|yJ!x>9f7_GE&coQHqQ$kwLgwu>H}Ct|Hy#pQ zn-1-M(B&5heBM5l6dz}Z%8cw^_M{eIdXkgg*ExOCI6P1VU(z;>s<*Ht&#wtvT&Qst zsZJi~-30^*)tuVuekM2JoqPM}3TTLa{`TSqCN0bESP1k0xSZ;OyX_ zO#z8$m+DsEqRHR}$ZaL^V6gOpWH&Sae$!sDqM%FNx2|53HQO^0@m=TEf2Lk+e`z3n zJe9?tbNtt4+iw?DiS4b&)PY6htyrVE8_3~y4QZ`D#NGZ>{MiRy9L^bcAVIUjUlQ_* z^JFJ_Pv1(^=iNO2c*53}DY8Eo6*Qv;f@f5G-wmk4cD=qkSyMPNYjgkbT|?6oXZNU) zSBje}NL;0T6l-wij&(@e->dljAU@8)5r{IQy6R3U>(zIV?4C4%k#BlS>rH=w-f z-LsK%uEA+PPLLiJ^c?Y7f_LWpumpR!moLFu8>L_2XUN_!@RWZ}%on)pxclQTuy6lH zPX3q3$zsHB3ErEtB(y8aePjtP-YESFcOgrfr@R|i-3bT*tE?)kEzUJ4;&6h?(Rz8; z6(XJY0E@;N4_6;7&2T*^2xJpVzdKP#TE%O%y7pJhxrVmw1ZXI!yBy0JP^RF>if-Ya zDbz!0+c1J{&erSDsM}5e##%!iI8bTd12ceJF5ok+D^vy$f!EVkJhBJty-5Ll8$SFn z=DQQdx`4OZI&SOca}A_c0x|WM<;)uj?EyACEjK?1rXE_?iD?QBKj3q&p+JQ|%(<>{ zVEk2Y@4a8&9GTOLKaC`5jy;I6;q3``r*aFCKb?!TAZPbmul79=$jZ1a&ux{Uky+bb zPBAQd-EqpdhyXczh`03hQ*C>ankGiTjidP5ghOdal&p9DSsf<0e5cLrk%k5MKdk{u zykN%N`3%#1+2F*D(QmPgq=K8TI>eOPim7$1DFV6lVrxmx4}2m|a<`khu6DO*ih7dU z0R(K=x9&+li`z93@oW^J)4!bLM8UGrON4Zpd@)TtM;3PP1CI{(7^>HMicAgCYQ=yt zt~5LM8AcAzWN{`H0LL;vmHxds{nyJ^zUzfs;s3 z_e2!B2Nqr%X}Eesj)n2^sWw35+C@Q15uR%vr2D5+AjZT!S zdI88)xiW{r^hOpg-TX}&=I$=hU(Fx97^pRrhB=an^lP`U)}kWLYbrX|=dgQQ(dyR#E}iMd}*o$rEA&!A>|+%f(fmflw2i98FJ~R1iEo zRrz=qUh*saDpJ>|RGv+him;Qq(6hS$VUj=>pGTps*MoFGwp6wGtp<<}vbfK>4Mbsb2aN(HVGBi%cI&iEfdGP2m>n)5V1mGW zl5vUUx0wKti}|0+tZ?!=#P&F9L)Ot@jR#YCFASw`RI}bh=b$ny61=UK35_WW!tOO9 z9W-N|^S?_=Fi@R=RIl(-qX;Jo6L7yXxV^X zH=IjoK#~umnJ7vxqZbUTNY@@b@0wopk3TK9!I7Oijj%Cgh?vv|aZlmo+i`rUI%e~B zk;A*2pJpu7Kzhft67T3%Q4-&TY}<(e1)PDvztlnCmMa~fSBZev!#{9VT>zC(GF^&b zkldWPVO^}y0dBX{=f|x@^Au#yJwkh^@R-@x9vv`Y!i=)kKO46dB`y~vm8vDCUaX#s zZ_Coka=M4=L^p6H-bF!NYa&IIrU(96iK9nS=bc2I87*rg4gpBz>Y_``3UauM6?YWI z6Z5M-&)F-F=g0l@VLjrG>VDMi*ONyR{sE7f>!;m(gsvabeXNj0@e8!Ub4t+iT20Gz zB+h94-L28zsbjzo>dp+cx|3qX``)a;a5f%5vu&B}#%SF&+=kMRp(2h|mrN?7w=>0@ z%~$+U;r;K2Yf@0H4}vp?#TX!^ZJ}2UfdAn>zuci@!^fD`!4dTS3YbnFj+NU2QvM5Z C6xWyl literal 0 HcmV?d00001 diff --git a/ohos/pubspec.yaml b/ohos/pubspec.yaml new file mode 100644 index 0000000..73c49dd --- /dev/null +++ b/ohos/pubspec.yaml @@ -0,0 +1,31 @@ +name: flutter_barcode_scanner_ohos +description: a plugin for Flutter apps that adds barcode scanning support on Ohos. +version: 1.0.0 +repository: https://gitee.com/openharmony-sig/fluttertpc_flutter_barcode_scanner/tree/master/ohos + + +environment: + sdk: '>=2.19.6 <3.0.0' + flutter: ">=2.5.0" + +dependencies: + flutter: + sdk: flutter + plugin_platform_interface: ^2.0.2 + flutter_plugin_android_lifecycle: ^2.0.1 + + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + pedantic: ^1.11.0 + test: ^1.16.8 + +# The following section is specific to Flutter packages. +flutter: + plugin: + platforms: + ohos: + package: com.example.flutter_barcode_scanner_ohos + pluginClass: FlutterBarcodeScannerOhosPlugin \ No newline at end of file diff --git a/ohos/test/flutter_barcode_scanner_ohos_test.dart b/ohos/test/flutter_barcode_scanner_ohos_test.dart new file mode 100644 index 0000000..c12c9be --- /dev/null +++ b/ohos/test/flutter_barcode_scanner_ohos_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_barcode_scanner_ohos/flutter_barcode_scanner_ohos.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + const MethodChannel methodChannel = MethodChannel('flutter_barcode_scanner'); + + TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger + .setMockMethodCallHandler( + methodChannel, + (message) => null, + ); + + test('QRScan', () async { + String barcodeScanRes = ''; + barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + '#ff6666', 'Cancel', true, ScanMode.qr); + // Assert + expect(barcodeScanRes, isNotNull); + }); + + test('BarcodeScan', () async { + String barcodeScanRes = ''; + barcodeScanRes = await FlutterBarcodeScanner.scanBarcode( + '#ff6666', 'Cancel', true, ScanMode.barcode); + // Assert + expect(barcodeScanRes, isNotNull); + }); + + test('startBarcodeScanStream', () async { + FlutterBarcodeScanner.getBarcodeStreamReceiver( + '#ff6666', 'Cancel', true, ScanMode.barcode)! + .listen((barcode) => { + // Assert + expect(barcode, isNotNull) + }); + }); +} -- Gitee