Files
MrleeAdmin/frontend/scanapp/docs/mas-code-scan-iOS支持方案.md
T
2026-08-31 11:33:59 +08:00

25 KiB
Raw Blame History

mas-code-scan iOS 端支持方案

文档状态:方案设计,尚未开始 iOS 原生实现。

目标是在不改变现有业务调用方式的前提下,为 mas-code-scan 增加 iOS App 支持,并与 Android 端尽量保持相同的功能、参数语义、回调顺序和错误码。


1. 背景与目标

当前 mas-code-scan 是 Android UTS API 插件,Android 原生层基于 CameraX + Google ML Kit 实现。对外 API 已沉淀在 utssdk/interface.uts,业务页面通过 openCodeScan 调用,因此具备扩展 iOS 实现的良好基础。

1.1 当前状态

项目 当前情况
对外 API openCodeScan(options)
公共类型 CodeScanOptions、CodeScanSuccess、CodeScanFail、ScanRegion、CodeScanStyle
Android 实现 utssdk/app-android/,CameraX + Google ML Kit
iOS 实现 暂无 utssdk/app-ios/ 目录
业务调用 pages/scan/prototype.vue 只需调用统一 API
当前支持平台 Android App(uni-app Vue2/Vue3)

1.2 建设目标

  1. API 不变:iOS 与 Android 均使用 openCodeScan,业务页面不增加平台分支。
  2. 回调一致:统一 success、fail、complete 的数据结构和触发时机。
  3. 优先原生能力:使用 iOS 系统框架,尽量不新增第三方识别库。
  4. 功能分阶段交付:先完成可真机使用的最小链路,再逐步补齐 Android 已有能力。
  5. 平台差异显式处理:对系统不支持或实现成本较高的能力,明确降级或延后,不以静默不生效代替。

1.3 非目标

本期方案不包含:

  • 鸿蒙、H5、小程序、nvue 支持;
  • 修改 Android 识别链路;
  • 将扫码页改造为 Vue 组件;
  • 为尚未经过真机验证的 iOS 能力提前修改 README 平台声明。

2. 总体架构

2.1 目录规划

在保持现有 Android 目录不变的基础上新增 iOS 实现:

frontend/scanapp/uni_modules/mas-code-scan/
├── package.json
├── readme.md
├── changelog.md
└── utssdk/
    ├── interface.uts                 # Android / iOS 共用公开类型
    ├── unierror.uts                  # Android / iOS 共用错误对象
    ├── app-android/                  # 现有 Android 实现
    │   ├── index.uts
    │   ├── CodeCaptureActivity.kt
    │   ├── MultiCodePickView.kt
    │   └── ScanFrameDecorView.kt
    └── app-ios/                      # 新增 iOS 实现
        ├── index.uts                 # UTS 桥接与回调编排
        ├── CodeCaptureViewController.swift
        ├── CodeScanner.swift
        ├── ScanOverlayView.swift
        ├── MultiCodePickView.swift
        ├── ScanStyleParser.swift
        └── Info.plist                # 或按 UTS iOS 配置规范声明权限

app-ios 的最终配置文件和 Swift 文件参与编译方式,必须以当前 HBuilderX 版本的 UTS iOS 官方规范为准;开始编码前需要用官方最小示例验证目录结构。

2.2 分层职责

业务页面
  ↓ openCodeScan(options)
UTS 平台入口(app-android/index.uts 或 app-ios/index.uts)
  ↓ 参数转换 / 生命周期 / 回调派发
原生扫码控制器
  ↓ 相机、识别、相册、交互
原生绘制层
  ↓ 扫描框、扫描线、多码点选、呼吸动画
  • interface.uts:作为跨端 API 契约,不应写入 Android 或 iOS 私有字段。
  • app-ios/index.uts:负责将 CodeScanOptions 转为原生配置,处理单次与连续扫码回调。
  • CodeCaptureViewController:负责页面展示、权限、相机生命周期、工具栏和结果模式。
  • CodeScanner:负责相机帧分析、Vision 识别、格式过滤、区域过滤和缩放策略。
  • ScanOverlayView:负责 scanStyle 与 scanRegion 的视觉绘制。
  • MultiCodePickView:负责多码定格、点选和绿色呼吸波纹。

3. iOS 技术选型

