前言
前两天写一个一篇从相册选择照片,进行识别的内容,今天有看到一个问题地址如下不在赘述了,本篇就针对这个问题详细的讲解一下 https://developer.huawei.com/consumer/cn/forum/topic/0208222707637089600?fid=0109140870620153026
“从相册选一张图片,要不要申请ohos.permission.READ_IMAGEVIDEO权限?”
说实话我一开始也拿不准。毕竟在 Android 里,读相册就得要权限,惯性思维嘛。后来翻文档跑了几个 demo 才搞明白:用 PhotoViewPicker 选图,完全不需要任何权限。但如果你直接用photoAccessHelper.getAssets()读媒体库,那就得申请,而且这个权限还是受限的,上架审核卡得很严。
这篇文章把两种方式的区别和完整实现都写清楚,跟着做就能跑起来。
先说结论
| 方式 | 是否需要权限 | 适用场景 |
|---|---|---|
PhotoViewPicker.select() | 不需要 | 让用户主动从相册选图片/视频 |
photoAccessHelper.getAssets() | 需要READ_IMAGEVIDEO(受限权限) | 应用自己遍历读取媒体库 |
划重点:只要场景是"用户主动选图",就用 PhotoViewPicker,零权限,零审核风险。
效果如图
PhotoViewPicker 是什么
PhotoViewPicker 是 HarmonyOS 提供的系统图库选择器。调用它的select()方法后,系统会拉起图库界面,用户自己挑图片,选完之后把 URI 返回给你。
整个过程用户是主动参与的选择操作,不是应用在后台偷偷读取,所以系统认为不需要权限。
说白了就是:用户亲手给你的,不算偷。
完整实现:从相册选一张图并回显
导入依赖
只有两个:picker用来选图,BusinessError用来捕获异常。
import{picker}from'@kit.CoreFileKit'import{BusinessError}from'@kit.BasicServicesKit'注意picker来自@kit.CoreFileKit,不是@kit.MediaLibraryKit,这个搞错了编译都过不了。
选图方法
核心逻辑就这几行:
privateasyncpickImage():Promise<void>{constoptions:picker.PhotoSelectOptions=newpicker.PhotoSelectOptions()options.MIMEType=picker.PhotoViewMIMETypes.IMAGE_TYPEoptions.maxSelectNumber=1constphotoPicker:picker.PhotoViewPicker=newpicker.PhotoViewPicker()try{constresult:picker.PhotoSelectResult=awaitphotoPicker.select(options)if(result.photoUris.length>0){this.selectedUri=result.photoUris[0]}}catch(e){consterr:BusinessError=easBusinessErrorconsole.error(`pickImage failed:${err.code}`)}}逐行解释:
PhotoSelectOptions是选图配置。MIMEType设为IMAGE_TYPE表示只选图片,不选视频。maxSelectNumber设为 1 表示只选一张。PhotoViewPicker是选择器实例,调用select()拉起系统图库。- 返回的
PhotoSelectResult里有photoUris数组,就是用户选中的图片 URI。 - 拿到 URI 后赋值给
@State变量,UI 自动刷新显示图片。
页面布局
选完图在页面上显示出来,同时放一个按钮触发选图:
@Entry@Componentstruct Qa8{@StateselectedUri:string=''// pickImage 方法同上,省略build(){Column(){if(this.selectedUri.length>0){Image(this.selectedUri).width(300).height(300).objectFit(ImageFit.Contain).borderRadius(8).margin({bottom:24})}Button('从相册选择图片').type(ButtonType.Capsule).backgroundColor('#3274F6').fontColor(Color.White).width('60%').onClick(()=>{this.pickImage()})}.width('100%').height('100%').justifyContent(FlexAlign.Center).backgroundColor('#FFFFFF')}}几个细节:
Image组件可以直接用 PhotoViewPicker 返回的 URI 加载图片,不需要额外转换。objectFit(ImageFit.Contain)保证图片等比缩放不裁剪。- 用
if (this.selectedUri.length > 0)判断是否显示图片,选图前不显示。
完整代码
把上面的部分合在一起,完整代码如下:
import{picker}from'@kit.CoreFileKit'import{BusinessError}from'@kit.BasicServicesKit'@Entry@Componentstruct Qa8{@StateselectedUri:string=''privateasyncpickImage():Promise<void>{constoptions:picker.PhotoSelectOptions=newpicker.PhotoSelectOptions()options.MIMEType=picker.PhotoViewMIMETypes.IMAGE_TYPEoptions.maxSelectNumber=1constphotoPicker:picker.PhotoViewPicker=newpicker.PhotoViewPicker()try{constresult:picker.PhotoSelectResult=awaitphotoPicker.select(options)if(result.photoUris.length>0){this.selectedUri=result.photoUris[0]}}catch(e){consterr:BusinessError=easBusinessErrorconsole.error(`pickImage failed:${err.code}`)}}build(){Column(){if(this.selectedUri.length>0){Image(this.selectedUri).width(300).height(300).objectFit(ImageFit.Contain).borderRadius(8).margin({bottom:24})}Button('从相册选择图片').type(ButtonType.Capsule).backgroundColor('#3274F6').fontColor(Color.White).width('60%').onClick(()=>{this.pickImage()})}.width('100%').height('100%').justifyContent(FlexAlign.Center).backgroundColor('#FFFFFF')}}不需要在module.json5里声明任何权限,直接跑就行。
什么时候才需要 READ_IMAGEVIDEO
只有一个场景:你的应用需要在不经过用户选择的情况下,直接读取媒体库中的图片或视频。
比如:
- 换机克隆:把旧手机的所有照片复制到新手机
- 云端备份:自动把本地照片上传到云端
- 跨设备同步:在设备间同步媒体文件
这些场景下,应用无法通过 PhotoViewPicker 让用户一张张选,必须直接访问媒体库,这才需要READ_IMAGEVIDEO。
其他所有"用户主动选图"的场景,PhotoViewPicker 都是最佳方案——零权限、实现简单、用户体验好。
写在最后
这个知识点不难,但很多人(包括之前的我)容易在权限问题上纠结半天。核心就一句话:用户选的不要权限,你偷读的才要权限。
如果你在做头像上传、朋友圈发图这类功能,直接用 PhotoViewPicker,别多想。