更新记录

1.0.0(2026-08-22) 下载此版本

1.0.0

标识

  • 插件公开 ID 为 dyl-media-picker
  • UTS 导入路径为 @/uni_modules/dyl-media-picker

新增

  • Android/iOS 原生全屏媒体选择器
  • 支持图片、视频及混合选择
  • "全部 / 图片 / 视频" 筛选 Tab
  • 四列网格分页加载(每页 60 条)
  • 选择顺序编号和取消重排
  • 图片缩放和视频播放预览
  • 视频时长和文件大小限制校验
  • 原文件流式导出到应用缓存
  • 准备进度显示和取消/重试
  • Android 版本适配(API 21–34+)
  • iOS PhotoKit/iCloud 支持
  • 24 小时自动缓存清理
  • clearMediaPickerCache API
  • 完整错误码体系(9201001–9201008)

平台兼容性

uni-app x(4.76)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - 13.0 12 - -

dyl-media-picker

面向 uni-app x 的 Android / iOS 原生全屏图片、视频选择器。

通过一次 API 调用打开原生媒体选择界面,支持图片、视频或混合选择,并提供分类筛选、分页加载、全屏预览、数量与文件限制、原文件导出和缓存清理能力。

功能特性

  • 图片、视频单选或混合多选,最多可选 99 个文件
  • 全部、图片、视频三个分类 Tab,支持指定初始 Tab
  • 按选择顺序编号,确认后按选择顺序返回结果
  • 支持视频时长、文件大小和选择数量限制
  • 图片缩放预览、视频播放和暂停控制
  • iOS 预览采用相邻页面缓存、缩略图到高清图渐进加载和 PhotoKit 预热,降低快速滑动时的白屏、黑屏概率
  • 视频预览使用封面占位,媒体内容在可用区域内居中;Android 暂停时保留控制栏,iOS 使用系统播放器控制栏
  • 支持 iCloud 媒体下载和原文件导出进度提示
  • 结果统一导出为本地绝对路径,不向业务层暴露 content://ph:// 地址
  • 自动清理过期缓存,也支持业务层主动清理

平台与环境

项目 支持范围
应用框架 仅 uni-app x App
HBuilderX 4.76 及以上
Android Android 5.0 / API 21 及以上
iOS iOS 12.0 及以上

插件直接弹出原生页面,不需要在 pages.json 中注册插件页面。

如果同一个业务页面还需要编译到 Web 或小程序,请使用条件编译,只在 App 端导入和调用本插件。

接入与自定义基座

本插件包含 Kotlin、Swift、原生依赖、系统 Framework 和权限配置。以下情况需要重新制作自定义调试基座:

  • 首次将 dyl-media-picker 加入项目
  • 修改了 utssdk/app-androidutssdk/app-ios 下的代码或配置
  • 升级插件后,新版本包含原生实现或原生依赖变更
  • 调整了 Android 权限、目标 SDK,或 iOS Info.plist、Framework 配置

只修改业务页面中的调用参数、回调处理或界面逻辑,不需要因为这些改动重新制作基座。

Android 和 iOS 基座需要分别构建。调试时请确认运行的是包含当前插件版本的最新基座;旧基座不会动态获得新加入的原生代码。

如果项目曾使用旧目录 jx-media-picker,请直接替换为 dyl-media-picker,不要同时保留两份插件;同时更新所有 import 后重新制作自定义基座。新版本使用独立的 dyl-media-picker 缓存目录,旧缓存由系统缓存策略回收,也可以在升级前主动清理。

快速开始

import {
  chooseMedia,
  type ChooseMediaResult,
  type ChooseMediaFail
} from '@/uni_modules/dyl-media-picker'

const openMediaPicker = () : void => {
  chooseMedia({
    count: 9,
    mediaType: ['image', 'video'],
    initialTab: 'all',
    success: (result : ChooseMediaResult) : void => {
      console.log('已选择:', result.tempFiles.length)

      if (result.tempFiles.length > 0) {
        const firstFile = result.tempFiles[0]
        console.log(firstFile.tempFilePath)
      }
    },
    fail: (error : ChooseMediaFail) : void => {
      console.log(error.errCode, error.errMsg)
    },
    complete: () : void => {
      console.log('选择流程结束')
    }
  })
}

chooseMedia 使用回调 API,不返回 Promise

  • 选择并成功导出全部文件时调用 success
  • 用户返回或主动取消时调用 fail,错误码为 9201006
  • 其他权限、参数、初始化或导出错误也调用 fail
  • 无论成功或失败,最后都只调用一次 complete
  • successfail 互斥,不会在同一次调用中同时触发

常用配置

只选择图片

chooseMedia({
  count: 9,
  mediaType: ['image'],
  initialTab: 'image',
  success: (result) : void => {
    console.log(result.tempFiles)
  }
})

只选择视频

chooseMedia({
  count: 1,
  mediaType: ['video'],
  initialTab: 'video',
  maxVideoDuration: 60,
  maxFileSize: 200 * 1024 * 1024,
  success: (result) : void => {
    console.log(result.tempFiles)
  }
})

