更新记录
0.2.0(2026-07-20)
- 新增 custom 自绘相册(序号选择、即时校验、大图预览、主题色、中英文),Android 无权限时自动降级 system
- 新增 camera 系统相机拍照/录像
- system 模式:Android Photo Picker / iOS PHPicker,零权限;自动 HEIC 转 JPG、视频抽帧封面
平台兼容性
uni-app(3.99)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | √ | 9.0 | 12 | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | × | × |
zoo-media-picker
一次打开相册,图片和视频同屏混排、混着一次选完。
uni.chooseImage 只能选图,uni.chooseMedia 的 mediaType 实际上也没法在一次会话里让用户既挑照片又挑视频——用户要传「3 张照片 + 1 段视频」,就得点两次入口、走两遍流程。这个插件解决的就是这件事。
特性
- 图片视频混选:一次打开,同屏混排,任意勾选
- 零权限:Android 走系统 Photo Picker、iOS 走 PHPicker,不申请
READ_MEDIA_IMAGES,不触发相册授权弹窗,Google Play 敏感权限声明表也不用填 - 零第三方依赖:不引 Glide / SDWebImage / RxJava,不和宿主 App 已有的库打架
- 脏活都包了:HEIC/HEIF 自动转 JPG、视频自动抽首帧封面、iCloud 未下载资源自动拉取、Android
content://自动落盘成可上传的真实文件 - API 对齐官方:走
uni.chooseMedia的参数与返回约定,另附 Promise 版本
快速开始
import { chooseMediaPro } from '@/uni_modules/zoo-media-picker'
chooseMediaPro({
count: 9,
mediaType: ['image', 'video'],
success: (res) => {
res.tempFiles.forEach((file) => {
console.log(file.mediaType, file.tempFilePath, file.size)
})
},
fail: (err) => {
console.log(err.errCode, err.errMsg)
}
})
Promise 版本:
import { chooseMediaProAsync } from '@/uni_modules/zoo-media-picker'
try {
const res = await chooseMediaProAsync({ count: 9 })
console.log(res.tempFiles)
} catch (err) {
console.log(err.errCode, err.errMsg)
}
仅支持 App(Android / iOS),H5 与小程序不支持。 UTS 插件必须打自定义基座才能真机调试,标准基座下不生效。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
count |
number | 9 |
最多可选/上传数量。不传默认 9;可自定义,取值会夹紧到 1 ~ 99 |
mediaType |
string[] | ['image', 'video'] |
混选就两个都传。传空数组或不传等同于混选 |
openType |
string | 'system' |
'system'=系统选择器(零权限);'custom'=自绘相册 UI(需宿主声明媒体权限,见下);'camera'=系统相机拍照/录像 |
sizeType |
string[] | ['compressed'] |
含 'compressed' 时压缩图片(长边 1280、质量 80);仅传 ['original'] 时保留原图 |
maxDuration |
number | 0 |
视频最长秒数,0 表示不限制 |
maxFileSize |
number | 0 |
单文件字节上限,0 表示不限制 |
convertHeic |
boolean | true |
HEIC/HEIF 是否转成 JPG |
extractVideoThumb |
boolean | true |
是否抽视频首帧作为封面 |
theme |
object | — | { primaryColor },作用于 custom 模式的选中圈/序号/完成按钮 |
language |
string | — | custom 模式 UI 语言:'en' 英文,空或其它跟随系统 |
返回
success 回调收到:
{
tempFiles: ZooMediaFileItem[]
openTypeUsed: string // 实际生效的模式,请求 custom 时这里会是 'system'
}
每个 ZooMediaFileItem:
| 字段 | 类型 | 说明 |
|---|---|---|
tempFilePath |
string | 沙盒内临时文件绝对路径,可直接喂 uni.uploadFile |
thumbTempFilePath |
string | 视频封面;图片时回填图片自身路径,方便前端统一只认这一个字段 |
fileName |
string | 保留可读原名,后缀已归一化(IMG_001.HEIC → IMG_001.jpg) |
fileExtension |
string | 已归一化的后缀,HEIC 转码后就是 jpg |
size |
number | 字节。取的是落盘后的真实体积,压缩过的图片就是压缩后的大小 |
mediaType |
string | 'image' | 'video' |
width |
number | 像素。竖屏视频已按旋转元数据换算成显示尺寸 |
height |
number | 像素 |
duration |
number | 视频毫秒;图片恒为 0 |
错误码
| errCode | 含义 |
|---|---|
| 9012001 | 当前页面无法打开媒体选择器 |
| 9012002 | 当前已有媒体选择任务正在执行 |
| 9012003 | 用户取消了媒体选择 |
| 9012004 | 未获取到有效的媒体文件 |
| 9012005 | 相册权限被拒绝 |
| 9012006 | 选择数量超出限制 |
| 9012007 | 视频时长超出限制 |
| 9012008 | 文件体积超出限制 |
| 9012009 | 复制文件到应用目录失败 |
| 9012010 | iCloud 资源下载失败 |
| 9012011 | 当前平台暂不支持媒体选择 |
| 9012012 | 媒体选择器初始化失败 |
| 9012013 | 媒体文件处理失败 |
errMsg 会带上具体是哪个文件、超了多少,可直接提示给用户。
三种模式(openType)
| 模式 | 说明 | 权限前提 |
|---|---|---|
system(默认) |
系统选择器,图片视频混选 | 零权限 |
custom |
自绘相册 UI:选中序号角标、时长/体积即时校验、大图预览、主题色、中英文 | 需宿主声明媒体权限;未声明时 Android 自动降级 system,iOS 运行时被拒也降级 |
camera |
系统相机拍照/录像 | 调用方无需 Android CAMERA 权限(Intent 委托);iOS 需宿主声明 NSCameraUsageDescription(录像另需 NSMicrophoneUsageDescription) |
任何降级都通过 success.openTypeUsed 如实告知实际生效的模式,不走 fail。请求 custom 但被降级时 openTypeUsed 会是 'system'。
custom 模式所需权限(宿主自行在 manifest.json 声明):
- Android:
READ_MEDIA_IMAGES/READ_MEDIA_VIDEO(13+),READ_EXTERNAL_STORAGE(≤12)。上架 Google Play 的宿主需自行处理敏感权限声明;不上架商店的宿主无此顾虑。 - iOS:
NSPhotoLibraryUsageDescription。
各平台行为
Android
| 系统版本 | 实际走的选择器 | 权限 |
|---|---|---|
| 13+ | 系统 Photo Picker(ACTION_PICK_IMAGES) |
无需权限 |
| 11–12 | Photo Picker backport(随 Google Play 系统更新下发) | 无需权限 |
| ≤10,或无 Play 服务的设备 | ACTION_GET_CONTENT + 多选 |
无需权限 |
- 插件不在 AndroidManifest 里声明任何权限,装上不会给宿主 App 增加任何权限。
count在 Photo Picker 上由系统强制;ACTION_GET_CONTENT分支系统不限数量,插件会在选完后校验并返回9012006。
iOS
| 系统版本 | 实际走的选择器 | 权限 |
|---|---|---|
| 14+ | PHPickerViewController |
无需相册权限 |
| ≤13 | UIImagePickerController(单选) |
需宿主声明 NSPhotoLibraryUsageDescription |
- iOS 14+ 是绝对主流路径,不需要任何隐私描述。
- iOS 13 及以下:插件坚持不硬写隐私描述(否则会给宿主 App 平白加上相册权限、影响审核)。宿主若没声明,插件返回
9012005而不是闪退。要支持这条分支,请在宿主的manifest.json→ App 权限配置里补NSPhotoLibraryUsageDescription。
FAQ
Q:为什么图片的 thumbTempFilePath 和 tempFilePath 一样?
图片本身就能直接渲染,再生成一份缩略图纯属浪费。回填自身路径是为了让前端统一只认 thumbTempFilePath,不用对图片和视频写两套渲染分支。
Q:为什么 GIF 选完还是原来那么大?
GIF 和 WebP 可能是动图,重编码只会留下第一帧、动画就没了。所以插件对这两类只做原样拷贝,sizeType: ['compressed'] 对它们不生效。只有 JPEG / PNG / HEIC 会被重编码,其中 PNG 用 PNG 编码保住透明通道。
Q:maxFileSize 是选之前限制还是选之后?
system 模式下 UI 是系统的,插件无法在用户勾选的瞬间拦截,只能选完再校验并返回 9012008;custom 模式则在选中时即时校验时长、超限当场拦截。另外,会被压缩的图片按压缩后的体积校验——原图 12MB、压缩后 800KB,在 maxFileSize: 1MB 下是通过的。
Q:视频会被压缩吗?
不会。sizeType 只作用于图片。视频原样落盘,避免转码耗时和画质损失。
Q:HEIC 一定能转成 JPG 吗?
Android 9 以下的系统解码器不支持 HEIF,这种情况下插件会原样拷贝,并如实把 fileExtension 保留为 heic(不会谎报成 jpg),前端可据此自行降级。iOS 全版本原生支持,不受影响。
Q:选中的顺序能保证吗?
能。iOS 15+ 开了 .ordered 选择模式,返回顺序即用户勾选顺序;Android Photo Picker 与系统返回顺序一致。
授权说明
本插件按 uni appid + 包名 粒度授权,一次购买绑定一个应用。更换 appid 或包名需重新购买。

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 0
赞赏 0
下载 12441222
赞赏 1934
赞赏
京公网安备:11010802035340号