能力 推荐技术 选择理由
相机预览与帧采集 AVFoundation 系统原生、稳定、无需新增依赖
条码识别 Vision 的 VNDetectBarcodesRequest 覆盖常见二维码与条形码,识别结果可获取码制和边界框
相册选图 PHPickerViewController iOS 14+ 可按用户选择读取图片,通常无需完整相册权限
低版本相册兼容 UIImagePickerController 仅在确认最低系统版本低于 iOS 14 时补充
扫描线动画 CAShapeLayer + CABasicAnimation 使用 Core Animation,避免定时器逐帧重绘
多码呼吸动画 CAShapeLayer + CABasicAnimation 与 Android 绿点呼吸波纹实现保持视觉一致
手势缩放 UIPinchGestureRecognizer 对应 Android 双指捏合
震动反馈 UIImpactFeedbackGenerator 适配 iOS 系统触感反馈

3.1 不引入第三方扫码库

首版不建议接入 ZXing、ML Kit iOS 等第三方库,原因:

  • 系统 Vision 已能覆盖主要码制;
  • 避免 CocoaPods/SPM 与 UTS iOS 构建的额外集成风险;
  • 减少安装包和维护成本;
  • 便于优先验证 UTS + Swift 桥接与相机链路。

若后续测试确认某些业务关键码制在 Vision 上识别率不足,再单独评估第三方引擎,不在首版预置依赖。


4. 公共 API 与行为约束

4.1 保持现有 API

现有 CodeScanOptions 不新增必填字段,iOS 端识别并实现以下参数:

参数 iOS 首版目标 说明
formats 支持 映射到 Vision 支持的 symbology;不支持值忽略
vibrate 支持 识别成功后触发轻触感反馈
fromAlbum 支持 打开扫码页后直接进入相册选择
scanRegion 支持 控制实时识别区域与扫描框;相册识图不受限制
scanStyle 支持 控制遮罩、边框、扫描线及动画
resultMode 支持 immediate、confirm、pause
continuous 支持 多次 success,关闭时 complete
showPauseButton 支持 仅连续扫码时展示暂停/继续控制
torch: 'off' 支持 默认关闭
torch: 'on' 支持 设备支持时尝试开启
smartZoom 第二阶段 首版可读取但不自动变焦,后续补齐
torch: 'auto' 第二阶段 需要基于视频帧亮度策略验证

4.2 成功数据

iOS 识别结果必须统一转换为:

{
  content: string,
  format: string,
  fromAlbum: boolean
}

格式名称与 Android 对齐,至少包括:

QR_CODE
EAN_13
EAN_8
UPC_A
UPC_E
CODE_128
CODE_39
CODE_93
ITF
CODABAR
PDF417
AZTEC
DATA_MATRIX

当 Vision 不支持某个 Android 已支持的格式时:

  1. formats 中的该值不参与 Vision 请求;
  2. 不因单个非法或不支持值使整个调用失败;
  3. 若过滤后没有任何 iOS 支持的格式,可按全格式或返回 9021004,最终策略需在编码前固定,并同步文档;
  4. 推荐与 Android 保持一致:过滤为空时退回全格式识别。

4.3 回调一致性

场景 success fail complete
单次扫码成功 调用一次 不调用 紧随成功调用一次,参数为成功结果
单次取消/关闭 不调用 9021003 紧随失败调用一次
相机权限拒绝 不调用 9021002 紧随失败调用一次
无有效扫码结果的异常结束 不调用 9021004 紧随失败调用一次
连续扫码单次命中 每次命中调用 不调用 页面未关闭前不调用
连续扫码关闭且已有命中 不再调用 不调用 complete({ closed: true, hitCount })
连续扫码关闭且无命中 不调用 9021003 紧随失败调用一次

所有业务回调必须在主线程派发,控制器关闭、权限回调和异步识别完成之间要有会话状态保护,确保不会重复回调。

4.4 错误码复用

继续使用 unierror.uts 中的错误码:

错误码 语义 iOS 对应场景
9021001 当前无法获取页面 Activity 无法获取当前 UIViewController 或不能展示扫码页
9021002 相机权限被拒绝 .denied / .restricted 或用户拒绝授权
9021003 用户取消扫码 点击关闭、系统返回或取消图片选择
9021004 未获取到有效的扫码结果 扫码处理异常结束、相册图片无有效条码后由调用方选择结束

5. 核心功能设计

5.1 相机权限与页面生命周期

流程:

openCodeScan
  ↓
获取当前 UIViewController
  ↓