图片和视频混选

chooseMedia({
  count: 9,
  mediaType: ['image', 'video'],
  initialTab: 'all',
  title: '选择素材',
  accentColor: '#00C853',
  success: (result) : void => {
    console.log(result.tempFiles)
  }
})

API

chooseMedia(options)

打开原生媒体选择器。同一时间只允许存在一个选择器实例,重复调用会返回 9201002

参数 类型 默认值 说明
count number 9 最大选择数量,必须是 1–99 的整数
mediaType MediaPickerMediaType[] ['image', 'video'] 可选择的媒体类型,数组不得为空
initialTab MediaPickerTab 'all' 初始 Tab:'all''image''video'
maxVideoDuration number 0 视频最大时长,单位为秒;0 表示不限制,必须是非负整数
maxFileSize number 0 单个文件最大大小,单位为字节;0 表示不限制,必须是非负整数
title string '相册' 原生选择页标题
accentColor string '#00C853' 主题色,支持 #RRGGBB#AARRGGBB
success (result: ChooseMediaResult) => void - 文件全部导出成功回调
fail (error: ChooseMediaFail) => void - 取消或失败回调
complete () => void - 流程结束回调

MediaPickerMediaType 可取:

type MediaPickerMediaType = 'image' | 'video'

MediaPickerTab 可取:

type MediaPickerTab = 'all' | 'image' | 'video'

如果 initialTabmediaType 冲突,插件会回退到当前允许的媒体分类。例如只允许视频时,初始页最终会使用视频分类。

ChooseMediaResult

type ChooseMediaResult = {
  tempFiles: MediaPickerFile[]
}

结果数组保持用户的选择顺序。确认后插件先将选中的系统资源导出到插件缓存,全部成功后再一次性返回。

MediaPickerFile

字段 类型 说明
identifier string 系统媒体资源标识,用于插件内部定位和去重;受平台权限与资源生命周期约束,不应作为文件地址使用
type 'image' \| 'video' 媒体类型
tempFilePath string 导出的原文件本地绝对路径
thumbnailPath string 导出的缩略图本地绝对路径
name string 原始文件名
mimeType string MIME 类型
size number 原文件大小,单位为字节
width number 媒体宽度,单位为像素
height number 媒体高度,单位为像素
duration number 视频时长,单位为秒;图片固定为 0
createTime number 媒体创建时间,毫秒时间戳

tempFilePaththumbnailPath 是普通本地绝对路径,可用于文件读取、上传和后续原生处理。它们属于插件缓存文件,不是永久文件。

ChooseMediaFail

interface ChooseMediaFail extends IUniError {
  errCode: MediaPickerErrorCode
  identifier: string | null
}

当某个具体媒体导出失败时,identifier 可能携带对应资源标识;没有明确资源时为 null

clearMediaPickerCache(options)

清理插件缓存目录中超过 24 小时的旧会话。

import {
  clearMediaPickerCache,
  type ClearMediaPickerCacheResult,
  type ChooseMediaFail
} from '@/uni_modules/dyl-media-picker'

const clearPickerCache = () : void => {
  clearMediaPickerCache({
    success: (result : ClearMediaPickerCacheResult) : void => {
      console.log('删除文件数:', result.removedFileCount)
      console.log('释放字节数:', result.freedSize)
    },
    fail: (error : ChooseMediaFail) : void => {
      console.log(error.errCode, error.errMsg)
    }
  })
}
返回字段 类型 说明
removedFileCount number 本次删除的文件数量
freedSize number 本次释放的空间,单位为字节

选择器打开期间不要清理缓存;此时清理请求会失败并返回 9201008

预览与导出行为

图片预览

  • 支持全屏查看和缩放
  • iOS 优先显示可用缩略图,再渐进加载高清图
  • 当前页和相邻页会被缓存与预热,快速左右滑动时不必每次重新创建全部媒体视图
  • 系统内存紧张时可能主动回收非当前页缓存,插件会在再次进入该页时重新加载

视频预览

  • 使用视频封面作为播放器准备完成前的占位内容
  • 媒体按比例在预览区域内居中显示
  • Android 暂停时控制栏保持可见,便于继续播放或拖动进度
  • iOS 使用 AVPlayerViewController 的系统播放控制栏
  • 离开当前预览页时会暂停视频,避免多个视频同时播放

iCloud 媒体

iOS 素材只存在于 iCloud 时,高清预览或确认导出需要联网下载。下载期间可能先显示缩略图或视频封面;网络速度会直接影响高清内容和播放器的就绪时间。

maxFileSize 在系统能提前获取文件大小时会在选择阶段校验。对于 iCloud 等大小暂不可知的资源,最终以导出阶段的校验结果为准。

权限说明

