HarmonyOS 鸿蒙Next 自定义扫码Demo

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 自定义扫码Demo

各位,有没有自定义扫码Demo

2 回复
import { scanCore, scanBarcode, customScan, detectBarcode } from '@kit.ScanKit';
// 导入功能涉及的权限申请、回调接口
import { router, promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { common, abilityAccessCtrl } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { uri } from '@kit.ArkTS';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct CustomScanDemo {
  [@State](/user/State) userGrant: boolean = false
  [@State](/user/State) surfaceId: string = ''
  [@State](/user/State) isShowBack: boolean = false
  [@State](/user/State) isFlashLightEnable: boolean = false
  [@State](/user/State) isFlashLightOpen: boolean = false
  // 设置预览流高度,默认单位:vp
  [@State](/user/State) cameraHeight: number = 640
  // 设置预览流宽度,默认单位:vp
  [@State](/user/State) cameraWidth: number = 360
  private mXComponentController: XComponentController = new XComponentController()
  private TAG: string = '[CustomScanDemo]'
  async showScanResult(result: Array<scanBarcode.ScanResult>) {
    if (result.length > 0) {
      // 打印测试结果,可在获取到结果后做相应处理
      hilog.info(0x0001, this.TAG, 'scan result: %{public}s', JSON.stringify(result));
      //获取到扫描结果后暂停相机流
      try {
        customScan.stop().then(() => {
          hilog.info(0x0001, this.TAG, 'stop success!');
          this.isFlashLightEnable = false;
        }).catch((error: BusinessError) => {
          hilog.error(0x0001, this.TAG, 'stop failed error: %{public}s ', JSON.stringify(error));
        })
      } catch (error) {
        hilog.error(0x0001, this.TAG, 'stop failed error: %{public}s ', JSON.stringify(error));
      }
      // 使用toast显示出扫码结果
      try {
        promptAction.showToast({
          message: JSON.stringify(result),
          duration: 5000
        });
      } catch (error) {
        hilog.error(0x0001, this.TAG, 'showToast error: %{public}s ', JSON.stringify(error));
      }
      this.isShowBack = true;
      this.isFlashLightEnable = false;
      router.pushUrl({
        url: "pages/DefaultScanDemo"
      })
    }
  }
  async reqPermissionsFromUser(): Promise<number[]> {
    hilog.info(0x0001, this.TAG, 'reqPermissionsFromUser start ')
    let context = getContext() as common.UIAbilityContext;
    let atManager = abilityAccessCtrl.createAtManager();
    let grantStatus = await atManager.requestPermissionsFromUser(context, ['ohos.permission.CAMERA']);
    return grantStatus.authResults;
  }
  // 申请相机权限
  async requestCameraPermission() {
    let grantStatus = await this.reqPermissionsFromUser()
    for (let i = 0; i < grantStatus.length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
        hilog.info(0x0001, this.TAG, 'requestPermissionsFromUser success');
        this.userGrant = true;
      }
    }
  }
  setDisplay() {
    // 默认竖屏
    this.cameraHeight = 800
    this.cameraWidth = 450
  }
  async onPageShow() {
    await this.requestCameraPermission();
    let options: scanBarcode.ScanOptions = {
      scanTypes: [scanCore.ScanType.ALL],
      enableMultiMode: true,
      enableAlbum: true
    }
    this.setDisplay();
    try {
      customScan.init(options);
    } catch (error) {
      hilog.error(0x0001, this.TAG, 'init fail, error: %{public}s ', JSON.stringify(error));
    }
  }
  async onPageHide() {
    // 页面消失或隐藏时,停止并释放相机流
    this.userGrant = false;
    try {
      await customScan.stop();
    } catch (error) {
      hilog.error(0x0001, this.TAG, 'Catch: stop error %{public}s', JSON.stringify(error));
    }
    try {
      customScan.release().then(() => {
        hilog.info(0x0001, this.TAG, 'release success!');
        this.isFlashLightEnable = false;
      }).catch((error: BusinessError) => {
        hilog.error(0x0001, this.TAG, 'release failed error: %{public}s ', JSON.stringify(error));
      })
    } catch (error) {
      hilog.error(0x0001, this.TAG, 'Catch: release error %{public}s', JSON.stringify(error));
    }
  }
  // 自定义扫码界面的顶部返回按钮和扫码提示
  [@Builder](/user/Builder)
  TopTool() {
    Column() {
      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
        Text('返回').fontColor(Color.White).fontWeight(FontWeight.Bold)
          .onClick(async () => {
            router.back();
          })
      }.padding({ left: 24, right: 24, top: 40 })
      Column() {
        Text('扫描二维码/条形码').fontColor(Color.White).fontWeight(FontWeight.Bold)
        Text('对准二维码/条形码,即可自动扫描').fontColor(Color.White).fontWeight(FontWeight.Bold)
      }.margin({ left: 24, right: 24, top: 24 })
    }
    .height(146)
    .width('100%')
  }
  build() {
    Stack() {
      if (this.userGrant) {
        Column() {
          XComponent({
            id: 'componentId',
            type: 'surface',
            controller: this.mXComponentController
          })
            .onLoad(async () => {
              hilog.info(0x0001, this.TAG, 'onLoad is called');
              // 获取XComponent组件的surfaceId
              this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
              hilog.info(0x0001, this.TAG, 'surfaceId: %{public}s ', this.surfaceId);
              let viewControl: customScan.ViewControl = {
                width: this.cameraWidth,
                height: this.cameraHeight,
                surfaceId: this.surfaceId
              };
              // 启动相机进行扫码
              try {
                this.isFlashLightEnable = true;
                customScan.start(viewControl)
                  .then(async (result: Array<scanBarcode.ScanResult>) => {
                    // 处理扫码结果
                    this.showScanResult(result);
                  })
              } catch (error) {
                hilog.error(0x0001, this.TAG, 'start fail, error: %{public}s ', JSON.stringify(error));
              }
            })// XComponent宽、高,默认单位vp,支持px、lpx、vp
            .width(this.cameraWidth)
            .height(this.cameraHeight)
            .position({ x: 0, y: 0 })
        }
        .height('100%')
        .width('100%')
      }
      Column() {
        this.TopTool()
        Column() {
        }
        .layoutWeight(1)
        .width('100%')
        // 闪光灯按钮,启动相机流后才能使用
        Column() {
          if (this.isFlashLightOpen) {
            Image($r('app.media.flash_off')).width(30).height(30)
          } else {
            Image($r('app.media.flash_on')).width(30).height(30)
          }
        }
        .justifyContent(FlexAlign.Center)
        .width(40)
        .height(40)
        .borderWidth(1)
        .borderRadius(20)
        .onClick(() => {
          // 根据当前闪光灯状态,选择打开或关闭闪关灯
          try {
            if (customScan.getFlashLightStatus()) {
              customScan.closeFlashLight();
            } else {
              customScan.openFlashLight();
            }
            this.isFlashLightOpen = !this.isFlashLightOpen;
          } catch (error) {
            hilog.error(0x0001, this.TAG, 'flashLight control failed, error: %{public}s', JSON.stringify(error));
          }
        }).position({ x: 90, y: 600 })
        .visibility((this.userGrant && this.isFlashLightEnable) ? Visibility.Visible : Visibility.None)
        // 系统图库
        Column() {
          Image($r('app.media.ic_public_picture')).width(30).height(30)
        }
        .justifyContent(FlexAlign.Center)
        .width(40)
        .height(40)
        .borderWidth(1)
        .borderRadius(20)
        .onClick(() => {
          if (customScan.getFlashLightStatus()) {
            customScan.closeFlashLight();
            this.isFlashLightOpen = false;
          }
          // 打开系统图库,选择图片扫描
          this.scanSystemPic()
        }).position({ x: 270, y: 600 })
        .visibility((this.userGrant && this.isFlashLightEnable) ? Visibility.Visible : Visibility.None)
        // 重新扫码按钮
        Button('Scan')
          .onClick(() => {
            // 点击按钮重启相机流,重新扫码
            try {
              this.isFlashLightEnable = true;
              customScan.start({ width: 1920, height: 1080, surfaceId: this.surfaceId })
                .then(async (result: Array<scanBarcode.ScanResult>) => {
                  // 处理扫码结果
                  this.showScanResult(result);
                })
            } catch (error) {
              hilog.error(0x0001, this.TAG, 'start fail, error: %{public}s ', JSON.stringify(error));
            }
            this.isShowBack = false;
          })
          .margin({ bottom: 30 })
          .visibility(this.isShowBack ? Visibility.Visible : Visibility.None)
      }
    }
    // 建议相机流设置为全屏
    .width('100%')
    .height('100%')
  }
  async scanSystemPic() {
    try {
      // 1、选择系统图片文件,获取文件管理器返回的文件可读uri
      let selectUri: string = '';
      let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
      photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
      photoSelectOptions.maxSelectNumber = 1;
      let photoPicker = new photoAccessHelper.PhotoViewPicker();
      await photoPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
        hilog.info(0x0001, this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult));
        if (photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {
          selectUri = photoSelectResult.photoUris[0];
        }
      }).catch((err: BusinessError) => {
        hilog.error(0x0001, this.TAG, 'PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
      });
      if(!selectUri) {
        hilog.error(0x0001, this.TAG, 'scanSystemPic failed, selectUri is null.');
        return;
      }
      // 2、识别图片
      try {
        // 定义识码参数options
        let options: scanBarcode.ScanOptions = { scanTypes: [scanCore.ScanType.ALL], enableMultiMode: true, enableAlbum: true }
        // 定义识码参数inputImage,其中uri为picker选择图片
        let inputImage: detectBarcode.InputImage = { uri: selectUri }
        // 调用图片识码接口
        await detectBarcode.decode(inputImage, options).then((result: Array<scanBarcode.ScanResult>) => {
          hilog.info(0x0001, this.TAG, 'Promise scan result: %{public}s', JSON.stringify(result));
          // 处理扫码结果
          this.showScanResult(result);
        }).catch((failResult: BusinessError) => {
          hilog.error(0x0001, this.TAG, 'Promise scan result: %{public}s', JSON.stringify(failResult));
        });
      } catch (error) {
        hilog.error(0x0001, this.TAG, 'Catch: failResult: %{public}s', JSON.stringify(error));
      }
    } catch (error) {
      hilog.error(0x0001, this.TAG, 'start fail, error: %{public}s ', JSON.stringify(error));
    }
  }
}

