diff --git a/ohos/example/lib/main.dart b/ohos/example/lib/main.dart index 4aaac564d4aa259f2afd023cc8bdd47750bf4911..2c4afa1895123dc6ae561b660dd008878a2c92be 100644 --- a/ohos/example/lib/main.dart +++ b/ohos/example/lib/main.dart @@ -20,7 +20,7 @@ class _MyAppState extends State { Future startBarcodeScanStream() async { FlutterBarcodeScanner.getBarcodeStreamReceiver( - '#ff6666', 'Cancel', true, ScanMode.barcode)! + '#ff6666', 'Cancel', true, ScanMode.both)! .listen((barcode) => print(barcode)); } diff --git a/ohos/lib/flutter_barcode_scanner.dart b/ohos/lib/flutter_barcode_scanner.dart new file mode 100644 index 0000000000000000000000000000000000000000..fca2b2fe3c3383f0e2840ea63396082cd2f3b1cd --- /dev/null +++ b/ohos/lib/flutter_barcode_scanner.dart @@ -0,0 +1,67 @@ +import 'dart:async'; +import 'package:flutter/services.dart'; + +/// Scan mode which is either QR code or BARCODE +enum ScanMode { qr, barcode, both, 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/lib/flutter_barcode_scanner_ohos.dart b/ohos/lib/flutter_barcode_scanner_ohos.dart index 1b540e8ce5728955e739ef0b8bcf2a6f26098d18..5031d35afa804147f2d97e218f8b7f7b6f36c4d3 100644 --- a/ohos/lib/flutter_barcode_scanner_ohos.dart +++ b/ohos/lib/flutter_barcode_scanner_ohos.dart @@ -1,12 +1,10 @@ import 'dart:async'; - import 'package:flutter/services.dart'; /// Scan mode which is either QR code or BARCODE -enum ScanMode { qr, barcode, other } +enum ScanMode { qr, barcode, both, 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 { @@ -19,7 +17,6 @@ class FlutterBarcodeScanner { 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. @@ -28,7 +25,6 @@ class FlutterBarcodeScanner { if (cancelButtonText.isEmpty) { cancelButtonText = 'Cancel'; } - // Pass params to the plugin Map params = { 'lineColor': lineColor, @@ -37,7 +33,6 @@ class FlutterBarcodeScanner { 'isContinuousScan': false, 'scanMode': scanMode.index }; - /// Get barcode scan result final barcodeResult = await _channel.invokeMethod('scanBarcode', params) ?? ''; @@ -46,7 +41,6 @@ class FlutterBarcodeScanner { /// 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 @@ -56,7 +50,6 @@ class FlutterBarcodeScanner { if (cancelButtonText.isEmpty) { cancelButtonText = 'Cancel'; } - // Pass params to the plugin Map params = { 'lineColor': lineColor, @@ -65,11 +58,10 @@ class FlutterBarcodeScanner { '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; } -} +} \ No newline at end of file diff --git a/ohos/ohos/src/main/ets/components/plugin/CameraService.ets b/ohos/ohos/src/main/ets/components/plugin/CameraService.ets index dc9b66da4849a65a0cbbb7f02b11330f07f90fc1..e154d08a1e6270362739982ed7711f7bccb5c4ed 100644 --- a/ohos/ohos/src/main/ets/components/plugin/CameraService.ets +++ b/ohos/ohos/src/main/ets/components/plugin/CameraService.ets @@ -222,17 +222,16 @@ class CameraService { } // 获取扫描类型 - getType(scanMode: ScanMode) { - switch (scanMode) { - // 二维码 - case ScanMode.qr: - return [scanCore.ScanType.TWO_D_CODE]; - // 条形码 - case ScanMode.barcode: + getType(scanMode: ScanMode = ScanMode.both) { + if (scanMode == ScanMode.barcode) { return [scanCore.ScanType.ONE_D_CODE]; - default: + } else if (scanMode == ScanMode.qr) { + return [scanCore.ScanType.TWO_D_CODE]; + } else if (scanMode == ScanMode.both) { + return [scanCore.ScanType.ONE_D_CODE, scanCore.ScanType.TWO_D_CODE]; + } else { return [scanCore.ScanType.FORMAT_UNKNOWN]; - } + } } // 变焦 diff --git a/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets b/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets index f9d770f6cffc9eff338c8dd7c837fa493ffc2cde..e0ad6c82d264a110e4cbf8034971e21d92f9bb74 100644 --- a/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets +++ b/ohos/ohos/src/main/ets/components/plugin/FlutterBarcodeScannerOhosPlugin.ets @@ -13,7 +13,12 @@ * limitations under the License. */ -import { AbilityAware, AbilityPluginBinding, FlutterPlugin, FlutterPluginBinding, } from '@ohos/flutter_ohos'; +import { + AbilityAware, + AbilityPluginBinding, + FlutterPlugin, + FlutterPluginBinding, +} from '@ohos/flutter_ohos'; import { MethodCallHandlerImpl } from './MethodCallHandlerImpl'; import { UIAbility } from '@kit.AbilityKit'; diff --git a/ohos/ohos/src/main/ets/components/plugin/GlobalContext.ets b/ohos/ohos/src/main/ets/components/plugin/GlobalContext.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ce57dffa57c19c8f06c26216a443facbc6a0e9b --- /dev/null +++ b/ohos/ohos/src/main/ets/components/plugin/GlobalContext.ets @@ -0,0 +1,40 @@ +/** + * 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. + */ + +class GlobalContext { + private constructor() { + } + + private static instance: GlobalContext; + private _objects = new Map(); + + public static getContext(): GlobalContext { + if (!GlobalContext.instance) { + GlobalContext.instance = new GlobalContext(); + } + return GlobalContext.instance; + } + + getObject(value: string): Object | undefined { + console.log("aaaaaa"+this._objects.size) + return this._objects.get(value); + } + + setObject(key: string, objectClass: Object): void { + this._objects.set(key, objectClass); + } +} + +export { GlobalContext } \ 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 index 75f8fde37ba2d931747d2b31e1c70b4ee50416ed..001d4d515e65641590bb9514edd09da861ba2946 100644 --- a/ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets +++ b/ohos/ohos/src/main/ets/components/plugin/MethodCallHandlerImpl.ets @@ -13,12 +13,14 @@ * limitations under the License. */ -import { BinaryMessenger, EventChannel, MethodCall } from '@ohos/flutter_ohos'; +import { Any, 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'; +import { EventSink, StreamHandler } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel'; +import { GlobalContext } from './GlobalContext'; const TAG: string = "MethodCallHandlerImpl"; @@ -30,7 +32,16 @@ export class MethodCallHandlerImpl implements MethodCallHandler { 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.imageStreamChannel = new EventChannel(messenger, "flutter_barcode_scanner_receiver"); + + let streamHandler: StreamHandler = { + onListen(args: Any, imageStreamSink: EventSink): void { + GlobalContext.getContext().setObject("imageStreamSink", imageStreamSink); + }, + onCancel(args: Any): void { + } + } + this.imageStreamChannel.setStreamHandler(streamHandler); this.methodChannel.setMethodCallHandler(this); } @@ -44,7 +55,7 @@ export class MethodCallHandlerImpl implements MethodCallHandler { isContinuousScan: call.argument('isContinuousScan'), isShowFlashIcon: call.argument('isShowFlashIcon'), scanMode: call.argument('scanMode'), - }, result, this.imageStreamChannel) + }, result) break; } case 'dispose': { diff --git a/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets b/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets index fb12297fa58ad6edb4713f947c5f94dc5c8643ed..7e8c15312003136bddfa0343985e8960d11606af 100644 --- a/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets +++ b/ohos/ohos/src/main/ets/components/plugin/ScannerUtils.ets @@ -22,7 +22,8 @@ import { dialogBuilder } from './ScannerView'; const width: number = px2vp(display.getDefaultDisplaySync().width) const height: number = px2vp(display.getDefaultDisplaySync().height) -export enum ScanMode { qr, barcode, other } + +export enum ScanMode { qr, barcode, both, other } // 扫一扫全局弹窗页面 class ScannerDialog { @@ -37,7 +38,7 @@ class ScannerDialog { this.context = context; } - show(args: Any, result: MethodResult, imageStreamChannel: EventChannel) { + show(args: Any, result: MethodResult) { window.getLastWindow(this.context).then((windowClass) => { this.windowClass = windowClass; const uiContext = windowClass.getUIContext(); @@ -52,7 +53,6 @@ class ScannerDialog { isShowFlashIcon: args.isShowFlashIcon, isContinuousScan: args.isContinuousScan, scanMode: args.scanMode, - imageStreamChannel: imageStreamChannel, dialog: this })); ScannerDialog.promptAction = uiContext.getPromptAction(); @@ -76,7 +76,7 @@ class ScannerDialog { TransitionEffect.OPACITY.animation({ delay: 1000, duration: 1000 }).combine( TransitionEffect.translate({ x: 1000 }).animation({ duration: 1000 })) ), - onWillDismiss:(dismissDialogAction: DismissDialogAction)=> { + onWillDismiss: (dismissDialogAction: DismissDialogAction) => { if (dismissDialogAction.reason == DismissReason.PRESS_BACK) { this.context.eventHub.emit('press_back'); dismissDialogAction.dismiss() @@ -96,7 +96,7 @@ class ScannerDialog { if (data === window.WindowEventType.WINDOW_HIDDEN) { this.context.eventHub.emit('page_hide'); } - if(data===window.WindowEventType.WINDOW_DESTROYED) { + if (data === window.WindowEventType.WINDOW_DESTROYED) { this.context.eventHub.off('page_show'); this.context.eventHub.off('page_hide'); } @@ -118,7 +118,6 @@ interface ScannerParams { isShowFlashIcon: boolean; isContinuousScan: boolean; scanMode: ScanMode; - imageStreamChannel: EventChannel; dialog: ScannerDialog } @@ -129,7 +128,6 @@ class Params { isShowFlashIcon: boolean; isContinuousScan: boolean; scanMode: ScanMode; - imageStreamChannel: EventChannel; dialog: ScannerDialog; constructor(param: ScannerParams) { @@ -139,7 +137,6 @@ class Params { this.isShowFlashIcon = param.isShowFlashIcon; this.isContinuousScan = param.isContinuousScan; this.scanMode = param.scanMode; - this.imageStreamChannel = param.imageStreamChannel; this.dialog = param.dialog; } } diff --git a/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets b/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets index a082cc8acbc5f5cd934592b0132719bb7f62f74a..f6864ec0a7fb42712256487ae69cd4e3d4c8766f 100644 --- a/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets +++ b/ohos/ohos/src/main/ets/components/plugin/ScannerView.ets @@ -22,6 +22,7 @@ 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'; +import { GlobalContext } from './GlobalContext'; const TAG = '[ScannerView]'; const width: number = px2vp(display.getDefaultDisplaySync().width) @@ -35,7 +36,6 @@ struct ScannerView { @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; @@ -49,13 +49,13 @@ struct ScannerView { private context: Context = getContext(this); private dialog: ScannerDialog = new ScannerDialog(this.context); private cameraService: CameraService = new CameraService(this.context); + private imageStreamSink: EventSink | null = null; 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) }) @@ -69,6 +69,7 @@ struct ScannerView { aboutToDisappear(): void { this.timer = null; + this.imageStreamSink = null; } onPageShow(): void { @@ -79,21 +80,12 @@ struct ScannerView { // 初始化扫描结果 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(); - } - } + this.imageStreamSink = GlobalContext.getContext().getObject("imageStreamSink") as EventSink; + if (this.imageStreamSink) { + this.cameraService.onImageArrival(this.cameraService.imageReceiver, this.result, true, + this.imageStreamSink, this.scanMode, null); } - that.imageStreamChannel!.setStreamHandler(streamHandler) } else { this.cameraService.onImageArrival(this.cameraService.imageReceiver, this.result, this.isContinuousScan, null, this.scanMode, (r: detectBarcode.DetectResult) => { @@ -101,7 +93,7 @@ struct ScannerView { this.result?.success(r.scanResults[0].originalValue); setTimeout(() => { this.cancel(); - }, 300); + }, 500); } }); } @@ -124,6 +116,7 @@ struct ScannerView { // 扫一扫初始化 scan() { + this.resultInit() const cameraManager = camera.getCameraManager(this.context); this.cameraService.createCamera(cameraManager); this.cameraService.initCamera(this.surfaceId); @@ -164,6 +157,7 @@ struct ScannerView { this.cameraService.setTorchMode(this.isOpen); await this.release(); this.dialog!.hide(); + this.imageStreamSink = null; } async release() { @@ -196,6 +190,7 @@ struct ScannerView { } .width('100%') .height('100%') + // 中间动画方格区域==================================================================start Column() { Column() { @@ -261,7 +256,7 @@ struct ScannerView { this.isFront = !this.isFront; this.cameraService.preFrontRelease().then(() => { this.cameraService.initCamera(this.surfaceId, this.isFront).then(() => { - if(this.isOpen) { + if (this.isOpen) { setTimeout(() => { this.cameraService.setTorchMode(this.isOpen); }, 200) @@ -269,6 +264,7 @@ struct ScannerView { }) }) }) + if (this.isShowFlashIcon) { Column() { Image(this.isOpen ? $r('app.media.flash_open') : $r('app.media.flash_close')) diff --git a/ohos/pubspec.yaml b/ohos/pubspec.yaml index 73c49dd89e1348653cb564cae8e9f048ede1a424..32327cf6f2a3cb261d92a7bda22c23f8e6cfccdd 100644 --- a/ohos/pubspec.yaml +++ b/ohos/pubspec.yaml @@ -3,7 +3,6 @@ description: a plugin for Flutter apps that adds barcode scanning support on Oho 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" @@ -14,7 +13,6 @@ dependencies: plugin_platform_interface: ^2.0.2 flutter_plugin_android_lifecycle: ^2.0.1 - dev_dependencies: flutter_test: sdk: flutter