Android

  • API 21–22:无需运行时授权
  • API 23–32:运行时申请 READ_EXTERNAL_STORAGE
  • API 33+:根据 mediaType 申请 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO
  • API 34+:支持 READ_MEDIA_VISUAL_USER_SELECTED 部分媒体访问
  • 要完整使用 Android 14 部分媒体访问,宿主 targetSdkVersion 应不低于 34
  • 插件不会覆盖宿主工程的目标 SDK 配置

用户拒绝权限或当前授权状态不可用时,插件返回 9201003

iOS

  • 使用 PhotoKit 读取系统相册
  • iOS 14+ 支持 limited Photos 权限,并只展示当前被授权的素材
  • 插件声明 NSPhotoLibraryUsageDescription,宿主可以根据产品文案覆盖该字段
  • 原生配置依赖 PhotosPhotosUIUIKitAVFoundationAVKit 等系统 Framework

权限或 Framework 配置发生变化后,需要重新制作 iOS 自定义基座。

缓存生命周期

  • 导出目录:<application-cache>/dyl-media-picker/<session-id>/
  • 每次打开选择器时自动删除超过 24 小时的旧会话
  • 调用 clearMediaPickerCache 时同样只清理超过 24 小时的旧会话
  • 操作系统仍可能因空间压力提前回收缓存
  • 需要长期保留的文件,应在成功回调中尽快上传或复制到业务持久目录
  • 不要把缓存路径长期写入数据库后直接复用

错误码

错误码 含义 常见原因
9201001 参数不合法 数量越界、媒体类型为空、颜色格式错误或限制值不是非负整数
9201002 选择器已打开 上一次选择流程尚未结束,又调用了 chooseMedia
9201003 相册权限不足 用户拒绝权限,或当前授权状态不可用
9201004 选择器初始化失败 原生页面、数据源或宿主环境初始化异常
9201005 原文件导出失败 系统资源已删除、iCloud 下载失败或文件复制失败
9201006 用户取消选择 用户从选择器主界面返回或关闭选择器
9201007 缓存空间不足 导出目录无法创建、写入或设备可用空间不足
9201008 缓存清理失败 选择器正在使用缓存,或目录删除失败

业务层通常应将 9201006 作为正常取消处理,不必展示错误提示。

常见问题

加入插件后运行没有效果,或提示找不到原生类

当前运行的自定义基座没有包含插件。重新制作对应平台的自定义基座,并确认设备安装的是新基座。

iOS 云打包能通过,但旧基座仍然表现为修改前的版本

UTS 原生插件代码会编译进基座。仅替换业务资源不会更新 Swift 实现,需要重新制作并安装 iOS 基座。

Android 14 只能看到部分照片

这是系统的部分媒体授权行为。确认宿主目标 SDK 不低于 34,并在授权流程中处理 READ_MEDIA_VISUAL_USER_SELECTED

iOS 预览 iCloud 视频时短暂显示封面

播放器需要等待系统返回可播放的 AVAsset。插件会保留视频封面,资源下载完成后再切换到播放器;请确认设备网络可用。

成功回调中的路径过一段时间失效

返回的是插件缓存路径。需要持久保存时,请在成功回调后立即复制到业务目录或完成上传。

如何避免数组越界

UTS 在 Android 和 iOS 原生端访问越界数组会抛出异常。读取 tempFiles[index] 前应显式检查:

if (index >= 0 && index < result.tempFiles.length) {
  const file = result.tempFiles[index]
  console.log(file.tempFilePath)
}

调试与验收

当前项目提供了调用示例页面:媒体选择器调试页

完整的自动检查、真机测试矩阵和发布前清单见:TESTING.md

建议至少在以下场景进行真机回归:

  • 首次授权、拒绝后重试、iOS limited Photos、Android 14 部分媒体权限
  • 图片、视频、混合选择,以及数量、时长、大小限制
  • 连续快速左右滑动图片和视频,并多次滑回同一素材
  • 从预览页返回列表,确认列表位置、选中状态和缩略图不闪烁
  • iCloud 原图和视频的弱网下载、取消与失败
  • 导出大文件时的进度、空间不足和缓存清理

从 uni.chooseMedia 迁移

// 旧代码
uni.chooseMedia({
  count: 9,
  mediaType: ['image', 'video'],
  success: (result) : void => {
    console.log(result.tempFiles)
  }
})

// 新代码
import { chooseMedia } from '@/uni_modules/dyl-media-picker'

chooseMedia({
  count: 9,
  mediaType: ['image', 'video'],
  success: (result) : void => {
    // 返回原文件、缩略图、尺寸、时长、MIME 和创建时间等完整信息
    console.log(result.tempFiles)
  }
})

迁移后需要注意:

  • 本插件只支持 uni-app x App
  • 首次接入必须重新制作 Android / iOS 自定义基座
  • 用户取消会进入 fail,错误码为 9201006
  • 返回路径位于插件缓存,长期使用前需要持久化
  • iCloud 素材可能在确认后继续下载和导出

隐私、权限声明

1. 本插件需要申请的系统权限列表:

相册,插件已内置

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。