diff --git a/example/ohos/entry/src/main/ets/entryability/CodeAbility.ets b/example/ohos/entry/src/main/ets/entryability/CodeAbility.ets index b3a9045f6e604a842f477abe89e0fcf90ce17161..19fae506b68ffa652d97d036ca7edd65079a5585 100644 --- a/example/ohos/entry/src/main/ets/entryability/CodeAbility.ets +++ b/example/ohos/entry/src/main/ets/entryability/CodeAbility.ets @@ -17,7 +17,7 @@ import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; -AppStorage.setOrCreate('codeInfo', {info: {}, uri: ''}); +AppStorage.setOrCreate('codeInfo', {info: {}, uri: '', config: {}}); export default class CodeAbility extends UIAbility { private want?: Want; @@ -28,7 +28,8 @@ export default class CodeAbility extends UIAbility { this.want = want; let info = this.want?.parameters?.info; let uri = this.want?.parameters?.uri; - AppStorage.setOrCreate('codeInfo', {info: info, uri}); + let config = this.want?.parameters?.config; + AppStorage.setOrCreate('codeInfo', {info: info, uri, config}); } onDestroy(): void { diff --git a/example/ohos/entry/src/main/ets/pages/CodePage.ets b/example/ohos/entry/src/main/ets/pages/CodePage.ets index b9ebb99d35ea4b297277fb09ddb3938717b9ce62..dbfcbf175344b5fdc5c6ed12cb02f4d962959afb 100644 --- a/example/ohos/entry/src/main/ets/pages/CodePage.ets +++ b/example/ohos/entry/src/main/ets/pages/CodePage.ets @@ -35,6 +35,15 @@ interface DetailInfo { interface CodeInfo { info: Array; uri: string; + config: Config +} + +interface Config { + icon: string, + iconWidth: number, + iconHeight: number, + cancelTitleFontSize: number, + cancelTitle: string } @Entry @@ -42,13 +51,29 @@ interface CodeInfo { struct CodePage { @StorageProp('codeInfo') codeInfo: CodeInfo = { info: [], - uri: '' + uri: '', + config: { + icon: '', + iconWidth: 0, + iconHeight: 0, + cancelTitleFontSize: 0, + cancelTitle: '' + } }; @State pixi: image.PixelMap | null = null; @State imgWidth: number = 0; @State imgHeight: number = 0; @State imgScale: number = 1; @State iconSize: number = 30; + @State pixiIcon: image.PixelMap | Resource = $r('app.media.bx_right_arrow'); + @State config: Config = { + icon: '', + iconWidth: 30, + iconHeight: 30, + cancelTitleFontSize: 16, + cancelTitle: '取消' + } + private screenW = display.getDefaultDisplaySync().width; aboutToAppear(): void { @@ -60,23 +85,37 @@ struct CodePage { this.imgScale = this.screenW / r.size.width; }); }); + + this.config.icon = this.codeInfo.config.icon ?? this.config.icon; + this.config.iconWidth = this.codeInfo.config.iconWidth ?? this.config.iconWidth; + this.config.iconHeight = this.codeInfo.config.iconHeight ?? this.config.iconHeight; + this.config.cancelTitleFontSize = this.codeInfo.config.cancelTitleFontSize ?? this.config.cancelTitleFontSize; + this.config.cancelTitle = this.codeInfo.config.cancelTitle ?? this.config.cancelTitle; + + if(!this.codeInfo.config.icon) { + return; + } + + image.createImageSource(this.codeInfo.config.icon).createPixelMap().then((r) => { + this.pixiIcon = r; + }) } getX(info: DetailInfo) { const codeWidth = info.scanCodeRect?.right - info.scanCodeRect?.left; const left = info.scanCodeRect?.left + codeWidth / 2; - return px2vp(left) * this.imgScale - this.iconSize / 2; + return px2vp(left) * this.imgScale - this.config.iconWidth / 2; } getY(info: DetailInfo) { const codeHeight = info.scanCodeRect?.bottom - info.scanCodeRect?.top; const top = info.scanCodeRect?.top + codeHeight / 2; - return px2vp(top) * this.imgScale - this.iconSize / 2; + return px2vp(top) * this.imgScale - this.config.iconHeight / 2; } build() { Column() { - Text($r('app.string.ui_cancel')).fontColor('#FFF').fontSize(20).position({ x: 10, y: 10 }).onClick(() => { + Text(this.config.cancelTitle).fontColor('#FFF').fontSize(this.config.cancelTitleFontSize).position({ x: 10, y: 10 }).onClick(() => { const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext const bundleManage = bundleManager.getBundleInfoForSelfSync(bundleFlags); let abilityResult: common.AbilityResult = { @@ -93,7 +132,7 @@ struct CodePage { if (this.pixi) { Image(this.pixi).width('100%') ForEach(this.codeInfo.info, (info: DetailInfo) => { - Image($r('app.media.bx_right_arrow')).width(this.iconSize) + Image(this.pixiIcon).width(this.config.iconWidth).height(this.config.iconHeight) .position({ x: this.getX(info), y: this.getY(info) }) .onClick(() => { const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext diff --git a/ohos/src/main/ets/dev/fluttercommunity/recognition_qrcode/RecognitionQrcodePlugin.ets b/ohos/src/main/ets/dev/fluttercommunity/recognition_qrcode/RecognitionQrcodePlugin.ets index d7f1cd427ed929a1dbb7a4e5501cd344ea175eab..9f8a3a44d29909693a30fd9f2916a0c157b33e09 100644 --- a/ohos/src/main/ets/dev/fluttercommunity/recognition_qrcode/RecognitionQrcodePlugin.ets +++ b/ohos/src/main/ets/dev/fluttercommunity/recognition_qrcode/RecognitionQrcodePlugin.ets @@ -31,6 +31,9 @@ import scanBarcode from '@hms.core.scan.scanBarcode'; import scanCore from '@hms.core.scan.scanCore'; import { BusinessError } from '@ohos.base'; import bundleManager from '@ohos.bundle.bundleManager'; +import fs from '@ohos.file.fs'; +import http from '@ohos.net.http'; +import { buffer , util } from '@kit.ArkTS' let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO const TAG: string = "RecognitionQrcode"; @@ -60,6 +63,7 @@ export class RecognitionQrcodePlugin implements FlutterPlugin, MethodCallHandler private methodChannel: MethodChannel | null = null; private applicationContext: Context | null = null; private ability: UIAbility | null = null; + private config: Map = new Map(); onAttachedToEngine(binding: FlutterPluginBinding): void { this.applicationContext = binding.getApplicationContext(); @@ -73,16 +77,32 @@ export class RecognitionQrcodePlugin implements FlutterPlugin, MethodCallHandler this.methodChannel = null; } - onMethodCall(call: MethodCall, result: MethodResult): void { + async onMethodCall(call: MethodCall, result: MethodResult) { if (call.method === "getPlatformVersion") { Log.d(TAG, deviceInfo.osFullName) result.success("Ohos " + deviceInfo.sdkApiVersion); } else if (call.method === 'setConfig') { + this.config = call.args; + if(call.args.get('icon')) { + const image: Uint8Array = call.args.get('icon'); + const url: string | null = this.saveCacheDir(image.buffer); + this.config.set('icon', url) + } + Log.d(TAG, JSON.stringify(call.args)) result.success(null); } else if (call.method === 'recognitionQrcode') { + let url: string | null = call.args; + if(url?.includes('http') || url?.includes('https')) { + url = await this.downloadHttpImage(call.args); + } else if(!url?.includes('/data/') && this.base64Decode(this.base64Encode(url as string)) == url) { + url = this.saveCacheDir(buffer.from(url, 'base64').buffer) + } + + if(!url) return; + // 定义识码参数inputImage,其中uri为picker选择图片 - let inputImage: detectBarcode.InputImage = { uri: call.args } + let inputImage: detectBarcode.InputImage = { uri: url } // 定义识码参数options let options: scanBarcode.ScanOptions = { scanTypes: [scanCore.ScanType.ALL], @@ -91,30 +111,72 @@ export class RecognitionQrcodePlugin implements FlutterPlugin, MethodCallHandler } // 调用图片识码接口 - detectBarcode.decode(inputImage, options).then((r: Array) => { - Log.d(TAG, JSON.stringify(r)); - if (r.length > 1) { - this.openAbility(r, inputImage.uri, result) - } else if (r.length === 1) { - result.success({ - code: "0", - value: r[0].originalValue, - result: r // 暴露给flutter让用户处理 - }); - } else { - result.error("-1", "Image parsing failed", null); - } - - }).catch((failResult: BusinessError) => { - Log.d(TAG, JSON.stringify(failResult)); - result.error("-1", "Image parsing failed", null); - }); - + this.decodeImage(inputImage, options, result) } else { result.notImplemented() } } + base64Encode(value: string) { + let base64Helper = new util.Base64Helper(); + let texEncoder = util.TextEncoder.create("utf-8"); + return base64Helper.encodeToStringSync(texEncoder.encodeInto(value)); + } + + base64Decode(value: string) { + let base64Helper = new util.Base64Helper(); + let texEncoder = util.TextDecoder.create("utf-8"); + return texEncoder.decodeWithStream(base64Helper.decodeSync(value)); + } + + decodeImage(inputImage: detectBarcode.InputImage, options: scanBarcode.ScanOptions, result: MethodResult) { + detectBarcode.decode(inputImage, options).then((r: Array) => { + Log.d(TAG, JSON.stringify(r)); + if (r.length > 1) { + this.openAbility(r, inputImage.uri, result) + } else if (r.length === 1) { + result.success({ + code: "0", + value: r[0].originalValue, + result: r // 暴露给flutter让用户处理 + }); + } else { + result.error("-1", "Image parsing failed", null); + } + + }).catch((failResult: BusinessError) => { + Log.d(TAG, JSON.stringify(failResult)); + result.error("-1", "Image parsing failed", null); + }); + } + + saveCacheDir(bmp: ArrayBufferLike) { + let filePath: string = this.applicationContext?.cacheDir + '/' + new Date().getTime().toString() + '.jpg'; + let outputFile = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + + try { + fs.writeSync(outputFile.fd, bmp) + } catch (e) { + return null; + } + + fs.closeSync(outputFile); + + return filePath; + } + + async downloadHttpImage(url: string): Promise { + let httpRequest = http.createHttp(); + try { + const data = await httpRequest.request(url); + return this.saveCacheDir(data.result as ArrayBuffer); + } catch (e) { + Log.e(TAG, 'download is field' + e); + } + + return null + } + openAbility(info: Array, uri: string, result: MethodResult) { const bundleManage = bundleManager.getBundleInfoForSelfSync(bundleFlags); Log.d(TAG, bundleManage.name); @@ -126,6 +188,13 @@ export class RecognitionQrcodePlugin implements FlutterPlugin, MethodCallHandler abilityName: 'CodeAbility', parameters: { // 自定义信息 + config: { + icon: this.config.get('icon'), + iconWidth: this.config.get('iconWidth'), + iconHeight: this.config.get('iconHeight'), + cancelTitleFontSize: this.config.get('cancelTitleFontSize'), + cancelTitle: this.config.get('cancelTitle') + }, info: info, uri: uri, }