检查 AVCaptureDevice 相机权限
  ├─ 已授权 → 初始化扫码控制器与会话
  ├─ 未决定 → 请求授权 → 成功后初始化
  └─ 拒绝/受限 → fail(9021002) → complete

控制器生命周期要求:

  • 页面展示时创建并启动 AVCaptureSession;
  • 页面进入后台时暂停会话;
  • 页面恢复前台时,未完成且未暂停时恢复会话;
  • 页面关闭、成功返回或发生不可恢复错误时停止会话;
  • 释放 AVCaptureVideoDataOutput 委托、图片引用、动画图层和 UTS 回调引用;
  • 防止异步 Vision 回调在页面关闭后再提交结果。

5.2 实时扫码链路

AVCaptureVideoDataOutput
  ↓ CMSampleBuffer
Vision VNDetectBarcodesRequest
  ↓ VNBarcodeObservation 列表
formats 过滤
  ↓
scanRegion 区域过滤
  ↓
单码 / 多码 / 连续扫码 / 结果模式处理

性能策略:

  • 使用串行 DispatchQueue 处理 Vision 请求,避免同一时间处理多帧;
  • 在上一帧识别尚未结束时丢弃新帧;
  • 多码定格、确认弹窗、暂停状态、页面关闭后停止提交识别请求;
  • 连续扫码需按 content + format 做短时间去重,建议冷却窗口 800ms ~ 1200ms;
  • 不在 Vision 回调线程直接更新 UIKit,统一回主线程更新界面。

5.3 formats 映射

新增 iOS 私有映射表:

QR_CODE     → VNBarcodeSymbologyQR
EAN_13      → VNBarcodeSymbologyEAN13
EAN_8       → VNBarcodeSymbologyEAN8
UPC_A       → VNBarcodeSymbologyUPCE(需以实际 Vision 结果确认映射)
UPC_E       → VNBarcodeSymbologyUPCE
CODE_128    → VNBarcodeSymbologyCode128
CODE_39     → VNBarcodeSymbologyCode39
CODE_93     → VNBarcodeSymbologyCode93
ITF         → VNBarcodeSymbologyI2of5
CODABAR     → VNBarcodeSymbologyCodabar
PDF417      → VNBarcodeSymbologyPDF417
AZTEC       → VNBarcodeSymbologyAztec
DATA_MATRIX → VNBarcodeSymbologyDataMatrix

VNBarcodeSymbology 的实际可用范围与命名随 iOS SDK 变化。开发时必须以目标 Xcode / iOS SDK 编译结果为准,不能假定每个 Android 格式都一一对应。

5.4 scanRegion 坐标转换与过滤

scanRegion 是业务 API 中最容易出现跨平台差异的部分,iOS 必须确保“画面上显示的扫描框”与“实际允许识别的区域”一致。

处理步骤:

  1. 根据 width、height、centerX、centerY 计算预览层的扫描框 CGRect;
  2. 使用 AVCaptureVideoPreviewLayer 将 Vision 的归一化 boundingBox 转换为 UIKit 坐标;
  3. 判断条码边界框中心点是否在扫描框中;
  4. 仅保留区域内条码;
  5. fullScreen: true 时不绘制扫描框且不进行区域过滤;
  6. 相册识图跳过 scanRegion 过滤,保持 Android 行为。

验证重点:

  • Vision 坐标原点与 UIKit 坐标原点不同;
  • .resizeAspectFill 会产生裁切偏移;
  • 前置镜像、横竖屏和刘海安全区可能影响坐标;
  • 多码点选标记必须与真实条码中心重合。

5.5 scanStyle 绘制

ScanOverlayView 使用 CAShapeLayer 与 CAGradientLayer 绘制,配置语义与 Android 一致:

参数 iOS 实现
showMask 显示/隐藏扫描框外遮罩层
showBeam 显示/隐藏扫描线图层
borderColor CGColor 边框颜色
maskColor 解析 #RRGGBB、#AARRGGBB、rgba() 后填充遮罩
beamColor 扫描线颜色
beamDuration 扫描线 CABasicAnimation.duration,限制 100 ~ 60000ms
cornerStyle: 'corner' 绘制四角边框
cornerStyle: 'full' 绘制完整矩形边框

默认值必须沿用当前接口默认行为:

{
  showMask: true,
  showBeam: true,
  borderColor: '#19be6b',
  maskColor: 'rgba(0, 0, 0, 0.45)',
  beamColor: '#12e880',
  beamDuration: 1800,
  cornerStyle: 'corner'
}