更多关于HarmonyOS 鸿蒙Next 自定义扫码Demo的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,自定义扫码Demo的实现主要依赖于ArkUI框架提供的组件和能力。以下是一个简要步骤,用于指导如何快速构建自定义扫码Demo:

  1. 项目创建:使用DevEco Studio创建新的HarmonyOS项目,选择“Empty Ability”模板。

  2. 界面设计:在resources/base/layout目录下创建或编辑XML布局文件,添加一个CameraKit组件用于扫码界面。

  3. 权限配置:在config.json文件中添加相机权限,确保应用有权限访问相机。

  4. 逻辑实现

    • 在对应的.ets文件中,通过@Entry装饰的组件类实现扫码逻辑。
    • 监听CameraKit的扫码结果事件,通过事件回调获取扫码内容。
    • 对扫码结果进行解析或处理,如跳转到对应页面或显示结果。
  5. 运行测试:将项目部署到鸿蒙设备或模拟器上,运行应用并测试扫码功能。

示例代码片段(仅示意,非完整代码):

@Entry
@Component
struct ScanCodePage {
  @State scanResult: string = '';

  @ConsumeScanResult
  handleScanResult(event: CustomEvent<string>) {
    this.scanResult = event.detail;
  }

  build() {
    Column() {
      CameraKit()
        .on('scanResult', this.handleScanResult);
      Text(this.scanResult);
    }.padding(16);
  }
}

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部