【听见课堂 HarmonyOS NEXT 实战系列 33】PhotoViewPicker 选图为何不需要宽泛媒体权限

“从相册导入”不等于“读取用户整个相册”。HarmonyOS 的 PhotoViewPicker 由系统展示选择界面,用户明确选中一张图片后,应用只接收对应 URI。对于板书 OCR,这种按次、按对象授权比申请整个媒体库更符合最小权限原则。

听见课堂在 ScanCaptureService.selectPhoto() 中把 MIME 类型限制为图片,最大选择数固定为 1,module.json5 没有声明宽泛媒体读写权限。本文拆解这条链路,也讨论多页扫描尚未真正扩展到批量 URI 的边界。

系统 PhotoViewPicker 只返回用户主动选择的单张图片

一、系统 Picker 是授权界面也是选择界面

PhotoViewPicker 不只是一个文件列表。它由系统承载,用户在系统 UI 中决定哪张图片可以被当前操作使用。应用无需先遍历全部照片再自己做选择页。

华为 Media Library Kit 术语和隐私保护文档都强调:Picker 让用户自主选择资源,应用无需申请敏感媒体权限。

二、项目只配置 IMAGE_TYPE

const options: photoAccessHelper.PhotoSelectOptions =
  new photoAccessHelper.PhotoSelectOptions();
options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;

OCR 输入只需要静态图片,因此不接受视频或混合类型。选择范围与业务需求一致,也减少后续解码分支。

三、单页流程把 maxSelectNumber 设为 1

options.maxSelectNumber = 1;

P05 当前每次只把一个 URI 交给 recognizeSelectedPhoto(),P06 也只保存一个临时 scanImageUri。如果 Picker 允许多选但页面只读取第一张,其余选择会让用户误以为批量扫描已生效。

四、返回数组仍要做空判断

const result: photoAccessHelper.PhotoSelectResult = await picker.select(options);
return result.photoUris.length > 0 ? result.photoUris[0] : '';

即使限制单选,结果仍是 URI 数组。用户取消时数组为空,Service 返回空字符串,页面把它映射成“已取消选择,未读取任何图片”。

五、取消不是异常

if (uri.length === 0) {
  this.scanStatus = '已取消选择,未读取任何图片';
  return;
}

取消不显示错误卡、不清除已有数据库记录,也不自动打开另一个 Picker。尊重退出比“强行完成任务”更重要。

六、为什么不需要 READ_IMAGEVIDEO

当前 module.json5 没有 READ_IMAGEVIDEO。应用不查询完整媒体库,只处理用户在系统 Picker 中明确选择的图片。

华为隐私保护文档把 Picker 作为最小化数据泄露风险的方案;Media Library Kit 也区分公开的 Picker 能力与需要受限权限的全量管理能力。

七、URI 代表临时输入,不代表拥有整张相册

应用拿到一个 URI 后可以在当前链路中解码、预览和 OCR,但这不意味着它可以访问相邻照片、相册元数据或其他未选择资源。

业务层也不应把一个选择结果推导成“用户授权了整个图库”。权限提示、日志和数据模型都要保持这一边界。

八、页面不要直接访问媒体库

页面只调用:

const uri: string = await this.scanService.selectPhoto();
await this.recognizeSelectedPhoto(uri, '系统图库');

MIME 配置、结果结构和空数组处理留在 Service。以后若 Picker API 或 URI 访问方式变化,只需调整能力层,不必改两套手机/2in1 页面。

宽泛媒体权限与单次 Picker 授权的数据范围对比

九、选中后立即记录来源

recognizeSelectedPhoto() 保存 scanImageUriscanSourceLabel='系统图库',随后进入 OCR。P06 能区分系统相机、系统图库和本地示例。

来源不是装饰文案,它决定保存后的证据说明,也避免示例数据被误认为真实图片识别。

十、原图只做临时预览

页面注释和 UI 明确“修改后保存到本机数据库,不上传原图”。saveOcrReview() 成功后清空 scanImageUri,Repository 保存文本和来源,不保存选择 URI。

这减少了 URI 失效、原图被删除、数据库迁移和隐私泄露风险。

十一、多页开关不等于批量 Picker 已完成

P05 有 isMultiPageScan 开关,但当前 selectPhoto() 仍固定 maxSelectNumber=1,页面也只有单个 scanImageUri。因此不能声称系统图库已支持一次选择多页并逐页 OCR。

当前多页更接近交互意向,真正批量链路还需要 URI 队列、逐页状态、失败隔离、资源释放和保存顺序。

十二、批量扩展应先设计数量上限

多页扫描不是把 maxSelectNumber 改成 50 就结束。需要回答:一次最多几页、图片是否压缩、并发 OCR 数量、失败是否阻断全批次、用户如何删除或重排,以及页面退出时怎样释放资源。

对课堂场景,较小上限和串行识别通常更容易控制内存与反馈。

十三、真实系统 UI 已验证到什么程度

项目在模拟器上成功拉起系统图库,UI 树显示“安全访问图库”和“仅可访问所选图片”,并验证取消后返回 P05、没有错误卡和数据修改。

模拟器图库没有测试图片,因此真实图片选择、解码和 OCR 成功仍为 not run。系统 Picker 能打开不等于内容链路已全部通过。

十四、隐私验收清单

检查 manifest 没有宽泛媒体读写权限;选择前不扫描媒体库;取消后不留 URI;日志不输出完整 URI;保存后数据库只含复核文本和来源;页面退出释放 PixelMap/ImageSource;隐私文案与行为一致。

若未来要上传原图,必须新增明确用途、网络数据流、失败重试和删除策略,不能沿用当前“本机处理”描述。

十五、API 演进要按项目 SDK 复核

旧的 @ohos.file.picker.PhotoViewPicker 已被官方文档标记为废弃并建议迁移到 photoAccessHelper.PhotoViewPicker。听见课堂当前使用的是 @kit.MediaLibraryKitphotoAccessHelper 路径。

后续升级 SDK 时仍要检查 MIME 枚举、URI 使用范围和系统能力,不能只凭旧示例复制代码。

十六、总结

PhotoViewPicker 的价值不只是少写一个相册页,而是把选择权和数据范围交还给用户。听见课堂当前单图、图片 MIME、无宽泛媒体权限、取消不写入和临时 URI 边界是清晰的;真正未完成的是批量多页选择与真图成功证据。

下一篇进入 OCR 内部:一张 URI 怎样经过 ImageSource、PixelMap 和 Core Vision,并在所有分支正确释放资源。

参考:华为应用隐私保护Media Library Kit 术语、项目 ScanCaptureService.selectPhoto()

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