查看: 135|回复: 0

HarmonyOS 7 Scan Kit 硬件探测与扫码降级实战

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
背景:泛终端扫码绑定为什么需要前置探测
在泛终端项目中,“扫码绑定设备”经常被低估。同一应用可能运行在旗舰手机、轻量智能手表、无摄像头智慧屏、只有前置弱摄像头的教育平板上。早期做法是硬编码机型,或在拉起相机流后捕获异常。这种被动防御很脆弱:低内存设备上强行拉起带 AR 动画和复杂取景框的 Custom Scan,可能触发 OOM 崩溃;更严重时相机 HAL 死锁,影响系统稳定性;即使捕获异常,用户面对黑屏后的延迟报错,体验也很糟糕。
HarmonyOS 7.0(API 26)的 Scan Kit 增加了硬件探测能力。系统级 API 可直接查询当前设备是否支持自定义界面扫码、是否支持默认界面扫码。这样可在业务逻辑发生前,根据硬件拓扑设计 UI 降级:能力不足时降级到系统默认低开销扫码,无摄像头设备则降级为手动输入或局域网发现。

Scan Kit 两个探针 API 的定位
API 26 中,@kit.ScanKit 模块下的 scanCore 命名空间新增了 isCustomScanSupported() 和 isDefaultScanSupported()。它们返回 boolean,背后联动操作系统设备信息树与硬件资源水位线。
isCustomScanSupported() 面向自定义扫码。Custom Scan 需要应用自行接管相机数据流,通常为 YUV 格式,在应用进程空间分配大量 Buffer,并通过 NPU 或 CPU 做高频图像帧特征提取和解码。返回 true 的隐式条件很苛刻:设备必须有满足基础分辨率和对焦能力的后置摄像头;系统评估当前可用连续内存足够承载高频渲染与解码流水线;设备 CPU 或 NPU 有足够算力在规定时间完成条码识别,避免主线程阻塞或发热过载。任一条件不满足就返回 false,从源头阻止应用强行拉起沉重自定义 UI。
isDefaultScanSupported() 面向默认扫码。Default Scan 是 HarmonyOS 系统提供的独立 Applet(小程序态或系统级 UI 进程)。相机流接管、解码运算、内存分配全部在操作系统特权进程中完成,应用进程只需等待返回的扫码结果 String。优势包括:极低进程开销,应用不需为相机流分配庞大内存;硬件级优化,系统进程可直接调用更底层硬件加速通道,低端手表也能流畅解析;安全性与解耦,避免应用直接操作底层相机 HAL 带来的不合规风险。在手表等穿戴设备上,通常 isCustomScanSupported() 返回 false,而 isDefaultScanSupported() 返回 true,这就是优雅降级的基础。

决策链路与工程结构
企业级架构要把硬件探测、权限申请、UI 路由分发串成健壮状态机。原则是:先探测高配,后探测低配,最后全面降级。这样可把业务从盲目试错转为确定性调度,消除弱摄像能力设备上的崩溃风险。
示例工程采用高内聚服务层封装,代码结构如下:
  1. entry/src/main/ets/
  2. ├── entryability/
  3. │   └── EntryAbility.ets
  4. ├── pages/
  5. │   ├── ScanEntryPage.ets
  6. │   ├── CustomScanPage.ets
  7. │   └── FallbackInputPage.ets
  8. └── services/
  9.     ├── ScanHardwareProbe.ets
  10.     └── PermissionManager.ets
复制代码
ScanHardwareProbe 是硬件能力探测与决策中枢,PermissionManager 负责相机权限调度。

封装硬件探针:能力分级
在 services/ScanHardwareProbe.ets 中,定义能力枚举,严格区分旗舰级自定义、标准级默认、无能力三档:
  1. export enum ScanCapabilityLevel {
  2.   CUSTOM_SUPPORTED = 0,
  3.   DEFAULT_ONLY_SUPPORTED = 1,
  4.   UNSUPPORTED = 2
  5. }
复制代码
评估方法建议异步实现,因为底层可能实时读取硬件设备树状态,避免阻塞应用主线程。核心探测顺序是:
  1. import { scanCore } from '@kit.ScanKit';
  2. const canCustom = scanCore.isCustomScanSupported();
  3. if (canCustom) {
  4.   return ScanCapabilityLevel.CUSTOM_SUPPORTED;
  5. }
  6. const canDefault = scanCore.isDefaultScanSupported();
  7. if (canDefault) {
  8.   return ScanCapabilityLevel.DEFAULT_ONLY_SUPPORTED;
  9. }
  10. return ScanCapabilityLevel.UNSUPPORTED;
复制代码
异常应统一视为 UNSUPPORTED,确保应用不崩溃,符合防御性编程。原文代码还使用 hilog 记录探针结果,便于在不同设备上追踪降级链路。

