【听见课堂 HarmonyOS NEXT 实战系列 33】PhotoViewPicker 选图为何不需要宽泛媒体权限
【听见课堂 HarmonyOS NEXT 实战系列 33】PhotoViewPicker 选图为何不需要宽泛媒体权限
“从相册导入”不等于“读取用户整个相册”。HarmonyOS 的 PhotoViewPicker 由系统展示选择界面,用户明确选中一张图片后,应用只接收对应 URI。对于板书 OCR,这种按次、按对象授权比申请整个媒体库更符合最小权限原则。
听见课堂在 ScanCaptureService.selectPhoto() 中把 MIME 类型限制为图片,最大选择数固定为 1,module.json5 没有声明宽泛媒体读写权限。本文拆解这条链路,也讨论多页扫描尚未真正扩展到批量 URI 的边界。

一、系统 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 页面。

九、选中后立即记录来源
recognizeSelectedPhoto() 保存 scanImageUri 和 scanSourceLabel='系统图库',随后进入 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.MediaLibraryKit 的 photoAccessHelper 路径。
后续升级 SDK 时仍要检查 MIME 枚举、URI 使用范围和系统能力,不能只凭旧示例复制代码。
十六、总结
PhotoViewPicker 的价值不只是少写一个相册页,而是把选择权和数据范围交还给用户。听见课堂当前单图、图片 MIME、无宽泛媒体权限、取消不写入和临时 URI 边界是清晰的;真正未完成的是批量多页选择与真图成功证据。
下一篇进入 OCR 内部:一张 URI 怎样经过 ImageSource、PixelMap 和 Core Vision,并在所有分支正确释放资源。
参考:华为应用隐私保护、Media Library Kit 术语、项目 ScanCaptureService.selectPhoto()。
更多推荐



所有评论(0)