uni-app 跨平台图片选择指南:uni.chooseImage 参数详解、相册模式与源码实现剖析
【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app
本文基于 uni-app 官方文档 docs/api/choose-image.md 与仓库内uni-media模块的跨端实现,系统讲解uni.chooseImage从相册选图、调用相机拍照、图片压缩与裁剪的完整能力。读完本文,你将掌握该 API 的每一个参数与回调字段、App 端 custom/system 两种相册选择模式的差异与权限模型、完整的错误码体系,并能从源码层面理解各平台(Android / iOS / HarmonyOS / Web / 微信小程序)的底层行为差异。
一、API 概览与兼容性
uni.chooseImage(options)用于从本地相册选择图片或使用相机拍照,是 uni-app 中最常用的媒体能力之一。它以ChooseImageOptions作为唯一入参,成功时通过回调返回图片的本地文件路径列表tempFilePaths。
从仓库中uni-media模块的类型定义(interface.uts)可以看到,其完整签名是:
export type ChooseImage = (options: ChooseImageOptions) => void平台兼容性
| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | 4.0 | 4.41 | 3.9 | 4.11 | 4.61 |
说明:上表版本号指 uni-app x(HBuilderX 的 uni-app x 编译器)版本,兼容性标注以本文档为准。需要特别注意的是,
sizeType在 HarmonyOS 端对应版本为 4.61(uni-app x 4.23 起)。
二、options 参数详解
options为必填项,类型为ChooseImageOptions。下表完整列出其全部属性:
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 | | :- | :- | :- | :- | :-: | :- | | pageOrientation | string | 否 | (见下) | Web: x; 微信小程序: x; Android: 4.33; iOS: 4.33; HarmonyOS: x | 屏幕方向。默认为 pages.json 中的 pageOrientation。 | | albumMode | string | 否 | "custom" | Web: x; 微信小程序: x; Android: 4.33; iOS: x; HarmonyOS: x | 图片选择模式 | | count | number | 否 | 9 | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 最多可以选择的图片张数,app 端不限制,微信小程序最多可支持 20 个。 | | sizeType | Array<string> | 否 | ['original','compressed'] | Web: x; 微信小程序: 4.41; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | original 原图,compressed 压缩图,默认二者都有 | | sourceType | Array<string> | 否 | ['album','camera'] | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | album 从相册选图,camera 使用相机,默认二者都有 | | extension | Array<string> | 否 | (默认不过滤) | Web: 4.0; 其余平台: x | 根据文件拓展名过滤,每一项都不能是空字符串。仅 H5 支持 | | crop | ChooseImageCropOptions | 否 | (无) | Web: x; Android: 3.9; iOS: 4.11; HarmonyOS: x | 图像裁剪参数,设置后 sizeType 失效。 | | success | (callback: ChooseImageSuccess) => void | 否 | (无) | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 成功则返回图片的本地文件路径列表 tempFilePaths | | fail | (callback: ChooseImageFail) => void | 否 | (无) | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 接口调用失败的回调函数 | | complete | (callback: any) => void | 否 | (无) | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 接口调用结束的回调函数(调用成功、失败都会执行) |
2.1 pageOrientation(屏幕方向)
可选合法值如下,默认取 pages.json 中的pageOrientation配置:
| 合法值 | 描述 | | :- | :- | | "auto" | 自动 | | portrait | 竖屏显示 | | landscape | 横屏显示 |
在源码中对应类型ChooseImagePageOrientation(interface.uts),其注释进一步明确:该参数仅 App 端(Android/iOS)支持,Web 与微信小程序等平台不支持。
2.2 albumMode(图片选择模式,仅 Android)
| 合法值 | 描述 | | :- | :- | | "custom" | 自定义媒体选择器 | | system | 系统媒体选择器 |
该参数默认值为"custom",仅 Android 端支持(4.33 起),iOS、Web、微信小程序均不支持。custom 与 system 两种模式的差异较大,是 Android 上架与权限合规的关键选择,详见本文第四节。
2.3 count、sizeType、sourceType、extension
- count:最多可选图片数,默认 9。app 端不限制,微信小程序最多 20 个。
- sizeType:
'original'(原图)与'compressed'(压缩图)的组合,默认['original','compressed']二者都提供。 - sourceType:
'album'(相册选图)与'camera'(相机拍照)的组合,默认['album','camera']两者都提供。 - extension:按文件扩展名过滤图片,每一项不能是空字符串,默认不过滤,仅 H5 支持。
从源码 protocol.uts 可以看出这些默认值在框架层是如何落地的:ChooseImageApiOptions.formatArgs中,当count、sizeType、sourceType未传入时会分别被规范化为9、['original', 'compressed']、['album', 'camera'];extension未传入时默认置为['*']。也就是说,即使调用方不传任何参数,框架也会在参数预处理阶段补齐一套可用的默认配置。
2.4 crop(图像裁剪,设置后 sizeType 失效)
crop 的类型为ChooseImageCropOptions,属性如下:
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 | | :- | :- | :- | :- | :- | :- | | width | number | 是 | (必填) | Android: 3.9; iOS: 4.11 | 裁剪的宽度,单位为 px,用于计算裁剪宽高比。 | | height | number | 是 | (必填) | Android: 3.9; iOS: 4.11 | 裁剪的高度,单位为 px,用于计算裁剪宽高比。 | | quality | number | 否 | 80 | Android: 3.9; iOS: 4.11 | 取值范围为 1-100,数值越小,质量越低(仅对 jpg 格式有效)。默认值为 80。 | | resize | boolean | 否 | true | Android: 3.9; iOS: 4.11 | 是否将 width 和 height 作为裁剪保存图片真实的像素值。默认值为 true。注:设置为 false 时在裁剪编辑界面显示图片的像素值,设置为 true 时不显示。 |
从源码实现看(ChooseMediaUtils.uts),Android 端在打开相册选择器时会将 crop 配置序列化为image_crop传入图片选择器 Activity(openGalleryActivity中的albumIntent.putExtra("image_crop", JSON.stringify(crop))),并在进入裁剪编辑时限制只能选中一张图(max_select_count被置为 1);拍照场景下同样会携带IMAGE_CROP进入图片编辑 Activity 完成裁切。这印证了文档中"设置 crop 后 sizeType 失效"的语义——裁剪输出由 crop 的 width/height/quality 决定,不再走原有的压缩流程。
三、回调返回值详解
3.1 ChooseImageSuccess(成功回调)
| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | errSubject | string | 是 | Android: 3.9; iOS: 4.11 | 调用 API 的名称 | | errMsg | string | 是 | Android: 3.9; iOS: 4.11 | 描述信息 | | tempFilePaths | Array<string> | 是 | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 图片的本地文件路径列表 | | tempFiles | Array<ChooseImageTempFile> | 是 | 微信小程序: 4.41; Android: 3.9; iOS: 4.11 | 图片的本地文件列表 |
其中tempFiles每个元素的属性:
| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | path | string | 是 | Android: 3.9; iOS: 4.11 | 本地文件路径 | | size | number | 是 | Android: 3.9; iOS: 4.11 | 本地文件大小,单位:B | | name | string | 否 | Android: x; iOS: x | 包含扩展名的文件名称,仅 H5 支持 | | type | string | 否 | Android: x; iOS: x | 文件类型,仅 H5 支持 |
源码中ChooseImageTempFile(interface.uts)的字段与文档一一对应,且name、type均标注为"仅 H5 支持",App 端返回 null。
3.2 ChooseImageFail(失败回调)
| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | errCode | number | 是 | 错误码 | | errSubject | string | 是 | 统一错误主题(模块)名称 | | data | any | 否 | 错误信息中包含的数据 | | cause | Error | 否 | 源错误信息,可以包含多个错误,详见 SourceError | | errMsg | string | 是 | 错误描述 |
四、错误码体系(errCode)
uni.chooseImage及整个媒体模块共用一套错误码,定义于 unierror.uts 的MediaUniErrors映射表中:
| 错误码 | 描述 | 英文信息(源码) | | :- | :- | :- | | 1101001 | 用户取消 | user cancel | | 1101002 | urls 至少包含一张图片地址 | fail parameter error: parameter.urls should have at least 1 item | | 1101003 | 文件不存在 | file not find | | 1101004 | 图片加载失败 | Failed to load resource | | 1101005 | 未获取权限 | No Permission | | 1101006 | 图片或视频保存失败 | save error | | 1101007 | 图片裁剪失败 | crop error | | 1101008 | 拍照或录像失败 | camera error | | 1101009 | 图片压缩失败 | image output failed | | 1101010 | 其他错误 | unexpect error: |
错误对象通过MediaErrorImpl构造,错误主题为uni-chooseImage(源码中UniError_ChooseImage = "uni-chooseImage")。例如在 Android 端,用户取消选择时触发1101001,权限被拒绝时触发1101005,拍照文件不存在时触发1101008,图片裁切失败时触发1101007——这些错误码在 ChooseMediaUtils.uts 的相机、相册、裁剪各分支中均有对应实现。
五、完整可运行示例
官方示例位于仓库演示工程 src/pages/API/choose-image/choose-image.uvue,覆盖了 sourceType、sizeType、count、pageOrientation、albumMode、crop 全部参数的交互式配置。核心调用逻辑如下(Uts 语法,<script setup lang="uts">):
const chooseImage = () => { if (imageList.value.length >= count.value) { uni.showToast({ position: "bottom", title: `已经有 ${count.value} 张图片了,请删除部分图片之后重新选择` }) return } uni.chooseImage({ sourceType: sourceTypeArray[sourceTypeIndex.value], // ['camera'] / ['album'] / ['camera','album'] sizeType: sizeTypeArray[sizeTypeIndex.value], // ['compressed'] / ['original'] / ['compressed','original'] crop: isCrop.value ? { "quality": cropPercent.value, "width": cropWidth.value, "height": cropHeight.value, "resize": cropResize.value } as ChooseImageCropOptions : null, count: count.value - imageList.value.length, // #ifdef APP pageOrientation: orientationTypeArray[orientationTypeIndex.value], // portrait / landscape / auto // #endif // #ifdef APP-ANDROID albumMode: albumModeTypeArray[albumModeTypeIndex.value], // custom / system // #endif success: (res) => { imageList.value = imageList.value.concat(res.tempFilePaths); }, fail: (err) => { uni.showToast({ title: "choose image error.code:" + err.errCode + ";message:" + err.errMsg, position: "bottom" }) } }) }示例页面配合uni.previewImage实现选图后的预览,配合uni.showActionSheet切换图片来源/质量/屏幕方向等选项。仓库中还有对应的自动化测试用例 choose-image.test.js,用于验证页面正常渲染与截图快照。
示例中的几个工程要点值得注意:
- 条件编译的使用:
pageOrientation用#ifdef APP限定 App 端传入,albumMode用#ifdef APP-ANDROID限定 Android 端传入,与文档兼容性矩阵完全一致。 - 数量自校验:选择前先判断已选图片数量是否达到上限,避免超选。
- 裁剪参数组装:启用裁剪时以
as ChooseImageCropOptions显式断言类型,quality 输入范围校验为 0~100。
六、App 端相册选择的 2 种方式:custom 与 system
App 平台的相册选择存在custom(自定义)与system(系统)两种模式,二者差异显著,直接影响权限申请、Google Play 上架合规、UI 定制能力与临时文件生成行为。
6.1 custom 方式(自定义媒体选择器)
- 权限模型:app 需要读取相册文件,因此必须申请相册/本地文件访问权限。而 Google Play 目前仅对合理需要相册权限的应用开放相册权限;若无法向 Google 证明获取相册权限的合理性,则应改用 system 方式。使用 custom 方式上架 Google Play 时需要提交声明以获得试用资格。uni-app x 开发者可升级 HBuilderX 4.41 后改用 system 方式,而 uni-app(非 x)开发者可借助插件方案解决该问题。
- 支持"原图"选项:custom 选择器可让用户选择原图。
- 临时文件:使用非原图(即压缩图片)时,会在应用沙盒目录的 cache 目录产生临时文件(压缩后的图片),位置详见 file-system-spec.md#cache。
- 4.41 起的行为变化:在 4.41 以前,Android 无论如何都会在应用沙盒 cache 目录产生临时文件;从 4.41 起,chooseImage 支持 contentURI,选择照片时如果不压缩图片,会直接返回 contentURI,不再向 cache 目录写临时文件。
从源码可以印证上述第 4 点:ChooseMediaUtils.uts 在组装相册选择结果时,会判断路径前缀path.startsWith("file://") || path.startsWith("content://")并原样保留,这意味着系统照片选择器返回的 content:// URI 会被直接透传给业务层;同一模块的 app-android/index.uts 中也对content://前缀做了分支处理,用于在不落盘的情况下读取与压缩图片。
6.2 system 方式(系统媒体选择器)
无需额外权限:使用系统选择器时,应用不需要申请额外权限,其模式类似于 Web 浏览器中的
input type=file——应用本身不具备本机文件访问能力,由用户通过系统选择器把图片传给应用。Google Play 上架友好:system 方式无需向 Google 特别声明选择权限的必要性即可正常上架。但注意需要在 manifest.json 中移除以下两个权限:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
配置方式参考 Android 原生资源中的"移除 Android 权限"章节(app-nativeresource-android.md)。
UI 无法自定义:如 Android、iOS 上无法添加"原图"选项;鸿蒙上系统 UI 自带原图选项。
主题与国际化跟随系统:界面 UI 的主题和国际化跟随手机 ROM,而不是跟随 App(即使 App 与 ROM 设置不一致)。
无临时文件:因为不涉及压缩,所以也没有临时文件,不会在 cache 目录下生成临时文件。
6.3 两种模式的源码实现差异
在 ChooseMediaUtils.uts 的openGalleryActivity中可以看到两者的分派逻辑:
if (useSystem == "system") { albumIntent.setClassName(getUniActivity()!!, "io.dcloud.uts.pick.SystemPickerActivity"); } else { albumIntent.setClassName(getUniActivity()!!, "io.dcloud.uts.dmcbig.mediapicker.PickerActivity"); }即 system 模式启动的是框架内置的系统选择器 Activity,custom 模式启动的是自定义媒体选择器。权限申请流程也有明显区别(chooseMediaImage):system 模式下,当系统版本高于 Android 12(SDK > 32)或 targetSdkVersion >= 33 时直接打开系统照片选择器,不申请任何权限;而 custom 模式在 targetSdkVersion >= 33 时申请READ_MEDIA_IMAGES,低于 33 时申请READ_EXTERNAL_STORAGE,拍照场景申请CAMERA权限,拒绝后回调1101005。
七、HarmonyOS 端实现要点
从 app-harmony/media/chooseImage.uts 可以看到鸿蒙端的实现逻辑:
- 图片来源分派:
sourceType为['camera']时直接调用_takePhoto;为['album']时通过photoAccessHelper(PhotoViewMIMETypes.IMAGE_TYPE)调用系统相册;两者都有时先弹出uni.showActionSheet让用户选择"拍摄 / 从相册选择"。 - sizeType 的处理:通过
options.sizeType判断是否支持原图:仅['original']时original = true;同时包含 original 与 compressed 时由系统 UI 提供原图选项。这与文档"鸿蒙上系统 UI 自带原图选项"的描述一致。 - 临时文件结构:鸿蒙端返回的
tempFiles只包含path与size两个字段,name、type为 null。
八、Tips 与工程实践建议
- 权限自动申请:本 API 会自动申请摄像头、相册等相关权限。如需手动获取 app 是否拥有摄像头和相册权限,参考 getAppAuthorizeSetting。
- 临时文件清理:app 端拍照和部分情况下的相册选择会在应用沙盒目录的 cache 目录产生临时文件(位置见 file-system-spec.md#cache)。如需主动删除临时文件,使用 getFileSystemManager。
- contentURI 返回条件:从 HBuilderX 4.41 版起,
uni.chooseImage在sourceType为['album']、albumMode为system、sizeType为['original']且未设置crop时,支持返回 Uri 地址(content://),此时不会产生临时文件。 - albumMode 语义:
albumMode的system打开的是系统的图片选择器;custom打开的是 uni-app x 框架提供的图片选择器。 - 系统选择器的 sizeType 限制:系统图片选择器的
sizeType仅支持设置['original']或['compressed']。在 Android 11 及以上系统中,设置system调用的是系统的照片选择器;低于 Android 11 的系统会调用系统的文件选择器。 - 选择结果消费链路:
tempFilePaths返回的是本地路径或 content:// URI,可以直接传给<image>组件渲染、uni.previewImage预览,或配合 uploadFile 上传到服务端;如需进一步处理图片(如压缩、获取信息),可参考仓库中 compress-image 与 get-image-info 相关文档。
九、阅读延伸
- 媒体模块类型定义与平台标注:interface.uts
- 参数协议与默认值规范化:protocol.uts
- 错误码与错误对象:unierror.uts
- Android 端选择器/相机/裁剪实现:ChooseMediaUtils.uts
- HarmonyOS 端实现:chooseImage.uts
- 官方交互示例:choose-image.uvue
- 自动化测试:choose-image.test.js
- 相关 API:图片预览 preview-image、图片压缩 compress-image、文件系统 file-system-spec、错误规范 err-spec
【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考