颜色解析建议单独实现 ScanStyleParser:

  • 支持 #RRGGBB;
  • 支持 #AARRGGBB;
  • 支持 rgba(r,g,b,a);
  • 解析失败时回退默认色;
  • 所有回退规则与 Android readScanStyle() 保持一致。

5.6 单码、多码和点选

单码

单个有效条码按 resultMode 处理:

  • immediate:停止识别并立即返回;
  • confirm:暂停识别,弹出确认框;
  • pause:暂停识别,显示继续扫描和确认返回操作。

多码

同一帧出现两个及以上有效、有内容且有边界框的条码时:

  1. 停止实时识别;
  2. 抓取当前预览帧;
  3. 显示定格画面和半透明遮罩;
  4. 把各码的边界框映射到屏幕;
  5. 在中心位置绘制点选标记;
  6. 显示“已识别到多个码,请选择一个”提示;
  7. 用户点击最近标记后提交对应条码结果。

MultiCodePickView 的标记视觉与 Android 对齐:

绿色中心圆点
  + 白色圆形底
  + 绿色半透明外圈
  + 周期性呼吸扩散动画

建议使用 CAKeyframeAnimation 或 CABasicAnimation 同步变化外圈的 transform.scale 与 opacity,周期暂定 1500ms。

点击策略:

  • 以点位中心为基准选择最近候选;
  • 设置最小可点击半径,建议约 28pt;
  • 无命中点时继续等待选择,不直接取消;
  • 用户主动关闭时按取消流程处理。

5.7 相册识图

优先采用 PHPickerViewController:

fromAlbum: true 或点击相册按钮
  ↓
系统图片选择器
  ↓
获取 UIImage / CGImage
  ↓
Vision VNDetectBarcodesRequest
  ↓
单码直接返回;多码进入点选

规则:

  • 相册识图结果的 fromAlbum 固定为 true;
  • 相册图片不受 scanRegion 限制;
  • 用户取消图片选择:单次扫码按 9021003 处理;
  • 图片中未识别到条码时,提示“未识别到有效条码”,并返回扫码页继续操作;
  • 多码相册图片使用图片本身作为定格背景并进入点选。

5.8 连续扫码与暂停

continuous: true 时:

  • 命中一次条码调用一次 success;
  • 扫码页不关闭;
  • 同一内容需通过短时冷却避免高频重复提交;
  • showPauseButton: true 时展示暂停/继续按钮;
  • 用户关闭时,若已有命中,则仅调用:
complete({ closed: true, hitCount })
  • 用户关闭时,若没有命中,则按 fail(9021003) 后 complete;
  • 多码点选确认后,在连续模式下应投递一次成功结果、清除定格层、恢复相机识别,而不是关闭控制器。

5.9 手电筒、缩放与震动

手电筒

  • 使用 AVCaptureDevice.hasTorch 判断设备能力;
  • 使用 lockForConfiguration() + torchMode 变更状态;
  • off:默认关闭;
  • on:启动后尝试开启;
  • 无手电筒设备隐藏或禁用页面按钮;
  • 页面结束时关闭手电筒。

手势缩放

  • 使用 UIPinchGestureRecognizer;
  • 映射至 videoZoomFactor;
  • 限制在 1.0 ... activeFormat.videoMaxZoomFactor 的安全范围;
  • 变焦期间禁止智能变焦抢占。

智能变焦

作为第二阶段能力:

  • 根据条码边界框占画面比例计算建议倍率;
  • 设定最大尝试次数、最大倍率和平滑过渡;
  • 检测到多个码时先恢复 1.0x,避免多码点选区域被放大裁切;
  • 与手势缩放、连续扫码、定格状态互斥。

震动

  • vibrate: true 时使用 UIImpactFeedbackGenerator(style: .light);
  • 连续扫码每次实际成功投递时触发;
  • 系统可能因“减少动态效果”、静音模式或设备策略弱化触感反馈,业务层不应依赖其作为唯一成功提示。

6. UTS 桥接设计

6.1 app-ios/index.uts 职责

app-ios/index.uts 负责:

  1. 获取可展示扫码页的当前 UIViewController;
  2. 校验当前是否已有扫码会话,避免重复打开;
  3. 归一化 CodeScanOptions 默认值;
  4. 创建并展示 CodeCaptureViewController;
  5. 接收原生事件并转换为 CodeScanSuccess / CodeScanFailImpl;
  6. 保证回调顺序和只执行一次的终止语义;
  7. 连续扫码时维护 hitCount;
  8. 控制器退出后解除事件与对象引用。

