更新记录
1.0.26(2026-11-11)
- 优化说明文档,补齐“作者系列 UTS 插件”清单及插件市场链接,便于按能力查找。
1.0.25(2026-11-03)
- 新增按“媒体、相册、处理、输出、管理”组织的双宿主演示 Tabs,支持进入指定相册、切换来源与时间筛选、填写自己的上传地址,并明确区分上传演练与实际上传。
- 修复示例加载末页覆盖已加载媒体、图片或视频续页切换为混合查询、查询与选择切换后旧回调覆盖新结果的问题。
- 修复普通监听参数、重复启动和离页后迟到监听释放,补齐预览、缓存清理与自检的请求归属;保存当前文件只使用已准备的原图或视频,基础自检始终只做上传演练。
- 修复 HarmonyOS 缓存清理的秒与毫秒及年龄语义,全部缓存清理同步覆盖插件专属持久游标;分页、缩略图和上传缺省参数与 Android、iOS 对齐。
- 修复示例页面和辅助模块使用相对引入路径的问题,统一通过
@/uni_modules/ 引用插件内文件,复制页面到其他目录时无需另行复制辅助代码。
- 整理使用说明和真实平台边界;本次 HarmonyOS 原生实现变更需要重新制作并安装匹配的自定义基座或 HAP。Android、iOS 本次仅更新示例与说明,无需因本轮改动重制原生基座。
1.0.24(2026-10-17)
- 修复微信和支付宝小程序编译时误加载 HarmonyOS 原生 ETS 文件,避免 HBuilderX 5.24 报
GalleryHarmonyTypes.ets 语法错误。
- 小程序继续返回明确的暂不支持错误,不改变 Android、iOS、HarmonyOS 的相册 API 和调用方式。
查看更多
平台兼容性
uni-app(5.07)
| Vue2 |
Vue3 |
Chrome |
Safari |
app-vue |
app-nvue |
Android |
iOS |
鸿蒙 |
| √ |
√ |
× |
× |
√ |
√ |
6.0 |
√ |
√ |
| 微信小程序 |
支付宝小程序 |
抖音小程序 |
百度小程序 |
快手小程序 |
京东小程序 |
鸿蒙元服务 |
QQ小程序 |
飞书小程序 |
小红书小程序 |
快应用-华为 |
快应用-联盟 |
| × |
× |
× |
× |
× |
× |
× |
× |
× |
× |
× |
× |
uni-app x(5.07)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| × |
× |
6.0 |
√ |
√ |
× |
lizhao-gallery-pro
为 uni-app / uni-app x 提供用户授权范围内的系统相册图片、视频读取、缩略图、文件准备、上传、保存、元数据和变化查询。
功能特色
| 功能 |
实现效果 |
使用示例 |
| 自定义媒体列表 |
分页读取图片、视频或混合媒体,按时间、相册和来源筛选 |
基础读取、筛选 |
| 渐进缩略图 |
当前页先显示信息,再分批补图 |
渐进列表 |
| 相册分组 |
先显示文件夹名称和数量,按需生成封面 |
相册与封面 |
| 准备预览与上传文件 |
一次返回预览、上传和可选 poster 路径 |
准备媒体 |
| 上传和保存 |
按输入顺序返回批量处理明细 |
上传、保存 |
| 图片 EXIF 与视频参数 |
按需读取拍摄参数;位置默认关闭 |
元数据 |
| 相册变化处理 |
页面监听变化,或以持久化游标查询新增、删除和修改 |
监听、增量查询 |
| 能力与缓存管理 |
按运行平台控制入口,按类型清理插件缓存 |
能力与缓存 |
适合哪些场景
| 场景 |
推荐能力 |
接入方式或边界 |
| 社区发帖、评价晒单、工单附件 |
媒体分页、渐进缩略图、文件准备和上传 |
从列表返回的真实 id 继续处理 |
| 自定义相册选择器、素材管理 |
相册分组、时间和来源筛选 |
来源分类受设备目录和系统元数据影响 |
| 全景图片列表 |
分页读取图片,按宽高比筛选 |
2:1 尺寸不能证明含有 360° 全景元数据 |
| 图片编辑、视频预览 |
准备或导出临时文件 |
详情页使用导出结果,不放大小缩略图 |
| 业务生成图片、视频归档 |
保存到系统相册 |
输入必须是可访问的本地文件 |
| 拍摄信息、视频详情页 |
元数据和 EXIF |
位置需显式开启并满足系统权限 |
| 相册刷新、增量备份 |
变化监听、持久化增量游标 |
监听依赖进程存活;游标在业务处理成功后推进 |
下载与导入
从基础到进阶
基础功能配置示例(简单示例)
用途:申请权限并读取第一批媒体;前置:已导入插件,App 使用包含本插件原生能力和权限声明的自定义基座或正式安装包。宿主:uni-app(Vue2/Vue3);触发:在用户点击事件中调用 readFirstGalleryPage(),无需额外初始化接口。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readFirstGalleryPage() {
const capabilities = GalleryPro.getGalleryCapabilities()
const nativePlatform = capabilities.platform === 'app-android' ||
capabilities.platform === 'app-ios' || capabilities.platform === 'app-harmony'
if (!nativePlatform) {
console.log('当前平台不支持系统相册操作', capabilities.platform, capabilities.message)
return
}
GalleryPro.requestGalleryPermission({
// all 请求图片和视频范围;只需要图片时可使用 image。
mediaType: 'all',
// 兼容保留参数;当前不会据此扩大用户授予的系统访问范围。
preferFullAccess: false,
success(permission) {
console.log('授权结果', permission.status, permission.mediaType, permission.platform)
console.log('权限说明', permission.message)
if (!permission.granted) {
console.log('是否需要前往设置', permission.shouldOpenSettings)
return
}
// HarmonyOS 的能力布尔值受当前授权影响,授权后重新读取。
const authorizedCapabilities = GalleryPro.getGalleryCapabilities()
if (!authorizedCapabilities.mixed) {
console.log('当前读取能力尚未就绪', authorizedCapabilities.message)
return
}
if (permission.limited) {
console.log('本次只读取系统允许访问的部分媒体')
}
GalleryPro.getGalleryMedia({
mediaType: 'all',
pageSize: 30, // 每页 30 条;可填写 1~200。
pageToken: '', // 首次查询不使用旧的下一页令牌。
thumbnailMode: 'none', // 最小流程先取列表,不等待缩略图。
success(result) {
console.log('查询结果', result.success, result.platform, result.mediaType)
console.log('可见总数与说明', result.total, result.message)
result.items.forEach(item => {
console.log('媒体入口', item.id, item.mediaType, item.fileName)
})
console.log('下一页', result.hasMore, result.nextPageToken)
},
fail(error) {
// 不把权限或读取失败显示成“相册为空”。
console.log('读取失败', error.errSubject, error.errCode, error.errMsg)
},
complete(result) {
// 这里表示本次列表动作结束,不代表整个相册已读完。
console.log('列表动作结束', result)
}
})
},
fail(error) {
console.log('申请权限失败', error.errCode, error.errMsg)
},
complete(result) {
// 权限动作结束不等于嵌套的列表动作结束。
console.log('权限动作结束', result)
}
})
}
高级示例
检查权限,按相册、时间和来源筛选
用途:读取最近七天指定来源的媒体;前置:已有相册读取授权。宿主:uni-app;触发:点击筛选按钮调用 readRecentCameraAlbum(),先取得真实相册 ID,再查询该相册。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
/** @param {import('@/uni_modules/lizhao-gallery-pro').GalleryMediaItem} item */
function printMediaItem(item) {
// 尺寸是像素,size 是字节;视频时长和两个时间字段均为毫秒。
console.log('身份与格式', item.id, item.mediaType, item.fileName, item.mimeType)
console.log('尺寸、时长与大小', item.width, item.height, item.durationMs, item.size)
console.log('创建与修改时间', item.createTime, item.modifiedTime)
console.log('相册与来源', item.albumId, item.albumName, item.sourceType, item.sourceLabel)
// 以下是列表原始返回值;资产标识不保证可直接渲染或上传。
console.log('列表路径', item.originalPath, item.renderPath, item.uploadPath)
console.log('缩略图与导出要求', item.thumbnailPath, item.requiresExport)
}
export function readRecentCameraAlbum() {
GalleryPro.checkGalleryPermission({
mediaType: 'all',
preferFullAccess: true, // 当前不改变系统授权范围;不能借此绕过 limited。
success(permission) {
if (!permission.granted) {
console.log('请先授权', permission.status, permission.shouldOpenSettings)
return
}
GalleryPro.getGalleryAlbums({
mediaType: 'all',
sourceType: 'camera',
includeCoverThumbnail: false,
success(groups) {
if (groups.albums.length === 0) {
console.log('当前授权范围内没有匹配相册')
return
}
const album = groups.albums[0]
// 同一轮分页须复用这组筛选值;改变筛选后从空 pageToken 重新开始。
const endTime = Date.now()
const startTime = endTime - 7 * 24 * 60 * 60 * 1000
GalleryPro.getGalleryMedia({
mediaType: 'all',
pageSize: 30,
pageToken: '',
startTime: startTime,
endTime: endTime,
albumId: album.albumId,
sourceType: 'camera',
sortOrder: 'asc', // 从较早的媒体开始;默认 desc。
includeHidden: true, // 只表达偏好,仍受系统可见范围限制。
includeThumbnail: true,// 未设置 thumbnailMode 时等价于 sync。
thumbnailWidth: 320,
thumbnailHeight: 180,
success(result) {
result.items.forEach(printMediaItem)
console.log('继续分页所需结果', result.hasMore, result.nextPageToken)
},
fail(error) {
console.log('筛选失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('筛选结束', result)
}
})
},
fail(error) {
console.log('相册分组失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('相册分组动作结束', result)
}
})
},
fail(error) {
console.log('权限检查失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('权限检查动作结束', result)
}
})
}
先显示当前页,再分批补缩略图
用途:媒体列表先出现、图片随后补齐;前置:已有图片读取授权。宿主:uni-app;触发:在列表加载事件中调用 readProgressiveImages()。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readProgressiveImages() {
GalleryPro.getGalleryImages({
pageSize: 30,
includeThumbnail: false, // 显式 thumbnailMode 优先于此兼容开关。
thumbnailMode: 'progressive', // none 不生成;sync 在列表返回前生成。
thumbnailBatchSize: 4, // 默认 4,每批允许 1~20 个。
thumbnailWidth: 320, // 请求物理像素尺寸,按实际显示区域选择。
thumbnailHeight: 320,
success(result) {
console.log('先渲染当前页', result.items)
},
thumbnailProgress(event) {
console.log('当前页处理量', event.current, event.total, event.done, event.message)
event.items.forEach(thumbnail => {
if (thumbnail.thumbnailPath !== '') {
// 实际页面按 id 更新这一项,不替换为另一页的缩略图。
console.log('补图', thumbnail.id, thumbnail.thumbnailPath)
}
console.log('实际尺寸与说明', thumbnail.width, thumbnail.height, thumbnail.message)
})
},
fail(error) {
console.log('列表读取失败', error.errCode, error.errMsg)
},
complete(result) {
// 渐进模式在当前页缩略图处理结束后才 complete。
// done 表示已处理完,不保证每个媒体都能生成缩略图。
console.log('本页列表及渐进处理结束', result)
}
})
}
为选中媒体单独生成缩略图
用途:生成列表小图或 2:1 图片的预览缩略图;前置:参数 ids 来自当前授权列表,不使用自造 ID。宿主:uni-app;触发:选中媒体后调用 createSelectedThumbnails(ids)。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function createSelectedThumbnails(ids) {
if (ids.length === 0) return
GalleryPro.getGalleryThumbnails({
ids: ids,
width: 800,
height: 400,
// quality 只在 HarmonyOS 调节 JPEG 质量,范围 1~100,默认 85。
// Android/iOS 当前使用各自固定编码质量,不读取此参数。
quality: 85,
success(result) {
console.log('缩略图结果', result.success, result.message)
result.items.forEach(item => {
console.log(item.id, item.thumbnailPath, item.width, item.height, item.message)
})
},
fail(error) {
console.log('缩略图失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('缩略图动作结束', result)
}
})
}
按 ID 重新读取单个媒体
用途:打开详情前确认媒体仍可访问;前置:id 来自列表结果。宿主:uni-app;触发:点击列表项时调用 readSelectedMedia(id)。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readSelectedMedia(id) {
GalleryPro.getMediaById({
id: id,
includeThumbnail: true, // 默认 false;这里同时取小图供详情页占位。
success(result) {
console.log('单媒体结果', result.success, result.message)
console.log('当前媒体', result.item.id, result.item.thumbnailPath)
},
fail(error) {
// 媒体删除或授权范围变化后,旧 id 可能失效。
console.log('媒体暂不可访问', error.errCode, error.errMsg)
},
complete(result) {
console.log('单媒体动作结束', result)
}
})
}
一次准备预览、上传与 poster
用途:用户选中后再准备可用文件;前置:id 来自当前授权列表。宿主:uni-app;触发:调用 prepareSelectedMedia(id),将结果赋给页面自己的数据。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function prepareSelectedMedia(id) {
GalleryPro.prepareGalleryMedia({
id: id,
includePoster: true, // 默认 true;仅需上传时可关闭,见模块化示例。
posterWidth: 640, // 默认 320,单位像素。
posterHeight: 360,
success(result) {
console.log('准备结果', result.success, result.id, result.mediaType, result.message)
console.log('页面 image/video 的 src', result.renderPath)
console.log('uni.uploadFile 的 filePath', result.uploadPath)
console.log('image 占位或 video 的 poster', result.posterPath)
console.log('文件字节数与导出缓存命中', result.size, result.cacheHit)
},
fail(error) {
console.log('文件准备失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('文件准备结束', result)
}
})
}
按用途导出独立临时文件
用途:详情、编辑或业务上传需要普通文件;前置:id 来自列表。宿主:uni-app;触发:调用 exportSelectedOriginal(id),从真实媒体信息取得文件名。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function exportSelectedOriginal(id) {
GalleryPro.getMediaById({
id: id,
includeThumbnail: false,
success(media) {
GalleryPro.exportMediaToTempFile({
id: media.item.id,
// render / upload / original 表达用途,均返回同一文件的两种可用路径。
exportType: 'original',
// 可填写自己的文件名;这里沿用媒体名,不把文件名当作目标目录。
fileName: media.item.fileName,
success(result) {
console.log('导出结果', result.success, result.id, result.message)
console.log('预览与上传路径', result.renderPath, result.uploadPath)
console.log('字节数与缓存命中', result.size, result.cacheHit)
},
fail(error) {
console.log('导出失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('导出动作结束', result)
}
})
},
fail(error) {
console.log('读取媒体信息失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('媒体信息动作结束', result)
}
})
}
快速显示相册,按需补封面
用途:相册侧栏先显示名称和数量;前置:已获相册读取授权。宿主:uni-app;触发:调用 readAlbumFolders(),下面只为第一个非空相册补封面,实际页面可按可见范围分批处理。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readAlbumFolders() {
GalleryPro.getGalleryAlbums({
mediaType: 'all',
sourceType: 'all',
includeCoverThumbnail: false, // 默认快速模式,不等待全部封面。
success(result) {
console.log('相册结果', result.success, result.message)
result.albums.forEach(album => {
console.log('相册', album.albumId, album.albumName, album.sourceType)
console.log('数量', album.count, album.imageCount, album.videoCount)
console.log('封面', album.coverThumbnailPath)
console.log('最新媒体', album.latestMediaId, album.latestMediaType)
console.log('最新文件与时间', album.latestFileName, album.latestCreateTime)
})
const album = result.albums.find(item => item.latestMediaId !== '')
if (album == null) return
GalleryPro.getGalleryThumbnails({
ids: [album.latestMediaId],
width: 180,
height: 180,
success(thumbnails) {
thumbnails.items.forEach(item => {
if (item.id === album.latestMediaId) {
album.coverThumbnailPath = item.thumbnailPath
}
})
console.log('此相册的封面', album.albumId, album.coverThumbnailPath)
},
fail(error) {
// 补封面失败不隐藏已经取得的文件夹。
console.log('封面暂不可用', error.errCode, error.errMsg)
},
complete(result) {
console.log('本批封面处理结束', result)
}
})
},
fail(error) {
console.log('相册读取失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('相册分组动作结束', result)
}
})
}
校验上传路径,或发送到自己的业务接口
用途:先导出,再按所选模式处理;前置:ids 来自列表,真实上传地址由应用提供。宿主:uni-app;触发:checkSelectedUploadPaths(ids) 只校验,uploadSelectedMedia(ids, url) 才发送网络请求。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
function submitGalleryMedia(ids, url, dryRun) {
if (ids.length === 0) return
if (!dryRun && url.trim() === '') {
console.log('请填写自己业务服务器的 HTTPS 上传地址')
return
}
GalleryPro.uploadGalleryMedia({
ids: ids,
url: url, // dryRun 为 true 时可为空。
dryRun: dryRun,
name: 'file', // 文件表单字段名须与服务端约定一致。
formData: { scene: 'feedback' }, // 附加业务字段,不在页面保存服务端 Secret。
concurrency: 2, // 默认 1,允许 1~4。
retryCount: 1, // 默认 0,允许 0~5 次额外重试。
timeoutMs: 120000, // 单文件请求超时,单位毫秒。
progress(event) {
// 阶段可能为 export、upload、dryRun、complete。
console.log('阶段', event.stage, event.current, event.total)
console.log('进度百分比与说明', event.progress, event.message)
},
success(result) {
console.log('批次结果', result.success, result.successCount, result.failCount, result.message)
result.items.forEach(item => {
console.log('输入位置与媒体', item.index, item.id, item.success, item.message)
// HTTP 成功仍需由业务检查 responseText 中的应用层结果。
console.log('HTTP 结果', item.statusCode, item.responseText)
if (item.renderPath != null) console.log('可预览路径', item.renderPath)
if (item.uploadPath != null) console.log('可上传路径', item.uploadPath)
if (item.size != null) console.log('文件字节数', item.size)
})
},
fail(error) {
console.log('上传任务失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('上传或路径校验结束', result)
}
})
}
export function checkSelectedUploadPaths(ids) {
// 不发起网络请求,成功只说明导出链路可用。
submitGalleryMedia(ids, '', true)
}
export function uploadSelectedMedia(ids, url) {
// url 使用应用自己的配置,不能把演示域名当成真实接口。
submitGalleryMedia(ids, url, false)
}
保存本地图片、视频并检查逐项结果
用途:把业务生成或下载的文件归档到相册;前置:paths 是实际可读的绝对路径或 file:// 路径。宿主:uni-app;触发:用户确认保存后调用 saveGeneratedMedia(paths)。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function saveGeneratedMedia(paths) {
if (paths.length === 0) return
GalleryPro.saveMediaToGallery({
paths: paths, // 不传网络地址、content URI 或虚构示例路径。
albumName: '工单附件', // 可替换为自己的相册名;空字符串使用系统默认相册。
duplicatePolicy: 'skip', // 默认 allow;skip 只跳过当前可见且能确认的重复项。
progress(event) {
console.log('处理进度', event.current, event.total, event.progress)
console.log('当前汇总', event.successCount, event.failCount)
console.log('当前输入与说明', event.currentPath, event.message)
},
success(result) {
// 至少一项成功或跳过时可进入 success,仍须检查 failCount。
console.log('批次状态', result.success, result.message)
console.log('保存或跳过/失败/跳过', result.successCount, result.failCount, result.skippedCount)
result.items.forEach(item => {
console.log('输入', item.index, item.sourcePath, item.mediaType)
console.log('结果', item.success, item.skipped, item.mediaId, item.albumName, item.message)
if (item.errCode != null) console.log('单项错误码', item.errCode)
})
},
fail(error) {
console.log('保存任务失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('保存流程结束', result)
}
})
}
读取 EXIF、视频参数和显式开启的位置
用途:按选中 ID 展示详情;前置:ids 为 1~100 个不重复 ID,位置开关应由用户知情操作触发。宿主:uni-app;触发:默认调用 readMetadataWithoutLocation(ids),用户确认读取位置后调用 readMetadataWithLocation(ids)。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readSelectedMetadata(ids, includeLocation = false) {
GalleryPro.getGalleryMetadata({
ids: ids,
includeExif: true, // 默认 true;只读视频参数可关闭,见模块化示例。
includeLocation: includeLocation, // 默认 false;开启后仍受系统权限和媒体内容限制。
useCache: true, // 仅复用非敏感缓存,位置不会进入插件缓存。
progress(event) {
console.log('元数据进度', event.current, event.total, event.successCount, event.failCount)
console.log('当前媒体', event.currentId)
},
success(result) {
// 批次完成后逐项读取;所有项目读取失败也可能正常返回汇总。
console.log('汇总', result.success, result.successCount, result.failCount, result.message)
result.items.forEach(item => {
console.log('身份与结果', item.id, item.success, item.mediaType, item.message)
console.log('像素、时长、方向', item.width, item.height, item.durationMs, item.orientation)
console.log('拍摄时间、相机和镜头', item.captureTime, item.cameraMake, item.cameraModel, item.lensModel)
console.log('可选曝光参数', item.iso, item.exposureTime, item.aperture)
console.log('可选焦距(毫米)', item.focalLength, item.focalLength35mm)
console.log('视频参数', item.videoCodec, item.videoBitrate, item.videoFrameRate)
console.log('位置可用性与缓存', item.locationAvailable, item.fromCache)
if (item.errCode != null) {
// 9070032 可与 success=true 同时存在,表示非敏感缓存异常。
console.log('单项诊断码', item.errCode)
}
if (item.location != null) {
// 示例只检查范围,不把真实经纬度写进日志。
const location = item.location
const validCoordinate = Number.isFinite(location.latitude) &&
Number.isFinite(location.longitude) &&
Math.abs(location.latitude) <= 90 && Math.abs(location.longitude) <= 180
const hasAltitude = location.altitude != null
console.log('本次返回有效坐标/海拔字段', validCoordinate, hasAltitude)
}
})
},
fail(error) {
console.log('元数据任务无法启动', error.errCode, error.errMsg)
},
complete(result) {
console.log('元数据批次结束', result)
}
})
}
export function readMetadataWithoutLocation(ids) {
readSelectedMetadata(ids, false)
}
export function readMetadataWithLocation(ids) {
// 仅绑定到用户明确选择读取位置的操作,不在页面加载时自动执行。
readSelectedMetadata(ids, true)
}
进阶示例
分页读取可访问图片,并筛选 2:1 全景图
用途:按页筛选当前授权范围内的图片;前置:已获图片读取授权。宿主:uni-app;触发:调用 startPanoramaRead(),页面离开时调用 stopPanoramaRead(),阻止迟到结果更新本轮数据。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
let panoramaRequestVersion = 0
let panoramaImages = []
export function stopPanoramaRead() {
// 只作业务侧失效处理,不会取消插件已经开始的原生查询。
panoramaRequestVersion += 1
}
export function startPanoramaRead() {
const version = ++panoramaRequestVersion
panoramaImages = []
function readPage(pageToken) {
if (version !== panoramaRequestVersion) return
GalleryPro.getGalleryImages({
pageSize: 100,
pageToken: pageToken,
sortOrder: 'desc',
thumbnailMode: 'none',
success(result) {
if (version !== panoramaRequestVersion) return
result.items.forEach(item => {
if (item.width <= 0 || item.height <= 0) return
const ratio = item.width / item.height
// 1.95~2.05 为像素误差容差;不限制 JPG/PNG 等编码。
if (ratio >= 1.95 && ratio <= 2.05) panoramaImages.push(item)
})
if (result.hasMore) {
if (result.nextPageToken === '' || result.nextPageToken === pageToken) {
console.log('下一页令牌无效,停止本轮读取')
return
}
readPage(result.nextPageToken)
return
}
console.log('本轮筛选结束', panoramaImages.length, panoramaImages)
},
fail(error) {
if (version === panoramaRequestVersion) {
console.log('分页读取失败', error.errCode, error.errMsg)
}
},
complete(result) {
if (version === panoramaRequestVersion) console.log('当前分页动作结束', result)
}
})
}
readPage('')
}
| 需要的结果 |
判断方式 |
边界 |
| 允许少量像素误差的 2:1 图片 |
ratio >= 1.95 && ratio <= 2.05 |
不检查文件编码 |
| 像素严格为 2:1 |
item.width === item.height * 2 |
不证明图片具有交互全景信息 |
| 只取 JPEG |
同时检查 item.mimeType === 'image/jpeg' |
需要其他编码时按真实 MIME 调整 |
| 完整画面展示 |
页面图片使用 mode="aspectFit" |
aspectFill 会裁剪边缘 |
监听变化并保留监听器归属
用途:相册变化后提示页面刷新;前置:读取权限有效。宿主:uni-app;触发:页面进入时调用 startLiveGalleryObserver(),页面卸载时调用 stopLiveGalleryObserver()。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
let liveObserverId = ''
let observerVersion = 0
let observerStarting = false
const pendingStopIds = new Set()
function stopOwnedObserver(id) {
pendingStopIds.add(id)
GalleryPro.stopGalleryChangeObserver({
observerId: id,
success(result) {
console.log('停止结果', result.observerId, result.stopped, result.message)
if (result.stopped) {
pendingStopIds.delete(result.observerId)
if (liveObserverId === result.observerId) liveObserverId = ''
}
},
fail(error) {
// 保留待清理 ID,调用 retryGalleryObserverCleanup 可重试。
console.log('停止监听失败', id, error.errCode, error.errMsg)
},
complete(result) {
console.log('本次停止动作结束', result)
}
})
}
export function startLiveGalleryObserver() {
if (observerStarting || liveObserverId !== '') return
observerStarting = true
const version = ++observerVersion
GalleryPro.startGalleryChangeObserver({
mediaType: 'all', // 需要刷新的业务范围,不是原生变化的精确媒体类型。
debounceMs: 500, // 默认 300 毫秒,允许 0~5000。
includeChanges: true, // 默认 false;开启后才尝试返回精确变化。
maxChanges: 2000, // 允许 1~10000;超限需重建全量基线。
change(event) {
if (version !== observerVersion) return
console.log('事件归属', event.observerId, event.mediaType)
console.log('事件原因、时间和合并数', event.reason, event.changedAt, event.mergedCount)
console.log('事件说明', event.message)
if (event.permissionStatus != null) console.log('授权范围变化', event.permissionStatus)
console.log('旧/新事件游标', event.cursor, event.nextCursor)
if (event.resetRequired === true || event.detailsAvailable !== true) {
console.log('重新读取页面数据', event.resetRequired, event.resetReason)
return
}
console.log('本次精确变化数', event.changeCount)
console.log('新增', event.addedIds)
console.log('删除', event.removedIds)
console.log('修改', event.updatedIds)
// 页面实际完成更新后再更新自己的状态;不把观察事件当成服务端同步完成。
},
success(result) {
console.log('注册结果', result.observerId, result.platform, result.message)
if (version !== observerVersion) {
// 注册回调迟到时,只停止这次回调返回的监听器。
stopOwnedObserver(result.observerId)
return
}
liveObserverId = result.observerId
},
fail(error) {
if (version === observerVersion) console.log('注册失败', error.errCode, error.errMsg)
},
complete(result) {
if (version === observerVersion) observerStarting = false
// complete 只代表注册动作结束;change 可在之后持续触发。
console.log('注册动作结束', result)
}
})
}
export function stopLiveGalleryObserver() {
observerVersion += 1
observerStarting = false
if (liveObserverId !== '') stopOwnedObserver(liveObserverId)
}
export function retryGalleryObserverCleanup() {
Array.from(pendingStopIds).forEach(id => stopOwnedObserver(id))
}
查询持久化增量,业务完成后再推进游标
用途:跨页面、跨启动保留变化查询基线;前置:已有读取权限,存储键由应用按账号隔离。宿主:uni-app;触发:调用 readPersistentGalleryChanges(),应用确认真实业务完成后才调用 confirmGalleryChangesApplied()。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
const cursorStorageKey = 'gallery-change-cursor'
let pendingChanges = null
let changesRequestVersion = 0
export function readPersistentGalleryChanges() {
const version = ++changesRequestVersion
pendingChanges = null
const stored = uni.getStorageSync(cursorStorageKey)
const cursor = typeof stored === 'string' ? stored : ''
GalleryPro.getGalleryChanges({
cursor: cursor, // 空字符串建立初始基线;后续使用原样保存的游标。
mediaType: 'all', // 更换媒体范围可能触发 filterChanged。
maxChanges: 2000,
success(result) {
if (version !== changesRequestVersion) return
pendingChanges = result
console.log('增量结果', result.success, result.message)
console.log('初始/重建', result.isInitial, result.resetRequired, result.resetReason)
console.log('数量与创建时间', result.changeCount, result.currentTotal, result.createdAt)
console.log('待确认的新游标', result.nextCursor)
if (result.isInitial || result.resetRequired) {
console.log('先执行自己的全量业务流程,本段代码不自动确认基线')
return
}
console.log('待处理新增', result.addedIds)
console.log('待处理删除', result.removedIds)
console.log('待处理修改', result.updatedIds)
// 此处只读取变化,不声称文件已上传或服务端已同步。
},
fail(error) {
if (version === changesRequestVersion) console.log('增量读取失败,保留旧游标', error.errCode, error.errMsg)
},
complete(result) {
if (version === changesRequestVersion) console.log('本次增量查询结束', result)
}
})
}
export function confirmGalleryChangesApplied(nextCursor, fullSyncCompleted = false) {
// 仅在应用自己的同步/更新流程真实成功后调用。
// fullSyncCompleted 必须来自真实全量结果,不能为消除提示固定填写 true。
if (pendingChanges == null || pendingChanges.nextCursor !== nextCursor) return
if ((pendingChanges.isInitial || pendingChanges.resetRequired) && !fullSyncCompleted) return
uni.setStorageSync(cursorStorageKey, nextCursor)
pendingChanges = null
}
export function removeStoredGalleryCursor() {
const stored = uni.getStorageSync(cursorStorageKey)
if (typeof stored !== 'string' || stored === '') return
GalleryPro.clearGalleryChangeCursor({
cursor: stored,
success(result) {
console.log('清理结果', result.success, result.cursor, result.removed, result.message)
// 不移除并发业务刚写入的新游标;removed=false 可表示原游标已不存在。
if (result.success && uni.getStorageSync(cursorStorageKey) === stored) {
uni.removeStorageSync(cursorStorageKey)
}
},
fail(error) {
console.log('清理游标失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('游标清理动作结束', result)
}
})
}
resetReason |
业务处理 |
none |
正常初始基线或增量,结合 isInitial 判断 |
cursorNotFound / cursorExpired |
原基线不存在或已过期,重新全量处理 |
permissionChanged / filterChanged |
授权或媒体范围变化,按新范围重新全量处理 |
tooManyChanges |
变化数超过上限,重新全量处理 |
snapshotChangedDuringScan |
扫描期间图库变化,重新读取并建立一致业务基线 |
判断平台能力并按缓存年龄清理
用途:显示适用入口、清理较旧缓存;前置:清理前确认页面和上传任务不再依赖这些缓存路径。宿主:uni-app;触发:调用 inspectGalleryCapabilities(),需要清理时单独调用 clearOldGalleryThumbnails()。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function inspectGalleryCapabilities() {
const result = GalleryPro.getGalleryCapabilities()
console.log('平台与说明', result.platform, result.message)
console.log('列表能力', result.images, result.videos, result.mixed)
console.log('查询能力', result.pagination, result.timeRange, result.sourceClassification)
console.log('文件能力', result.thumbnails, result.exportTempFile, result.upload, result.saveMedia)
console.log('元数据能力', result.metadata, result.exif, result.locationMetadata)
console.log('变化能力', result.changeObserver, result.incrementalChanges, result.persistentChangeCursor)
console.log('原生安装包提示', result.customBaseRecommended)
// 能力为 true 不替代权限检查;HarmonyOS 的 false 也可能只是尚未授权。
// 保留原生平台的授权入口,授权后再次读取能力。
return result
}
export function clearOldGalleryThumbnails() {
GalleryPro.clearGalleryCache({
cacheType: 'thumbnail',
// 缓存年龄,单位毫秒;这里清理至少已存放 7 天的缩略图,不传时间戳。
olderThanMs: 7 * 24 * 60 * 60 * 1000,
success(result) {
console.log('清理结果', result.success, result.cacheType, result.message)
console.log('文件数与释放字节数', result.removedCount, result.releasedBytes)
},
fail(error) {
console.log('缓存清理失败', error.errCode, error.errMsg)
},
complete(result) {
console.log('缓存清理动作结束', result)
}
})
}
完整示例
下面两段各自构成可复制的最小页面:点击后申请授权、读取第一项、准备预览,并在页面退出时停止变化监听;不需要上传地址或虚构媒体 ID。更完整的操作页面分别为 uni_modules/lizhao-gallery-pro/example/uniapp/galleryPro.vue 和 uni_modules/lizhao-gallery-pro/example/uniappx/index.uvue。
uni-app:选项式页面
前置:App 安装包已包含本插件及所需权限;宿主:uni-app Vue2/Vue3。触发:点击按钮;清理:onUnload 先使请求失效,再停止本页监听,迟到的注册结果只清理自己的 ID。
<template>
<view>
<button :disabled="busy" @click="loadMedia">读取并预览第一项</button>
<text>{{ message }}</text>
<image v-if="previewPath !== '' && mediaType === 'image'"
:src="previewPath" mode="aspectFit" />
<video v-if="previewPath !== '' && mediaType === 'video'"
:src="previewPath" :poster="posterPath" controls />
</view>
</template>
<script>
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export default {
data() {
return {
alive: false, busy: false, requestVersion: 0, observerId: '',
previewPath: '', posterPath: '', mediaType: 'image', message: ''
}
},
onLoad() {
this.alive = true
},
onUnload() {
this.alive = false
this.requestVersion += 1
const id = this.observerId
this.observerId = ''
if (id !== '') this.stopOwnedObserver(id)
},
methods: {
isCurrent(version) {
return this.alive && this.requestVersion === version
},
stopOwnedObserver(id) {
GalleryPro.stopGalleryChangeObserver({
observerId: id,
fail: error => console.log('停止监听失败', id, error.errCode, error.errMsg),
complete: result => console.log('停止动作结束', result)
})
},
watchGallery(version) {
if (!GalleryPro.getGalleryCapabilities().changeObserver) return
GalleryPro.startGalleryChangeObserver({
mediaType: 'all',
debounceMs: 300,
includeChanges: false,
change: event => {
if (this.isCurrent(version)) this.message = '相册已变化,可再次读取:' + event.message
},
success: result => {
if (!this.isCurrent(version)) {
this.stopOwnedObserver(result.observerId)
return
}
this.observerId = result.observerId
},
fail: error => console.log('监听注册失败', error.errCode, error.errMsg),
complete: result => console.log('注册动作结束', result)
})
},
readAndPrepare(version) {
GalleryPro.getGalleryMedia({
mediaType: 'all',
pageSize: 1,
thumbnailMode: 'none',
success: result => {
if (!this.isCurrent(version)) return
if (result.items.length === 0) {
this.message = '当前授权范围内没有媒体'
this.busy = false
return
}
GalleryPro.prepareGalleryMedia({
id: result.items[0].id,
includePoster: true,
posterWidth: 320,
posterHeight: 320,
success: prepared => {
if (!this.isCurrent(version)) return
this.previewPath = prepared.renderPath
this.posterPath = prepared.posterPath
this.mediaType = prepared.mediaType
this.message = prepared.message
},
fail: error => {
if (this.isCurrent(version)) this.message = error.errMsg
},
complete: result => {
// 外层列表的 complete 可能早于文件准备结束,忙碌状态在这里释放。
if (this.isCurrent(version)) this.busy = false
console.log('准备动作结束', result)
}
})
},
fail: error => {
if (!this.isCurrent(version)) return
this.message = error.errMsg
this.busy = false
},
complete: result => console.log('列表动作结束', result)
})
},
loadMedia() {
if (this.busy || !this.alive) return
const capabilities = GalleryPro.getGalleryCapabilities()
const nativePlatform = capabilities.platform === 'app-android' ||
capabilities.platform === 'app-ios' || capabilities.platform === 'app-harmony'
if (!nativePlatform) {
this.message = capabilities.message
return
}
const version = ++this.requestVersion
const oldObserverId = this.observerId
this.observerId = ''
if (oldObserverId !== '') this.stopOwnedObserver(oldObserverId)
this.busy = true
this.previewPath = ''
this.posterPath = ''
this.message = '正在读取'
GalleryPro.requestGalleryPermission({
mediaType: 'all',
success: permission => {
if (!this.isCurrent(version)) return
if (!permission.granted) {
this.message = permission.message
this.busy = false
return
}
const authorizedCapabilities = GalleryPro.getGalleryCapabilities()
if (!authorizedCapabilities.mixed || !authorizedCapabilities.exportTempFile) {
this.message = authorizedCapabilities.message
this.busy = false
return
}
this.watchGallery(version)
this.readAndPrepare(version)
},
fail: error => {
if (!this.isCurrent(version)) return
this.message = error.errMsg
this.busy = false
},
complete: result => console.log('权限动作结束', result)
})
}
}
}
</script>
uni-app x:组合式 UTS 页面
前置、触发和退出顺序与上例一致;宿主:uni-app x。类型与方法均从插件根入口导入,函数先声明后调用;此处没有上传、保存或清空缓存等额外操作。
<template>
<view>
<button :disabled="busy" @click="loadMedia">读取并预览第一项</button>
<text>{{ message }}</text>
<image v-if="previewPath !== '' && mediaType === 'image'"
:src="previewPath" mode="aspectFit" />
<video v-if="previewPath !== '' && mediaType === 'video'"
:src="previewPath" :poster="posterPath" controls />
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import {
getGalleryCapabilities, requestGalleryPermission, getGalleryMedia,
prepareGalleryMedia, startGalleryChangeObserver, stopGalleryChangeObserver,
type GalleryPermissionResult, type GalleryQueryResult, type GalleryPrepareResult,
type GalleryChangeEvent, type GalleryChangeObserverStartResult, type GalleryFail
} from '@/uni_modules/lizhao-gallery-pro'
const busy = ref(false)
const previewPath = ref('')
const posterPath = ref('')
const mediaType = ref('image')
const message = ref('')
let alive = false
let requestVersion = 0
let observerId = ''
function isCurrent(version: number): boolean {
return alive && requestVersion == version
}
function stopOwnedObserver(id: string): void {
stopGalleryChangeObserver({
observerId: id,
fail: (error: GalleryFail): void => {
console.log('停止监听失败', id, error.errCode, error.errMsg)
},
complete: (result: any): void => { console.log('停止动作结束', result) }
})
}
function watchGallery(version: number): void {
if (!getGalleryCapabilities().changeObserver) return
startGalleryChangeObserver({
mediaType: 'all',
debounceMs: 300,
includeChanges: false,
change: (event: GalleryChangeEvent): void => {
if (isCurrent(version)) message.value = '相册已变化,可再次读取:' + event.message
},
success: (result: GalleryChangeObserverStartResult): void => {
if (!isCurrent(version)) {
stopOwnedObserver(result.observerId)
return
}
observerId = result.observerId
},
fail: (error: GalleryFail): void => {
console.log('监听注册失败', error.errCode, error.errMsg)
},
complete: (result: any): void => { console.log('注册动作结束', result) }
})
}
function readAndPrepare(version: number): void {
getGalleryMedia({
mediaType: 'all',
pageSize: 1,
thumbnailMode: 'none',
success: (result: GalleryQueryResult): void => {
if (!isCurrent(version)) return
if (result.items.length == 0) {
message.value = '当前授权范围内没有媒体'
busy.value = false
return
}
prepareGalleryMedia({
id: result.items[0].id,
includePoster: true,
posterWidth: 320,
posterHeight: 320,
success: (prepared: GalleryPrepareResult): void => {
if (!isCurrent(version)) return
previewPath.value = prepared.renderPath
posterPath.value = prepared.posterPath
mediaType.value = prepared.mediaType
message.value = prepared.message
},
fail: (error: GalleryFail): void => {
if (isCurrent(version)) message.value = error.errMsg
},
complete: (result: any): void => {
if (isCurrent(version)) busy.value = false
console.log('准备动作结束', result)
}
})
},
fail: (error: GalleryFail): void => {
if (!isCurrent(version)) return
message.value = error.errMsg
busy.value = false
},
complete: (result: any): void => { console.log('列表动作结束', result) }
})
}
function loadMedia(): void {
if (busy.value || !alive) return
const capabilities = getGalleryCapabilities()
const nativePlatform = capabilities.platform == 'app-android' ||
capabilities.platform == 'app-ios' || capabilities.platform == 'app-harmony'
if (!nativePlatform) {
message.value = capabilities.message
return
}
const version = ++requestVersion
const oldObserverId = observerId
observerId = ''
if (oldObserverId != '') stopOwnedObserver(oldObserverId)
busy.value = true
previewPath.value = ''
posterPath.value = ''
message.value = '正在读取'
requestGalleryPermission({
mediaType: 'all',
success: (permission: GalleryPermissionResult): void => {
if (!isCurrent(version)) return
if (!permission.granted) {
message.value = permission.message
busy.value = false
return
}
const authorizedCapabilities = getGalleryCapabilities()
if (!authorizedCapabilities.mixed || !authorizedCapabilities.exportTempFile) {
message.value = authorizedCapabilities.message
busy.value = false
return
}
watchGallery(version)
readAndPrepare(version)
},
fail: (error: GalleryFail): void => {
if (!isCurrent(version)) return
message.value = error.errMsg
busy.value = false
},
complete: (result: any): void => { console.log('权限动作结束', result) }
})
}
onLoad((): void => { alive = true })
onUnload((): void => {
alive = false
requestVersion += 1
const id = observerId
observerId = ''
if (id != '') stopOwnedObserver(id)
})
</script>
模块化示例
媒体:只读取视频列表
用途:为视频素材页读取一页数据;前置:视频读取授权。宿主:uni-app;触发:视频页签首次加载调用 readGalleryVideoPage(),后续分页仍使用结果中的令牌。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readGalleryVideoPage() {
GalleryPro.getGalleryVideos({
mediaType: 'video', // 专用视频方法会固定为 video,不受其他 mediaType 值改变。
pageSize: 30,
pageToken: '',
thumbnailMode: 'sync',
thumbnailWidth: 320,
thumbnailHeight: 180,
success(result) {
result.items.forEach(item => console.log('视频', item.id, item.durationMs, item.thumbnailPath))
console.log('分页', result.hasMore, result.nextPageToken)
},
fail(error) { console.log('视频读取失败', error.errCode, error.errMsg) },
complete(result) { console.log('视频列表动作结束', result) }
})
}
相册:读取截图文件夹并等待封面
用途:一次取得截图相册和封面;前置:读取授权,页面可以接受等待封面。宿主:uni-app;触发:调用 readScreenshotAlbums(),首屏需要更快出现文件夹时用前文快速模式。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readScreenshotAlbums() {
GalleryPro.getGalleryAlbums({
mediaType: 'image',
sourceType: 'screenshot',
includeCoverThumbnail: true, // 显式等待封面处理,可能慢于默认 false。
success(result) {
result.albums.forEach(album => console.log(album.albumName, album.count, album.coverThumbnailPath))
},
fail(error) { console.log('截图相册读取失败', error.errCode, error.errMsg) },
complete(result) { console.log('截图相册动作结束', result) }
})
}
处理:重新读取视频参数
用途:读取视频参数而不读取 EXIF 或位置;前置:videoId 来自视频列表。宿主:uni-app;触发:打开视频详情后调用 readFreshVideoMetadata(videoId)。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function readFreshVideoMetadata(videoId) {
GalleryPro.getGalleryMetadata({
ids: [videoId],
includeExif: false,
includeLocation: false,
useCache: false, // 需要重新读取时关闭非敏感缓存复用。
success(result) {
result.items.forEach(item => console.log(item.success, item.videoCodec, item.videoBitrate, item.videoFrameRate))
},
fail(error) { console.log('视频参数读取失败', error.errCode, error.errMsg) },
complete(result) { console.log('视频参数动作结束', result) }
})
}
输出:只准备可用文件,再保存到默认相册
用途:明确要求保存一份副本时使用;前置:id 来自列表且用户已确认保存。宿主:uni-app;触发:调用 saveSelectedMediaCopy(id),这里实际保存准备结果中的本地文件,不使用占位路径。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function saveSelectedMediaCopy(id) {
GalleryPro.prepareGalleryMedia({
id: id,
includePoster: false, // 不生成页面不需要的 poster。
success(prepared) {
GalleryPro.saveMediaToGallery({
paths: [prepared.uploadPath],
albumName: '',
duplicatePolicy: 'allow', // 明确保留本次副本,不执行可见重复项跳过。
success(result) { console.log('保存副本结果', result.success, result.items) },
fail(error) { console.log('保存副本失败', error.errCode, error.errMsg) },
complete(result) { console.log('保存副本动作结束', result) }
})
},
fail(error) { console.log('准备副本失败', error.errCode, error.errMsg) },
complete(result) { console.log('副本准备动作结束', result) }
})
}
管理:清理全部非敏感元数据缓存
用途:让下次详情页重新读取非敏感字段;前置:没有依赖本次缓存清理结果的并发任务。宿主:uni-app;触发:调用 clearGalleryMetadataCache(),不会删除系统相册原文件。
import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'
export function clearGalleryMetadataCache() {
GalleryPro.clearGalleryCache({
cacheType: 'metadata',
olderThanMs: 0, // 默认 0;清理该类型全部缓存,不按年龄筛选。
success(result) { console.log('清理文件数与字节数', result.removedCount, result.releasedBytes) },
fail(error) { console.log('元数据缓存清理失败', error.errCode, error.errMsg) },
complete(result) { console.log('元数据缓存清理动作结束', result) }
})
}
API 用途速查
| 模块 |
适用业务 |
常用方法 |
使用结果 |
| 权限 |
首次访问、返回页面检查授权 |
checkGalleryPermission、requestGalleryPermission |
权限状态 |
| 媒体 |
图片、视频、混合列表 |
getGalleryMedia、getGalleryImages、getGalleryVideos |
分页媒体 |
| 缩略图与单项 |
列表小图、详情入口 |
getGalleryThumbnails、getMediaById |
缩略图、单媒体 |
| 文件准备与导出 |
图片/视频预览、poster、编辑和上传 |
prepareGalleryMedia、exportMediaToTempFile |
可用路径 |
| 上传 |
导出校验、发送至自己的接口 |
uploadGalleryMedia |
进度与逐项响应 |
| 保存 |
本地媒体归档到相册 |
saveMediaToGallery |
保存与跳过明细 |
| 相册 |
文件夹、封面和来源分类 |
getGalleryAlbums |
相册列表 |
| 处理 |
EXIF、视频参数和可选位置 |
getGalleryMetadata |
逐项元数据 |
| 监听与增量 |
页面刷新、备份变化查询 |
startGalleryChangeObserver、stopGalleryChangeObserver、getGalleryChanges、clearGalleryChangeCursor |
事件、持久游标 |
| 管理 |
平台入口和缓存空间 |
getGalleryCapabilities、clearGalleryCache |
能力与清理结果 |
公共回调与结果判定
下列公共参数适用于除同步 getGalleryCapabilities() 以外的异步方法;回调的具体结果类型见各组输出表。完整传入和读取方式可见基础示例及各功能示例。
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
success |
function |
否 |
动作正常完成后接收该方法的结果 |
无 |
按结果判断授权、整体及单项状态 |
fail |
(error: GalleryFail) => void |
否 |
参数、权限、平台或任务失败 |
无 |
读取 errSubject / errCode / errMsg |
complete |
(result: any) => void |
否 |
本次动作成功或失败后结束 |
无 |
渐进列表在当前页缩略图处理结束后触发 |
| 接口或情形 |
应读取的结果 |
处理边界 |
| 权限动作 |
granted / status / limited / shouldOpenSettings |
success 不等于已获得完整授权 |
| 上传批次 |
successCount / failCount / items |
检查逐项 HTTP 状态及服务端业务响应 |
| 保存批次 |
successCount / failCount / skippedCount / items |
至少一项保存或跳过成功可进入 success |
| 元数据批次 |
successCount / failCount / items |
批次回调正常返回也可能存在全部单项失败 |
| 渐进缩略图 |
thumbnailProgress.items / done |
处理结束不代表每一项都有图片 |
| 监听注册 |
注册 success 返回 observerId |
注册 complete 不代表监听生命周期结束 |
| 取消或系统中断 |
fail.errCode |
没有公开的批量任务取消 API;请求版本只能阻止旧结果更新页面 |
输入参数
以下各表均同时支持上方公共回调;同名参数的示例链接指向实际赋值或调用代码。
权限:GalleryPermissionOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
mediaType |
GalleryMediaType |
否 |
检查或申请的媒体范围 |
all |
image / video / all |
preferFullAccess |
boolean |
否 |
兼容保留,当前不改变系统授权范围 |
false |
true / false |
列表:GalleryQueryOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
mediaType |
GalleryMediaType |
否 |
通用方法的媒体范围;图片/视频专用方法固定各自类型 |
all |
image / video / all |
pageSize |
number |
否 |
每页条数,使用分页读取大图库 |
30 |
整数 1~200 |
pageToken |
string |
否 |
原样使用前页 nextPageToken |
空字符串 |
同一查询条件下的令牌 |
startTime |
number |
否 |
开始时间,毫秒时间戳;0 不限制 |
0 |
非负时间戳 |
endTime |
number |
否 |
结束时间,毫秒时间戳;0 不限制 |
0 |
非负时间戳 |
albumId |
string |
否 |
来自相册结果的 ID |
空字符串 |
当前平台真实相册 ID |
sourceType |
GallerySourceType |
否 |
来源过滤,仍受系统分类准确性影响 |
all |
camera / screenshot / wechat / qq / download / other / all |
sortOrder |
GallerySortOrder |
否 |
时间排序方向 |
desc |
desc / asc |
includeHidden |
boolean |
否 |
隐藏媒体偏好;不突破授权和系统可见范围 |
false |
true / false |
includeThumbnail |
boolean |
否 |
未传模式时,true 使用同步缩略图 |
false |
true / false |
thumbnailMode |
GalleryThumbnailMode |
否 |
显式设置时优先于 includeThumbnail |
按兼容开关选择 sync / none |
none / sync / progressive |
thumbnailBatchSize |
number |
否 |
当前页渐进处理的每批数量 |
4 |
整数 1~20 |
thumbnailWidth |
number |
否 |
请求缩略图宽度,像素 |
160 |
建议跨端使用 64~1200 |
thumbnailHeight |
number |
否 |
请求缩略图高度,像素 |
160 |
建议跨端使用 64~1200 |
thumbnailProgress |
(event: GalleryThumbnailProgress) => void |
否 |
仅渐进模式返回批次结果 |
无 |
读取结果后按 id 更新当前列表 |
缩略图:GalleryThumbnailOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
ids |
Array<string> |
是 |
当前授权范围内的媒体 ID |
无 |
非空 ID 数组 |
width |
number |
否 |
请求宽度,像素 |
160 |
建议跨端使用 64~1200 |
height |
number |
否 |
请求高度,像素 |
160 |
建议跨端使用 64~1200 |
quality |
number |
否 |
仅 HarmonyOS 使用;Android/iOS 不读取此参数 |
HarmonyOS 85;其他端固定编码质量 |
HarmonyOS 1~100 |
单媒体:GalleryMediaByIdOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
id |
string |
是 |
列表返回的稳定媒体 ID |
无 |
当前平台真实媒体 ID |
includeThumbnail |
boolean |
否 |
是否附带占位缩略图 |
false |
true / false |
导出:GalleryExportOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
id |
string |
是 |
列表或单媒体查询返回的 ID |
无 |
当前平台真实媒体 ID |
exportType |
GalleryExportType |
否 |
表达本次用途,不为三种用途分别复制文件 |
render |
render / upload / original |
fileName |
string |
否 |
自定义文件名,不是输出目录 |
原媒体名或平台生成名 |
合法文件名,平台会处理不安全字符 |
文件准备:GalleryPrepareOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
id |
string |
是 |
列表返回的媒体 ID |
无 |
当前平台真实媒体 ID |
includePoster |
boolean |
否 |
是否额外生成 JPEG poster |
true |
true / false |
posterWidth |
number |
否 |
poster 请求宽度,像素 |
320 |
建议跨端使用 64~1200 |
posterHeight |
number |
否 |
poster 请求高度,像素 |
320 |
建议跨端使用 64~1200 |
上传:GalleryUploadOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
ids |
Array<string> |
是 |
处理结果按输入 ID 顺序返回 |
无 |
非空 ID 数组 |
url |
string |
实际上传时是 |
自己的业务接口地址 |
无 |
dryRun=true 可不传 |
dryRun |
boolean |
否 |
只导出并检查路径,不发起网络请求 |
false |
true / false |
name |
string |
否 |
文件表单字段名 |
file |
与业务服务器约定的字段名 |
formData |
UTSJSONObject |
否 |
附加表单数据 |
无 |
业务接口接受的字段 |
concurrency |
number |
否 |
同时处理的上传数量 |
1 |
整数 1~4 |
retryCount |
number |
否 |
单文件失败后的额外重试次数 |
0 |
整数 0~5 |
timeoutMs |
number |
否 |
单文件网络请求超时,毫秒;不是整个批次期限 |
120000 |
正数;跨端建议不少于 1000 |
progress |
(event: GalleryUploadProgress) => void |
否 |
上传阶段及处理进度 |
无 |
不是统一的逐字节网络进度 |
保存:GallerySaveOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
paths |
Array<string> |
是 |
应用可访问的本地文件,结果保持输入顺序 |
无 |
绝对路径或 file:// 路径 |
albumName |
string |
否 |
指定相册名称 |
系统默认相册 |
空字符串或自己的相册名 |
duplicatePolicy |
GalleryDuplicatePolicy |
否 |
保存全部输入或跳过可确认的可见重复项 |
allow |
allow / skip |
progress |
(event: GallerySaveProgress) => void |
否 |
每处理完一项返回当前汇总 |
无 |
读取当前输入路径和数量 |
相册分组:GalleryAlbumsOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
mediaType |
GalleryMediaType |
否 |
相册统计的媒体范围 |
all |
image / video / all |
sourceType |
GallerySourceType |
否 |
相册统计的来源范围 |
all |
camera / screenshot / wechat / qq / download / other / all |
includeCoverThumbnail |
boolean |
否 |
是否在返回相册前等待封面处理 |
false |
true / false;true 示例见截图相册 |
元数据:GalleryMetadataOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
ids |
Array<string> |
是 |
不重复的真实媒体 ID,结果保持输入顺序 |
无 |
1~100 个 |
includeExif |
boolean |
否 |
是否读取图片 EXIF |
true |
true / false |
includeLocation |
boolean |
否 |
是否显式读取敏感位置 |
false |
true / false |
useCache |
boolean |
否 |
是否复用非敏感缓存 |
true |
true / false |
progress |
(event: GalleryMetadataProgress) => void |
否 |
每处理完一个媒体返回数量 |
无 |
不包含坐标 |
变化监听:GalleryChangeObserverOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
mediaType |
GalleryMediaType |
否 |
页面需要刷新的业务范围 |
all |
image / video / all |
debounceMs |
number |
否 |
合并内容变化通知的防抖时间,毫秒 |
300 |
0~5000 |
includeChanges |
boolean |
否 |
是否尝试返回精确 ID 变化 |
false |
true / false |
maxChanges |
number |
否 |
精确变化数上限,超限需重建 |
2000 |
整数 1~10000 |
change |
(event: GalleryChangeEvent) => void |
是 |
注册后持续接收变化事件 |
无 |
根据详情可用性或重建标记刷新 |
停止监听:GalleryChangeObserverStopOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
observerId |
string |
是 |
启动成功返回的监听器 ID |
无 |
不复用其他请求的 ID |
增量查询:GalleryChangesOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
cursor |
string |
否 |
已确认业务处理完成后保存的游标 |
空字符串 |
为空建立基线,否则使用原始游标 |
mediaType |
GalleryMediaType |
否 |
增量查询媒体范围 |
all |
image / video / all |
maxChanges |
number |
否 |
单次允许返回的最大变化数 |
2000 |
整数 1~10000 |
游标清理:GalleryClearChangeCursorOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
cursor |
string |
是 |
需要清理的持久游标 |
无 |
原样保存的游标字符串 |
缓存清理:GalleryClearCacheOptions
| 参数 |
类型 |
必填 |
说明 |
默认值 |
可选参数 |
cacheType |
GalleryCacheType |
否 |
清理插件内对应类型的缓存 |
all |
thumbnail / export / changeCursor / metadata / all |
olderThanMs |
number |
否 |
缓存年龄阈值,毫秒;不是绝对时间戳 |
0 |
<=0 清理所选类型全部缓存;>0 按年龄清理 |
返回字段与事件
权限结果:GalleryPermissionResult
读取示例:基础授权。
| 字段 |
类型 |
说明 |
granted |
boolean |
是否获得可读取权限,有限授权也可能为 true |
status |
GalleryPermissionStatus |
unknown / authorized / limited / denied / restricted / notDetermined / unsupported |
mediaType |
GalleryMediaType |
本次检查或申请的范围 |
limited |
boolean |
是否仅可访问用户选定的部分媒体 |
shouldOpenSettings |
boolean |
是否建议引导到系统设置 |
platform / message |
string |
运行平台和中文说明 |
列表与单媒体:GalleryQueryResult / GalleryMediaByIdResult
读取示例:基础结果、逐项字段、按 ID 查询。
| 字段 |
类型 |
说明 |
GalleryQueryResult.success |
boolean |
本次查询状态 |
platform / message |
string |
运行平台和中文说明 |
mediaType |
GalleryMediaType |
本次查询媒体范围 |
total |
number |
当前条件下可见媒体总数 |
items |
Array<GalleryMediaItem> |
当前页数据 |
hasMore |
boolean |
是否还有下一页 |
nextPageToken |
string |
下一页令牌,不自行修改 |
GalleryMediaByIdResult.success |
boolean |
单媒体读取状态 |
GalleryMediaByIdResult.item |
GalleryMediaItem |
当前可见的媒体 |
GalleryMediaByIdResult.message |
string |
中文说明 |
| 字段 |
类型 |
说明 |
GalleryMediaItem.id |
string |
当前平台稳定媒体 ID;授权撤回或删除后可能不可访问 |
mediaType |
GalleryMediaType |
实际图片或视频类型 |
fileName / mimeType |
string |
文件名与 MIME 类型 |
width / height |
number |
像素宽高 |
durationMs |
number |
视频时长,毫秒;图片为 0 |
size |
number |
文件大小,字节 |
createTime / modifiedTime |
number |
创建和修改时间,毫秒时间戳 |
albumId / albumName |
string |
相册 ID 和名称 |
sourceType |
GallerySourceType |
来源分类 |
sourceLabel |
string |
中文来源说明 |
originalPath |
string |
原始路径或平台资产标识,不保证直接可用 |
renderPath / uploadPath |
string |
列表阶段的路径,不保证已完成可用文件准备 |
thumbnailPath |
string |
列表小图路径,可为空 |
requiresExport |
boolean |
是否需先导出再稳定使用 |
缩略图:GalleryThumbnailResult / GalleryThumbnailProgress / GalleryThumbnailItem
读取示例:渐进结果、独立缩略图。
| 字段 |
类型 |
说明 |
GalleryThumbnailResult.success |
boolean |
本次缩略图任务状态 |
GalleryThumbnailResult.items |
Array<GalleryThumbnailItem> |
该任务的缩略图结果 |
GalleryThumbnailResult.message |
string |
中文说明 |
GalleryThumbnailProgress.items |
Array<GalleryThumbnailItem> |
当前渐进批次结果 |
current / total |
number |
当前页已处理数量与待处理总数 |
done |
boolean |
当前页处理是否结束 |
GalleryThumbnailProgress.message |
string |
进度说明 |
GalleryThumbnailItem.id |
string |
原媒体 ID,用于关联当前页面项 |
thumbnailPath |
string |
JPEG 缩略图路径,失败项可为空 |
width / height |
number |
该结果记录的缩略图尺寸 |
GalleryThumbnailItem.message |
string |
单项说明 |
文件准备与导出:GalleryPrepareResult / GalleryExportResult
读取示例:准备结果、导出结果。
| 字段 |
类型 |
说明 |
success |
boolean |
本次准备或导出状态 |
id |
string |
原媒体 ID |
GalleryPrepareResult.mediaType |
GalleryMediaType |
图片或视频类型 |
renderPath |
string |
准备/导出后用于页面 image/video 的路径 |
uploadPath |
string |
准备/导出后用于上传的本地路径 |
GalleryPrepareResult.posterPath |
string |
JPEG poster;关闭或未能生成时为空 |
size |
number |
导出文件大小,字节 |
cacheHit |
boolean |
是否直接复用了同一媒体的有效导出缓存 |
message |
string |
中文说明 |
上传:GalleryUploadProgress / GalleryUploadResult / GalleryUploadItemResult
读取示例:上传与路径校验。
| 字段 |
类型 |
说明 |
GalleryUploadProgress.stage |
GalleryUploadStage |
export / upload / dryRun / complete |
current / total |
number |
当前处理序号(从 1 起)与总数 |
progress |
number |
进度百分比,不作为统一的逐字节网络进度 |
GalleryUploadProgress.message |
string |
阶段说明 |
GalleryUploadResult.success |
boolean |
批次整体状态 |
successCount / failCount |
number |
成功与失败数量 |
items |
Array<GalleryUploadItemResult> |
按输入 ID 顺序返回的结果 |
GalleryUploadResult.message |
string |
批次说明 |
GalleryUploadItemResult.index |
number |
输入 ID 下标,从 0 起 |
id |
string |
原媒体 ID |
GalleryUploadItemResult.success |
boolean |
单项处理状态 |
statusCode |
number |
HTTP 状态码;未发网络请求时不代表服务器成功 |
responseText |
string |
服务端原始响应文本,业务自行判断 |
renderPath? / uploadPath? |
string |
导出成功后可能返回的路径 |
size? |
number |
导出文件字节数 |
GalleryUploadItemResult.message |
string |
单项说明;该类型没有公开 errCode 字段 |
保存:GallerySaveProgress / GallerySaveResult / GallerySaveItemResult
读取示例:批量保存。
| 字段 |
类型 |
说明 |
GallerySaveProgress.current / total |
number |
已处理数量(从 1 起)与输入总数 |
progress |
number |
总体处理百分比 |
GallerySaveProgress.successCount / failCount |
number |
当前已成功或跳过、已失败数量 |
currentPath |
string |
当前输入的原始路径 |
GallerySaveProgress.message |
string |
当前进度说明 |
GallerySaveResult.success |
boolean |
是否全部项目保存或跳过成功 |
GallerySaveResult.successCount / failCount / skippedCount |
number |
成功或跳过、失败、判重跳过数量 |
items |
Array<GallerySaveItemResult> |
按输入路径顺序返回 |
GallerySaveResult.message |
string |
汇总说明 |
GallerySaveItemResult.index |
number |
输入路径下标,从 0 起 |
sourcePath |
string |
原始输入路径 |
mediaType |
GalleryMediaType |
识别出的媒体类型 |
GallerySaveItemResult.success / skipped |
boolean |
是否保存或跳过成功、是否因重复跳过 |
mediaId / albumName |
string |
新建或匹配媒体 ID、实际相册名称 |
errCode? |
GalleryErrorCode |
单项失败码 |
GallerySaveItemResult.message |
string |
单项中文说明 |
相册:GalleryAlbumsResult / GalleryAlbumItem
读取示例:相册结果及补封面。
| 字段 |
类型 |
说明 |
GalleryAlbumsResult.success |
boolean |
相册查询状态 |
albums |
Array<GalleryAlbumItem> |
相册列表 |
GalleryAlbumsResult.message |
string |
中文说明 |
GalleryAlbumItem.albumId / albumName |
string |
相册 ID 和名称 |
sourceType |
GallerySourceType |
来源分类 |
count / imageCount / videoCount |
number |
媒体总数、图片数、视频数 |
coverThumbnailPath |
string |
快速模式默认空字符串,不表示相册读取失败 |
latestMediaId |
string |
最新媒体 ID,可用于按需补封面 |
latestMediaType |
GalleryMediaType |
最新媒体类型 |
latestFileName |
string |
最新媒体文件名 |
latestCreateTime |
number |
最新媒体创建时间,毫秒时间戳 |
元数据:GalleryMetadataProgress / GalleryMetadataResult / GalleryMetadataItem / GalleryMediaLocation
读取示例:元数据与位置读取。
| 字段 |
类型 |
说明 |
GalleryMetadataProgress.current / total / successCount / failCount |
number |
已处理、总数、成功和失败数量 |
currentId |
string |
当前处理的媒体 ID |
GalleryMetadataResult.success |
boolean |
是否全部单项成功 |
GalleryMetadataResult.successCount / failCount |
number |
成功和失败数量 |
items |
Array<GalleryMetadataItem> |
按输入 ID 顺序返回的结果 |
GalleryMetadataResult.message |
string |
汇总说明 |
GalleryMetadataItem.id |
string |
原媒体 ID |
GalleryMetadataItem.success |
boolean |
单项是否读取成功 |
mediaType |
GalleryMediaType |
媒体类型 |
width / height |
number |
像素宽高 |
durationMs |
number |
视频时长,毫秒;图片为 0 |
orientation |
number |
EXIF 方向 1~8,未知为 0 |
captureTime |
number |
拍摄时间,毫秒时间戳;未知为 0 |
cameraMake / cameraModel / lensModel |
string |
相机厂商、型号和镜头型号 |
iso? / aperture? |
number |
ISO、光圈值,未知时省略 |
exposureTime? |
number |
曝光时间,秒 |
focalLength? / focalLength35mm? |
number |
焦距和 35 毫米等效焦距,毫米 |
videoCodec |
string |
视频编码名称 |
videoBitrate? |
number |
视频码率,bit/s |
videoFrameRate? |
number |
视频帧率 |
locationAvailable |
boolean |
本次是否能读取位置;false 不证明原文件没有 GPS |
location? |
GalleryMediaLocation |
仅显式开启位置读取时可能出现 |
fromCache |
boolean |
非敏感字段是否来自缓存 |
errCode? |
GalleryErrorCode |
单项诊断码;9070032 可与读取成功并存 |
GalleryMetadataItem.message |
string |
单项说明 |
GalleryMediaLocation.latitude / longitude |
number |
纬度和经度;按业务隐私要求使用 |
altitude? |
number |
海拔,米,媒体未提供时省略 |
监听:GalleryChangeObserverStartResult / GalleryChangeObserverStopResult / GalleryChangeEvent
读取示例:监听归属及清理。
| 字段 |
类型 |
说明 |
GalleryChangeObserverStartResult.observerId |
string |
新注册监听器的 ID |
platform / message |
string |
注册平台与中文说明 |
GalleryChangeObserverStopResult.observerId |
string |
本次停止的监听器 ID |
stopped |
boolean |
是否已停止 |
GalleryChangeObserverStopResult.message |
string |
停止说明 |
GalleryChangeEvent.observerId |
string |
触发事件的监听器 |
mediaType |
GalleryMediaType |
业务刷新范围,不代表变动媒体的精确类型 |
reason |
GalleryChangeReason |
contentChanged / appResume / permissionChanged |
changedAt / mergedCount |
number |
毫秒时间戳、防抖窗口合并通知数 |
permissionStatus? |
GalleryPermissionStatus |
权限变化事件可能携带的新状态 |
detailsAvailable? |
boolean |
是否可使用精确变化详情 |
addedIds? / removedIds? / updatedIds? |
Array<string> |
新增、删除和修改的 ID |
changeCount? |
number |
精确变化总数 |
cursor? / nextCursor? |
string |
本次详情计算的旧、新游标 |
resetRequired? |
boolean |
是否需全量重建 |
resetReason? |
GalleryChangeCursorResetReason |
重建原因,见增量原因表 |
GalleryChangeEvent.message |
string |
事件说明 |
增量与游标:GalleryChangesResult / GalleryClearChangeCursorResult
读取示例:查询、确认和清理游标。
| 字段 |
类型 |
说明 |
GalleryChangesResult.success |
boolean |
查询动作状态 |
isInitial |
boolean |
是否首次建立基线 |
resetRequired |
boolean |
是否必须重建全量业务基线 |
resetReason |
GalleryChangeCursorResetReason |
重建原因,见原因表 |
addedIds / removedIds / updatedIds |
Array<string> |
相对于旧游标的变化 ID |
changeCount / currentTotal |
number |
变化总数与本次可见总数 |
nextCursor |
string |
业务真正处理成功后保存的新游标 |
createdAt |
number |
游标创建时间,毫秒时间戳 |
GalleryChangesResult.message |
string |
中文说明 |
GalleryClearChangeCursorResult.success |
boolean |
清理动作状态 |
cursor |
string |
本次请求清理的游标 |
removed |
boolean |
是否实际移除了游标 |
GalleryClearChangeCursorResult.message |
string |
中文说明 |
缓存与能力:GalleryClearCacheResult / GalleryCapabilities
读取示例:能力分支与缓存清理。
| 字段 |
类型 |
说明 |
GalleryClearCacheResult.success |
boolean |
清理动作状态 |
cacheType |
GalleryCacheType |
本次清理类型 |
removedCount / releasedBytes |
number |
实际移除文件数和释放字节数 |
GalleryClearCacheResult.message |
string |
中文说明 |
GalleryCapabilities.platform / message |
string |
当前平台和能力说明 |
images / videos / mixed |
boolean |
图片、视频、混合列表 |
pagination / timeRange / sourceClassification |
boolean |
分页、时间范围和来源筛选 |
thumbnails / exportTempFile / upload / saveMedia |
boolean |
缩略图、文件导出、上传辅助和保存 |
metadata / exif / locationMetadata |
boolean |
标准化元数据、EXIF 和按开关读取位置 |
changeObserver / incrementalChanges / persistentChangeCursor |
boolean |
监听、精确增量和持久化游标 |
customBaseRecommended |
boolean |
当前平台是否提示使用包含原生插件的安装包 |
错误码说明
错误对象的 errSubject 为 lizhao-gallery-pro,读取方式见基础失败处理。批量结果还应检查单项状态;上传单项没有 errCode,使用 statusCode / responseText / message 判断。
| 错误码 |
含义 |
处理办法 |
| 9070001 |
平台不支持或 App 上下文不可用 |
先检查能力,在可用的 App 页面调用 |
| 9070002 |
相册读取权限不足 |
检查授权状态;HarmonyOS 同时检查 ACL、声明与用户授权 |
| 9070003 |
通用参数无效 |
检查媒体 ID、数组和参数类型 |
| 9070004 |
媒体不存在或已不可见 |
重新读取列表,不复用已删除或其他平台的 ID |
| 9070005 |
相册分组查询失败 |
保留原错误说明,确认授权和系统相册状态 |
| 9070006 |
缓存目录或写入失败 |
检查可用空间与应用缓存访问 |
| 9070007 |
媒体查询或平台查询失败 |
检查系统状态,允许业务重试 |
| 9070008 |
缩略图生成失败 |
保留媒体信息,用占位图并按需重试 |
| 9070009 |
文件导出失败 |
确认媒体可访问;iOS 云端原图可能需先下载 |
| 9070010 |
上传失败 |
检查地址、网络、超时与服务端响应 |
| 9070011 |
缓存清理失败 |
停止相关使用后重试,保留错误说明 |
| 9070012 |
系统中断或取消 |
结束当前业务忙碌状态,不显示为成功 |
| 9070013 |
文件不可用 |
重新准备文件,核对具体错误说明 |
| 9070014 |
内部异常 |
保留错误码和脱敏错误信息 |
| 9070015 |
变化监听注册失败 |
确认读取授权和运行平台后重试 |
| 9070016 |
监听器不存在或已停止 |
核对本页保存的 observerId |
| 9070017 |
监听参数无效 |
传入真实 change 回调和合法参数 |
| 9070018 |
保存参数无效 |
传入非空本地路径数组 |
| 9070019 |
本地源文件不存在或不可读 |
检查路径、文件寿命及访问权限 |
| 9070020 |
文件不是可识别的图片或视频 |
传入实际支持的本地媒体文件 |
| 9070021 |
相册写入或判重所需权限不足 |
检查保存权限;指定相册或判重可能还需读取权限 |
| 9070022 |
目标相册操作失败 |
检查相册名、平台权限和系统状态 |
| 9070023 |
媒体保存失败 |
检查文件、空间和逐项说明 |
| 9070024 |
当前平台不支持保存 |
根据能力隐藏该入口 |
| 9070025 |
增量查询或精确监听参数无效 |
核对游标、媒体范围和 maxChanges |
| 9070026 |
增量快照处理失败 |
保留旧游标,稍后重试 |
| 9070027 |
当前平台不支持增量变化 |
根据能力选择普通刷新方式 |
| 9070028 |
清理指定游标失败 |
保留游标值后重试 |
| 9070029 |
元数据参数无效 |
使用 1~100 个不重复的真实 ID |
| 9070030 |
单项元数据读取失败 |
查看单项结果,其他项目可继续使用 |
| 9070031 |
当前平台不支持元数据 |
根据能力隐藏相关入口 |
| 9070032 |
非敏感元数据缓存异常 |
仍可能读取原媒体成功,检查单项 success |
示例与平台接入
| 平台 |
使用范围 |
接入条件 |
| Android App |
图片、视频、相册、文件准备、保存、元数据与变化查询 |
插件声明最低 Android 6(API 23),同时满足宿主更高要求;媒体读取与写入权限满足系统要求 |
| iOS App |
PhotoKit 授权范围内的媒体操作 |
原生目标最低 iOS 12,实际同时满足宿主更高要求;有限照片权限只读取选定媒体 |
| HarmonyOS App |
系统授权范围内的完整相册操作 |
AGC 受限权限资格、Profile ACL、安装包声明和用户授权同时满足 |
| Web/H5 |
不提供系统相册整库操作 |
能力检查可用于隐藏入口,媒体操作明确返回不支持 |
| 微信/支付宝小程序 |
不提供系统相册整库操作 |
使用对应平台的媒体选择能力 |
| 接入项 |
使用要求 |
| 导入入口 |
仅从 @/uni_modules/lizhao-gallery-pro 导入方法和类型 |
| App 安装包 |
使用包含本插件原生实现、权限和依赖的自定义基座或正式安装包 |
| Android 授权 |
Android 13+ 按图片、视频授权;较早系统使用存储读取权限;Android 9 及以下保存需写入权限 |
| iOS 用途说明 |
按业务填写 NSPhotoLibraryUsageDescription 和 NSPhotoLibraryAddUsageDescription |
| HarmonyOS 完整相册 |
按实际读写能力申请 READ_IMAGEVIDEO / WRITE_IMAGEVIDEO 等权限资格与 ACL,并在应用中声明及请求;缺少 ACL 时反复弹运行时请求不能解决 |
| HarmonyOS 媒体位置 |
仅显式读取位置时处理 ohos.permission.MEDIA_LOCATION;此项不是相册 ACL 项 |
注意事项
| 情形 |
正确使用方式 |
| 权限检查成功但列表不可用 |
检查 granted / status;limited 只表示可访问部分媒体 |
| HarmonyOS 首次能力为 false |
原生平台仍保留授权入口,授权成功后重读能力;不能提前禁用申请权限按钮 |
| 成功返回空列表 |
检查当前可见范围及筛选条件,不把所有空结果都解释为未授权 |
| 列表路径不能直接预览 |
originalPath 可能为 content:// 等资产标识;大图、视频和上传先调用 prepareGalleryMedia 或 exportMediaToTempFile |
| 图片显示模糊 |
thumbnailPath 是另行缩放编码的 JPEG 小图,不能放大充当原图;详情用文件准备或导出的 renderPath |
| 图片显示被裁剪 |
缩略图尺寸按显示所需像素选择;完整画面用 aspectFit,填满区域用 aspectFill |
| 尺寸与质量跨端不同 |
请求尺寸可能被平台收敛,跨端可选 64~1200 像素;quality 仅 HarmonyOS 生效 |
| 相册有名称但封面为空 |
默认快速模式不等封面;通过 latestMediaId 补图,或显式开启 includeCoverThumbnail |
| 大图库首屏较慢 |
分页和渐进补图,不把 pageSize 当作一次读取全部图库的开关 |
| 原始媒体保护 |
列表和缩略图不会修改系统相册原文件;保存副本由应用显式调用保存 API |
| 位置隐私 |
元数据位置读取默认关闭且不进入插件缓存;导出媒体可能保留原有敏感元数据,上传前按业务隐私要求处理 |
| 云端媒体或权限撤回 |
媒体准备、导出、元数据仍可能单项失败,不依据旧 ID 推定文件持续可用 |
| 批量任务部分失败 |
逐项检查结果,不能只凭回调进入 success 宣称每个文件成功 |
| 重复策略 |
skip 只跳过当前可见且能确认的重复项,不作为跨设备去重合同 |
| 监听与页面退出 |
保存注册返回的 ID,卸载时停止;监听不能代替系统后台任务 |
| 增量游标 |
原样保存;初始、过期、授权变化或重建标记时先处理全量业务,成功后再推进 |
| 缓存与临时路径 |
正在预览、上传时不清理对应缓存;清理 export 后应重新准备文件 |
| 清理范围 |
changeCursor 会使对应增量基线失效;all 会清理插件各类缓存,不会删除系统相册原媒体 |
| 来源和隐藏媒体 |
来源依赖系统目录和元数据;includeHidden=true 不突破系统可见范围 |
微信:l-z-1-8-7-1512-5421(使用时去掉连字符)。
作者系列 UTS 插件
以下为作者已发布的 UTS 插件,可按能力方向查找。
| 插件 |
能力方向 |
插件市场 |
lizhao-alipay-kit |
支付宝授权登录、App 支付与脱敏诊断 |
查看插件 |
lizhao-app-keepalive |
应用保活、唤醒、自愈与报告 |
查看插件 |
lizhao-apple-iap |
苹果内购、交易恢复、订阅管理与服务端验签参考 |
查看插件 |
lizhao-apple-login |
苹果授权登录、凭证状态与撤销监听 |
查看插件 |
lizhao-bg-audio |
背景音频播放、队列、倍速与事件 |
查看插件 |
lizhao-ble |
BLE 扫描、连接、读写、通知与自动重连 |
查看插件 |
lizhao-call-kit |
电话、短信、通讯录原生能力 |
查看插件 |
lizhao-camera-pro |
原生相机、拍照录像、水印与媒体保存 |
查看插件 |
lizhao-cast-screen |
DLNA 投屏、AirPlay 路由入口 |
查看插件 |
lizhao-choose-file |
原生文件选择、上传、进度与取消 |
查看插件 |
lizhao-device-id |
设备标识、隐私策略与诊断 |
查看插件 |
lizhao-dingtalk |
钉钉授权登录、内容分享与回执诊断 |
查看插件 |
lizhao-doc-corrector |
文档扫描、矫正、增强与识别 |
查看插件 |
lizhao-douyin-kit |
抖音授权登录、内容分享与回执诊断 |
查看插件 |
lizhao-emu-detect |
模拟器环境检测、风险评分与证据 |
查看插件 |
lizhao-float-window |
悬浮窗、画中画、权限与诊断 |
查看插件 |
lizhao-gallery-pro |
相册媒体分页、筛选、缩略图与导出 |
查看插件 |
lizhao-google-login |
Google 授权登录、会话管理与脱敏诊断 |
查看插件 |
lizhao-hce-card |
NFC 虚拟卡、APDU 交互与 NDEF 标签模拟 |
查看插件 |
lizhao-health |
健康数据授权、查询、统计与写入 |
查看插件 |
lizhao-http-server |
本地 HTTP 服务、文件传输与实时通信 |
查看插件 |
lizhao-icon-pro |
SVG 图标组件、多主题与缓存 |
查看插件 |
lizhao-id-photo |
证件照制作、尺寸换算、换底色与模板换装 |
查看插件 |
lizhao-img-eraser |
图片去水印、局部修复与原生编辑器 |
查看插件 |
lizhao-live-activity |
实时活动、系统胶囊与普通通知降级 |
查看插件 |
lizhao-live-photo |
实况照片选取、展示预览与原件处理 |
查看插件 |
lizhao-map |
高德地图、定位、地点搜索、路线规划与导航 |
查看插件 |
lizhao-meta |
Facebook 登录分享、应用事件与深链 |
查看插件 |
lizhao-nfc-pro |
NFC 标签读写、NDEF、IsoDep 与诊断 |
查看插件 |
lizhao-notify-pro |
本地通知、点击动作、进度与定时提醒 |
查看插件 |
lizhao-novel-reader |
原生小说阅读、仿真翻页与段落评论 |
查看插件 |
lizhao-office-view |
Office 与 PDF 文件预览、进度与缓存管理 |
查看插件 |
lizhao-pdf-pro |
PDF 阅读、签批、真实写回与页面处理 |
查看插件 |
lizhao-play-billing |
Google Play 商品购买、订阅、恢复与确认消耗 |
查看插件 |
lizhao-qq-share |
QQ 授权码登录、QQ 与 QQ 空间分享 |
查看插件 |
lizhao-qrcode |
二维码生成、Logo 与样式配置、批量生成及导出 |
查看插件 |
lizhao-scan-pro |
原生扫码、连续扫码、相册识别 |
查看插件 |
lizhao-serial-port |
路径串口、USB 串口、多会话收发与诊断 |
查看插件 |
lizhao-share-plus |
系统分享、远程文件下载后分享 |
查看插件 |
lizhao-smart-tts |
系统 TTS、云端合成、听书方案 |
查看插件 |
lizhao-sqlite-pro |
原生 SQLite、迁移、备份与诊断 |
查看插件 |
lizhao-sse-pro |
SSE、Line、JSONL 与 Raw 流式请求 |
查看插件 |
lizhao-tcp-pro |
TCP 客户端、服务端、多连接与诊断 |
查看插件 |
lizhao-usb-storage |
U 盘、移动硬盘文件浏览、读写与批量复制 |
查看插件 |
lizhao-video-editor |
视频裁剪、压缩、取帧与 FFmpeg/FFprobe |
查看插件 |
lizhao-video-feed |
短视频上下滑、短剧选集与分页加载 |
查看插件 |
lizhao-video-player |
原生视频播放器、清晰度与播放交互 |
查看插件 |
lizhao-video-thumb |
视频封面、批量取帧与 Base64 返回 |
查看插件 |
lizhao-vpn-pro |
企业 VPN、IKEv2、安全接入与脱敏诊断 |
查看插件 |
lizhao-wechat-kit |
微信登录、分享、支付、小程序与客服 |
查看插件 |
lizhao-wecom |
企业微信授权登录、内容分享与脱敏诊断 |
查看插件 |
lizhao-xhs-share |
小红书图文视频分享与回执诊断 |
查看插件 |