入口页调度与默认扫码降级
在 ScanEntryPage.ets 中,用户点击扫码按钮后先调用探针,再按能力分发。用 isLoading 防止重复点击引发竞态。分发逻辑如下:
  1. const capability = await ScanHardwareProbe.evaluateScanCapability();
  2. switch (capability) {
  3.   case ScanCapabilityLevel.CUSTOM_SUPPORTED:
  4.     router.pushUrl({ url: 'pages/CustomScanPage' });
  5.     break;
  6.   case ScanCapabilityLevel.DEFAULT_ONLY_SUPPORTED:
  7.     this.launchSystemDefaultScan();
  8.     break;
  9.   case ScanCapabilityLevel.UNSUPPORTED:
  10.     router.pushUrl({ url: 'pages/FallbackInputPage' });
  11.     break;
  12. }
复制代码
当进入 DEFAULT_ONLY_SUPPORTED,应用调用系统默认扫码。构造 ScanOptions 时可限制只扫描二维码和一维码,以提高系统底层解码速度,并开启自动连续对焦。startVisibleScan 会拉起系统扫码 UI,应用进程挂起等待结果:
  1. const options: scanBarcode.ScanOptions = {
  2.   scanTypes: [scanCore.ScanType.QR_CODE, scanCore.ScanType.EAN13],
  3.   enableMultiMode: true
  4. };
  5. scanBarcode.startVisibleScan(getContext(this), options)
  6.   .then((result: scanBarcode.ScanResult) => {
  7.     this.processBindLogic(result.originalValue);
  8.   })
  9.   .catch((error: BusinessError) => {
  10.     // 处理用户取消或超时
  11.   });
复制代码
拿到 originalValue 后继续绑定验证。UNSUPPORTED 则路由到 FallbackInputPage,让用户手动输入设备 SN 码,或在无摄像头智慧屏上走手动绑定码、局域网发现模式。原文提到,无摄像头智慧屏端可隐藏扫码按钮,或点击后平滑过渡到“请输入设备绑定码”纯表单界面。

四类真实场景的分发结果
1. 折叠屏旗舰手机(如 Mate X 系列):顶级 NPU、大运存、主摄性能极速。isCustomScanSupported 返回 true,进入 CustomScanPage,可渲染环境光监测动态按钮和复杂 AR 扫描取景框,提供顺滑科技感体验。
2. 轻量级智能手表(Watch 系列):屏幕小、运存紧张、摄像头以基础前置为主。Custom 返回 false,Default 返回 true。应用拦截拉起 Custom Scan 的危险操作,转入系统独立进程的 Default Scan,降低内存吃紧,避免 OOM,同时完成扫码。
3. 无摄像头商显智慧屏:两个探测 API 均返回 false。探测到全无支持后,直接路由 FallbackInputPage,提示用户用遥控器输入设备配对码,或展示局域网内的自动发现设备列表。
4. 高负载发热降频手机:硬件本身好,但后台任务繁重、内存剩余极低。系统在 API 内部评估内存水位低,Custom 动态返回 false,Default 返回 true。系统自我保护机制生效,自动降级默认扫码,保证核心扫码可用,而不是在内存危急时强行分配巨量 Buffer 导致进程被杀。

避坑指南
第一,权限状态与硬件探针不是强关联。isCustomScanSupported 探测的是物理硬件架构和系统运力,不是用户是否授予相机权限。即使用户在系统设置拒绝相机权限,只要旗舰机硬件满足,该方法仍可能返回 true。因此执行探测前必须配合 abilityAccessCtrl 显式检查和请求 ohos.permission.CAMERA,不能用探针结果替代权限校验。
第二,多模态平板横竖屏旋转陷阱。教育平板等设备上,若探测支持 Custom Scan 并进入自定义界面,开发者需自行处理 display.on('change') 带来的屏幕旋转;不做矩阵重映射,相机预览流会被拉伸变形。若降级到 Default Scan,系统级 Applet 会自动处理横竖屏,这是默认扫码的隐性红利。
第三,异步探针可能引发 UI 主线程挂起。虽然用 await 等待探针返回,但如果底层硬件总线处于异常重启状态,探针可能存在几十毫秒延迟。调用 evaluateScanCapability 期间应提供 Loading 反馈,例如 this.isLoading = true,避免用户毫无响应而疯狂连击,造成状态机紊乱。
第四,不要强制绕过探测。有些开发者为了统一多端视觉风格,忽略 isCustomScanSupported 返回 false,硬写代码强制初始化 Custom Scan。在 API 26 环境中,这种不合规行为会被底层系统服务层强行熔断,直接抛出未捕获的 C++ 侧异常。必须尊重探针决策。

总结
HarmonyOS 7.0 的 Scan Kit 通过 isDefaultScanSupported 与 isCustomScanSupported,把系统底层硬件拓扑和资源水位线传递给应用层。基于硬件探针的优雅降级架构,改变了过去依赖机型黑名单和异常捕获的被动防御。通过前置探测、状态分发、系统进程接管、表单兜底,跨设备部署的稳定性更好,也避免了非授权访问底层 HAL 资源带来的合规风险。泛终端开发中,感知硬件水位、执行优雅降级应成为架构习惯:尊重不同形态设备的物理约束,才能写出企业级健壮的万物互联应用。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-24 09:19 , Processed in 0.021566 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部