6.2 建议的原生事件模型

控制器向桥接层输出有限事件,不直接感知 UTS 回调:

onResult(content, format, fromAlbum)
onCancel()
onPermissionDenied()
onFatalError()
onClosed(hitCount, hadHits)

桥接层统一决定:

  • 单次成功:success → complete;
  • 单次失败:fail → complete;
  • 连续扫码:每次 onResult → success,关闭时再 complete;
  • 已结束会话的后续事件全部丢弃。

6.3 会话状态

建议 iOS 桥接层维护:

idle → presenting → scanning → paused / picking → finishing → finished

关键约束:

  • finished 后不允许再次派发回调;
  • 权限请求、Vision 回调、相册回调都需检查当前状态;
  • 控制器 dismissal 完成后再释放强引用;
  • 业务层再次调用时必须创建新会话,不复用旧回调。

7. 权限与配置

7.1 必需权限

iOS 必须声明:

<key>NSCameraUsageDescription</key>
<string>需要使用相机扫描二维码和条形码</string>

若采用 PHPickerViewController 且最低系统版本为 iOS 14,一般不需要完整相册访问权限。

若最终需要 UIImagePickerController 或直接读取照片库,则补充:

<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以识别图片中的二维码和条形码</string>

7.2 最低系统版本建议

建议首版目标:

iOS 14+

理由:

  • 可以使用 PHPickerViewController;
  • Vision 条码能力更成熟;
  • 降低图片权限和兼容逻辑复杂度。

若产品必须支持 iOS 13,需要增加相册选择兼容分支,并重新评估 Vision 可识别格式集合。

7.3 打包与调试

iOS 原生 UTS 代码不能通过 Web 预览验证,必须使用:

  • 包含插件的 iOS 自定义调试基座;或
  • iOS 云打包 / 本地原生打包产物;
  • 真机设备与 Xcode 控制台。

模拟器不应作为相机扫码主验收环境;可用于页面布局、权限分支和相册图片识别的部分验证。


8. 分阶段实施计划

阶段 0:UTS iOS 可编译性验证

目标:确认当前 HBuilderX 与项目配置可编译 app-ios 原生实现。

任务:

  • 创建最小 app-ios/index.uts;
  • 验证获取当前 iOS 控制器与展示原生页面的官方方式;
  • 验证 Swift 文件参与 UTS iOS 编译的目录和配置;
  • 在 iPhone 真机执行一个最小“打开原生页并返回”示例;
  • 固化项目实际约定后再开始完整扫码实现。

验收:iOS 自定义基座可编译并成功打开、关闭原生测试页面。

阶段 1:最小可用扫码

范围:

  • 相机权限;
  • 后置相机预览;
  • Vision 单码实时识别;
  • success、fail、complete;
  • 用户关闭;
  • 常见二维码与条形码格式。

验收:iPhone 真机可扫描 QR Code 和 Code 128,并按既定顺序回调。

阶段 2:跨端核心功能对齐

范围:

  • formats;
  • scanRegion;
  • scanStyle;
  • 相册识图;
  • 多码定格点选;
  • 绿色呼吸波纹;
  • resultMode;
  • vibrate。

验收:Android 与 iOS 对同一配置的显示、区域过滤和数据结构一致。

阶段 3:会话与相机增强

范围:

  • continuous;
  • showPauseButton;
  • torch: 'off' | 'on';
  • 手势缩放;
  • 连续扫码去重与关闭结算。

验收:连续扫码有命中和无命中关闭时的回调行为与 Android 一致。

阶段 4:高级策略

范围:

  • smartZoom;
  • torch: 'auto';
  • 复杂机型上的性能优化;
  • 必要时评估第三方识别引擎。

验收:在目标机型上无明显误触发、频繁跳变、发热或回调重复问题。


9. 验收矩阵

9.1 功能验收

场景 预期
单个二维码 返回 QR_CODE、fromAlbum: false
单个 Code 128 返回 CODE_128
formats 过滤 仅接受指定码制
全屏识别 不显示扫描框,整画面可识别
自定义区域 框外条码不返回,框内条码正常返回
相册单码 返回 fromAlbum: true
相册多码 显示定格图片与多个可点击标记
实时多码 显示定格画面、提示语和绿色呼吸点
confirm 模式 确认后返回,取消后继续识别
pause 模式 可继续扫描或确认结果
连续扫码 多次 success,关闭后返回正确 hitCount
连续扫码无命中关闭 fail 9021003 后 complete
相机权限拒绝 fail 9021002 后 complete
无手电筒设备 不崩溃,按钮隐藏或禁用

9.2 机型与系统验收

至少覆盖:

  • iPhone 小屏机型;
  • 刘海屏机型;
  • 灵动岛机型;
  • 无手电筒或手电筒不可用场景;
  • iOS 14、16、17 及项目实际要求的最新系统;
  • 深色模式;
  • 权限首次授权、拒绝、设置页重新授权;
  • 前后台切换、来电或控制中心打断后恢复;
  • 快速打开、关闭、再次打开扫码页。

9.3 性能与稳定性验收

  • 连续识别 5 分钟不出现明显内存持续增长;
  • 多次进入、退出扫码页后相机可再次正常打开;
  • 多码定格帧不会造成明显卡顿或黑屏;
  • 页面关闭后不再收到 success;
  • 不发生重复 complete 或 success/fail 同时触发;
  • 扫描框与实际识别区域、点选标记位置对齐。

10. 风险与应对

风险 影响 应对措施
UTS iOS 原生目录/Swift 桥接规则与预期不同 无法编译或调用 阶段 0 使用官方最小示例先验证,不直接大规模开发
Vision 支持的码制与 Android 不完全一致 formats 行为差异 建立格式能力矩阵,过滤不支持项并在 README 明示
Vision 到预览层坐标转换错误 scanRegion、点选位置偏移 单独编写坐标转换测试清单,覆盖 Aspect Fill、旋转和安全区
定格帧转换开销高 多码时卡顿、内存上涨 限制图像分辨率,及时释放 CGImage / UIImage,仅保留一帧
异步回调竞争 重复回调、页面关闭后回调 使用会话状态机和主线程串行化终止事件
Torch / zoom 在机型上差异大 功能不稳定 将 auto 与 smartZoom 放到后续阶段,先实现基础能力
iOS 权限文案或 Info.plist 缺失 审核或运行时崩溃 将权限配置纳入构建前检查和真机回归

11. 代码与文档更新清单

11.1 开发完成后需要修改

文件 修改内容
utssdk/app-ios/* 新增 iOS UTS 桥接和 Swift 原生实现
package.json displayName、描述、关键字、platforms.client.uni-app.app.ios 改为支持
readme.md 支持平台改为 Android / iOS;补充 iOS 权限、最低版本和格式差异说明
changelog.md 记录 iOS 首次支持及功能范围
pages/scan/prototype.vue 将 Android 专属提示改为 Android / iOS App 提示

11.2 开发完成前不得修改

以下内容必须等 iOS 自定义基座成功编译且完成真机验收后再调整:

  • README 的“支持 iOS”声明;
  • package.json 中的 ios: '√';
  • 业务页面中“Android 专属”的运行提示;
  • changelog 中的正式 iOS 发布记录。

12. 推荐实施顺序

  1. 确认项目的 HBuilderX 版本、Xcode 版本和最低 iOS 版本;
  2. 用官方 UTS iOS 最小原生页面验证 app-ios 目录与 Swift 编译方式;
  3. 实现相机权限 + 单码 QR 实时识别闭环;
  4. 固化 success / fail / complete 的 iOS 回调行为;
  5. 加入 formats、scanRegion 和 scanStyle;
  6. 加入相册识图和多码定格点选;
  7. 加入连续扫码、暂停、手电筒和手势缩放;
  8. 最后实现 smartZoom、auto torch 等设备敏感能力;
  9. 真机回归通过后更新插件元信息、README、changelog 和演示页文案。

13. 结论

推荐采用 AVFoundation + Vision + PHPickerViewController 的原生 iOS 实现方案,并在 utssdk/app-ios/ 中增加独立平台入口。现有 interface.uts、unierror.uts 和 openCodeScan 调用方式继续作为跨端契约,Android 代码无需重构。

实施上应先完成 iOS UTS 编译与原生页面呈现验证,再逐步建立单码扫码、多码点选、相册识图和连续扫码能力。这样能将最大的构建与坐标转换风险前置,同时避免在未验证前修改对外平台支持声明。