更新记录

1.0.23(2026-09-17)

  • 修复 Android 部分系统上,接入插件后 App 内嵌 H5 调用 uni.chooseImage 或文件选择控件无法打开选图界面的问题。
  • 无需修改项目配置或调用代码;需要重新制作并安装 Android 自定义基座,正式包也需要重新打包。仅更新页面资源无法生效,iOS 和 HarmonyOS 不受影响。

1.0.22(2026-09-14)

  • 修复 iOS 使用列表渐进缩略图时云打包可能编译失败的问题;现有 API、参数和调用无需调整。
  • 本次仅影响 iOS;升级后需重新制作并安装 iOS 自定义基座或重新打包,Android、HarmonyOS 无需重新制作。

1.0.21(2026-09-11)

  • 修复 iOS 大图库媒体列表在分页前处理全部缩略图导致首屏等待较长的问题;现在先完成媒体分页,再按当前页生成缩略图。
  • 现有 API、参数、调用方式和 Android、HarmonyOS 行为无需调整。
  • 本次包含 iOS 原生代码变更,升级后需要重新制作并安装 iOS 自定义基座或正式包;仅更新页面资源或 WGT 无法生效。
查看更多

平台兼容性

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

lizhao-gallery-pro 是面向 uni-app / uni-app x 的系统相册媒体插件。取得用户授权后,应用可以直接读取图片和视频,并完成分页筛选、缩略图展示、临时文件导出、上传、保存到系统相册、元数据读取和相册变化监听。

这个插件能解决什么问题

  • 不弹系统选择器,直接构建自己的图片、视频或混合素材列表。
  • 分页读取大图库,并按时间、相册和来源筛选媒体。
  • 为九宫格、瀑布流和素材管理页生成缩略图。
  • 将系统媒体导出为页面可预览、接口可上传的临时文件。
  • 批量上传相册媒体,或把业务生成的图片和视频保存到系统相册。
  • 按相机、截图、微信、QQ、下载等来源组织素材。
  • 读取图片 EXIF、视频参数,以及由业务显式开启的位置元数据。
  • 监听相册变化,或使用持久化游标完成增量备份和同步。

适合社区发帖、评价晒单、工单上报、素材管理、云盘备份、自定义相册选择器和内容审核等业务。

本插件读取的是系统相册中当前应用有权访问的媒体,不会绕过系统权限。Web/H5 和小程序不能使用 App 端的系统相册整库读取能力。

支持平台

平台 图片/视频读取 缩略图与导出 保存与监听 是否需要自定义基座 说明
App Android 支持 支持 支持 需要 Android 13+ 按图片、视频分别授权;Android 12 及以下使用存储读取权限。
App iOS 支持 支持 支持 需要 使用 PhotoKit;有限照片权限下只返回用户允许访问的媒体。
App HarmonyOS 条件支持 条件支持 条件支持 需要 完整相册访问需要应用通过 AppGallery Connect(AGC)受限权限审核、取得对应 ACL、声明权限并完成用户授权。
Web/H5 不支持 不支持 不支持 不需要 API 明确返回不支持,不伪造成功。
微信/支付宝小程序 不支持 不支持 不支持 不需要 小程序应使用平台自己的媒体选择 API。

uni-app 与 uni-app x 使用同一套公开方法。平台能力应以本表和 getGalleryCapabilities() 的运行结果为准。

先选择接入方式

你的需求 推荐方法 下一步
只读取图片 getGalleryImages 用 nextPageToken 分页
只读取视频 getGalleryVideos 根据 durationMs 展示时长
图片和视频混合展示 getGalleryMedia 根据 mediaType 区分样式
做自己的素材选择器 列表使用渐进缩略图 选中后调用 prepareGalleryMedia
上传相册中的媒体 uploadGalleryMedia 监听 progress 和逐项结果
保存业务生成的文件 saveMediaToGallery 选择目标相册和重复策略
做相册入口或来源分类 getGalleryAlbums + 查询过滤 使用返回的 albumId 或 sourceType
读取拍摄和视频参数 getGalleryMetadata 默认不读取位置
相册变化后刷新页面 startGalleryChangeObserver 页面卸载时停止监听
做增量备份或同步 getGalleryChanges 业务处理成功后保存 nextCursor

第一次接入建议从模块一开始;已经有媒体 ID 时,可以直接查看缩略图、导出、上传或元数据模块。

下载与导入

  1. 从 DCloud 插件市场导入插件。
  2. App 端使用包含本插件原生代码和权限配置的自定义基座或正式安装包。
  3. 页面只能从插件根目录导入,不要直接导入 utssdk 子目录。

uni-app 导入

import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'

uni-app x 导入

import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'

下面以普通 uni-app 写法说明业务流程;uni-app x 使用同名 API,完整强类型页面见文末示例路径。

按业务模块使用

模块一:申请权限并读取第一批图片和视频

适合第一次接入。流程是先检查权限,未授权时再请求,授权成功后读取第一批媒体。

import * as GalleryPro from '@/uni_modules/lizhao-gallery-pro'

function loadFirstPage() {
  GalleryPro.getGalleryMedia({
    mediaType: 'all',
    pageSize: 30,
    thumbnailMode: 'progressive',
    thumbnailBatchSize: 4,
    success(res) {
      // 先显示当前页名称、类型和尺寸等信息。
      console.log('首批媒体', res.items)
      console.log('是否还有下一页', res.hasMore, res.nextPageToken)
    },
    thumbnailProgress(event) {
      // 每批只更新 event.items 对应的列表项。
      console.log('缩略图进度', event.current, event.total, event.items)
    },
    fail(err) {
      console.log('读取相册失败', err.errCode, err.errMsg)
    }
  })
}

GalleryPro.checkGalleryPermission({
  mediaType: 'all',
  success(permission) {
    if (permission.granted) {
      loadFirstPage()
      return
    }

    GalleryPro.requestGalleryPermission({
      mediaType: 'all',
      preferFullAccess: true,
      success(result) {
        if (result.granted) {
          loadFirstPage()
        } else if (result.shouldOpenSettings) {
          console.log('请引导用户到系统设置中开启相册权限')
        }
      },
      fail(err) {
        console.log('请求相册权限失败', err.errCode, err.errMsg)
      }
    })
  },
  fail(err) {
    console.log('检查相册权限失败', err.errCode, err.errMsg)
  }
})

success 表示权限检查或请求动作正常完成,是否真正获得权限仍要读取 granted 和 status。不要把权限受限当成空相册。列表使用 thumbnailMode: 'progressive' 时,success 先返回当前页基础数据,thumbnailProgress 再分批补充缩略图,complete 在当前页缩略图处理结束后触发。

模块二:分页读取并筛选需要的媒体

适合素材库、相册备份和媒体管理。getGalleryImages、getGalleryVideos 与 getGalleryMedia 使用同一套分页和筛选参数。 getGalleryMedia 用于图片视频混合列表;需要全量读取时,必须根据 hasMore 和 nextPageToken 循环读取下一页,不能用超大 pageSize 代替分页。

let nextPageToken = ''
let mediaItems = []

function loadNextPage() {
  GalleryPro.getGalleryMedia({
    mediaType: 'all',
    pageSize: 30,
    pageToken: nextPageToken,
    // 示例:只看最近 7 天、来自相机或系统识别为 camera 的媒体。
    startTime: Date.now() - 7 * 24 * 60 * 60 * 1000,
    sourceType: 'camera',
    sortOrder: 'desc',
    success(res) {
      mediaItems = mediaItems.concat(res.items)
      nextPageToken = res.nextPageToken
      console.log('已加载/总数', mediaItems.length, res.total)
    },
    fail(err) {
      console.log('分页读取失败', err.errCode, err.errMsg)
    }
  })
}

只读取图片时改用 getGalleryImages,只读取视频时改用 getGalleryVideos。如果已经从相册分组取得 albumId,可以把它传给查询方法,只读取该相册。

不要自行修改 nextPageToken,也不要用超大的 pageSize 一次加载整个图库。筛选条件变化时应清空旧令牌并从第一页重新查询。

获取全部可访问图片,并筛选 2:1 全景图

“全部图片”是指当前应用在系统授权范围内能够访问的全部图片。必须持续请求下一页,直到 hasMore 为 false;iOS 有限照片权限等场景只会返回用户允许访问的图片。

2:1 表示图片的宽高比,不是 JPG、PNG 这类文件格式。查询结果包含 width、height 和 mimeType,可以先分页读取,再按宽高比筛选。考虑到裁剪、拼接和编码可能产生少量像素偏差,普通业务建议使用 1.95 ~ 2.05 的容差范围:

let panoramaImages = []

function loadAllPanoramaImages(pageToken = '') {
  GalleryPro.getGalleryImages({
    pageSize: 100,
    pageToken,
    sortOrder: 'desc',
    success(res) {
      const currentPage = res.items.filter((item) => {
        if (item.width <= 0 || item.height <= 0) {
          return false
        }

        const aspectRatio = item.width / item.height
        return aspectRatio >= 1.95 && aspectRatio <= 2.05
      })

      panoramaImages = panoramaImages.concat(currentPage)

      if (res.hasMore && res.nextPageToken !== '') {
        loadAllPanoramaImages(res.nextPageToken)
        return
      }

      console.log('2:1 全景图片读取完成', panoramaImages.length, panoramaImages)
    },
    fail(err) {
      console.log('读取全景图片失败', err.errCode, err.errMsg)
    }
  })
}

// 每次重新筛选前清空旧结果,并从第一页开始。
panoramaImages = []
loadAllPanoramaImages()

如果业务要求像素必须严格等于 2:1,可把判断改为 item.width === item.height * 2。如果还要限制文件编码格式,可同时判断 item.mimeType,例如只保留 image/jpeg。仅凭 2:1 尺寸不能判断图片是否带有完整的 360° 全景元数据;需要识别可交互全景图时,还应在导出文件后检查对应的全景元数据。

模块三:渐进显示缩略图并一次准备可用文件

相册返回的 id 是后续操作的稳定入口。推荐让列表先显示基础信息并渐进补缩略图;用户真正选中某一项后,再一次准备预览、上传和视频 poster 路径。 路径用途保持固定:renderPath 用于页面显示,uploadPath 用于上传,不要在页面层自行转换系统资产标识。

getGalleryImages 不会修改或压缩系统相册中的原文件。启用缩略图后,插件会另外生成经过缩放和 JPEG 编码的缓存文件;thumbnailPath 只适合列表小图,不要直接放大作为详情页或全屏预览。大图、视频和上传请使用 prepareGalleryMedia 的结果。

const selectedId = '从列表结果取得的媒体ID'

GalleryPro.prepareGalleryMedia({
  id: selectedId,
  posterWidth: 640,
  posterHeight: 360,
  success(res) {
    // image/video 的 src 使用 renderPath。
    console.log('预览路径', res.renderPath)
    // uni.uploadFile 使用 uploadPath。
    console.log('上传路径', res.uploadPath)
    // video 的 poster 或列表封面使用 posterPath。
    console.log('视频首帧', res.posterPath)
    console.log('是否复用已有导出', res.cacheHit)
  },
  fail(err) {
    console.log('准备媒体失败', err.errCode, err.errMsg)
  }
})

视频组件直接绑定 <video :src="prepared.renderPath" :poster="prepared.posterPath" />。posterPath 是 JPEG 缓存路径;图片也会返回可用于占位展示的缩略图路径。仅上传、不需要 poster 时可传 includePoster: false。

同一媒体未变化时,再次调用会复用已有导出并返回 cacheHit: true,预览后上传不需要重复复制。旧的 getGalleryThumbnails、getMediaById 和 exportMediaToTempFile 继续可用;用户删除媒体、撤销权限或云端原图尚未下载时,准备或导出仍可能失败。

模块四:上传媒体或批量保存到系统相册

uploadGalleryMedia 用于把已存在于系统相册的媒体上传到业务服务器。先用 dryRun: true 可以只验证导出链路,不发起网络请求。 调试时也可以记为 dryRun=true;批量结果顺序与 options.ids 一致,仍需检查每一项的 success。

GalleryPro.uploadGalleryMedia({
  ids: ['media-id-1', 'media-id-2'],
  url: 'https://example.com/upload',
  name: 'file',
  formData: { scene: 'feedback' },
  concurrency: 2,
  retryCount: 1,
  progress(event) {
    console.log('上传进度', event.current, event.total, event.progress)
  },
  success(res) {
    console.log('上传成功/失败', res.successCount, res.failCount)
    console.log('逐项结果', res.items)
  },
  fail(err) {
    console.log('上传任务无法完成', err.errCode, err.errMsg)
  }
})

saveMediaToGallery 用于把业务生成、下载或插件导出的本地文件保存到系统相册。

GalleryPro.saveMediaToGallery({
  paths: [
    '/本地可访问路径/report-photo.jpg',
    '/本地可访问路径/report-video.mp4'
  ],
  albumName: '工单附件',
  duplicatePolicy: 'skip',
  progress(event) {
    console.log('保存进度', event.current, event.total, event.progress)
  },
  success(res) {
    console.log('保存/跳过/失败', res.successCount, res.skippedCount, res.failCount)
  },
  fail(err) {
    console.log('保存到相册失败', err.errCode, err.errMsg)
  }
})

上传结果和保存结果都按输入顺序返回。duplicatePolicy: 'skip' 只跳过系统当前可见范围内能够确认的重复项,不应把它当作跨设备文件去重方案;需要保留每次保存结果时使用 duplicatePolicy: 'allow'。

模块五:按相册和来源组织素材

适合相册入口、文件夹侧栏、来源筛选和素材分类页。getGalleryAlbums 默认使用快速模式:先返回相册名称、数量和最新媒体信息,不在返回前生成封面,因此大图库不会因为缩略图处理而延迟显示整个文件夹列表。常见来源包括相机、截图、微信、QQ、下载,例如截图筛选可传 sourceType='screenshot'。

第一步:快速显示文件夹列表

GalleryPro.getGalleryAlbums({
  mediaType: 'all',
  sourceType: 'all',
  // 可以省略,默认就是 false。
  includeCoverThumbnail: false,
  success(res) {
    console.log('先显示这些文件夹', res.albums)

    const firstAlbum = res.albums[0]
    if (firstAlbum == null) return

    GalleryPro.getGalleryMedia({
      mediaType: 'all',
      albumId: firstAlbum.albumId,
      pageSize: 30,
      success(list) {
        console.log('当前相册媒体', list.items)
      }
    })
  },
  fail(err) {
    console.log('读取相册分组失败', err.errCode, err.errMsg)
  }
})

默认快速模式下,coverThumbnailPath 为空是正常结果,不表示文件夹读取失败。相册名称、count、imageCount、videoCount 和 latestMediaId 已经可以立即用于渲染侧栏或列表。

第二步:列表显示后再补封面(推荐)

先把 res.albums 赋给页面数据,让文件夹完成一次渲染;下一轮再使用每个相册的 latestMediaId 生成封面:

let albumList = []

function fillAlbumCovers(ids, offset = 0) {
  if (offset >= ids.length) return

  const batch = ids.slice(offset, offset + 4)
  GalleryPro.getGalleryThumbnails({
    ids: batch,
    width: 180,
    height: 180,
    success(thumbnails) {
      thumbnails.items.forEach(thumbnail => {
        const album = albumList.find(item => item.latestMediaId == thumbnail.id)
        if (album != null) album.coverThumbnailPath = thumbnail.thumbnailPath
      })

      // 当前批次完成后再处理下一批,避免一次生成全部封面。
      setTimeout(() => fillAlbumCovers(ids, offset + batch.length), 0)
    },
    fail(err) {
      // 单批失败不隐藏文件夹,也不阻塞后续批次。
      console.log('这一批封面暂未生成', err.errCode, err.errMsg)
      setTimeout(() => fillAlbumCovers(ids, offset + batch.length), 0)
    }
  })
}

GalleryPro.getGalleryAlbums({
  mediaType: 'all',
  includeCoverThumbnail: false,
  success(res) {
    // 先更新页面,文件夹名称和数量会立即出现。
    albumList = res.albums

    const ids = res.albums
      .map(album => album.latestMediaId)
      .filter((id, index, values) => id.length > 0 && values.indexOf(id) == index)

    if (ids.length == 0) return

    setTimeout(() => fillAlbumCovers(ids, 0), 0)
  }
})

内置 uni-app 和 uni-app x 示例会每批处理 4 个封面,并输出查询耗时,适合直接观察“文件夹先出现、封面随后补齐”的效果。

在示例页可以按下面顺序验证:

按钮 页面表现 日志标记 适用场景
快速读取文件夹 文件夹名称和数量先出现,封面显示“待加载” ALBUMS_FAST_OK 只需要文件夹信息
快速读取并补封面 文件夹先出现,封面随后每批 4 个逐步补齐 ALBUMS_FAST_OK、ALBUMS_LAZY_COVER_OK 正式项目推荐
读取时生成封面(性能对照) 等封面都处理后一次显示,可与前两项耗时对比 ALBUMS_EAGER_COVER_OK 兼容必须一次返回封面的旧页面

首次测试建议选择“快速读取并补封面”。看到文件夹名称和数量后即可操作列表,不需要等待所有封面;个别封面生成失败也不应隐藏已经显示的文件夹。

需要一次返回封面时

如果页面必须等封面准备好再接收结果,可以显式开启:

GalleryPro.getGalleryAlbums({
  mediaType: 'all',
  sourceType: 'all',
  includeCoverThumbnail: true,
  success(res) {
    console.log('相册和封面均已处理', res.albums)
  }
})

这种方式会等待封面缓存读取或生成,大图库首次调用可能明显慢于默认快速模式,不建议用于文件夹侧栏首屏。

sourceType 可使用 camera / screenshot / wechat / qq / download / other / all。来源分类依赖系统相册目录、文件名和平台元数据,不同设备或应用保存目录可能存在差异。

模块六:读取图片 EXIF、视频参数和位置信息

先从列表取得媒体 ID,再按需批量读取元数据。GPS 默认关闭,只有显式设置 includeLocation: true 才会请求并读取位置。

GalleryPro.getGalleryMetadata({
  ids: ['media-id-1', 'media-id-2'],
  includeExif: true,
  includeLocation: false,
  useCache: true,
  progress(event) {
    console.log('元数据进度', event.current, event.total)
  },
  success(res) {
    console.log('成功/失败', res.successCount, res.failCount)
    res.items.forEach((item) => {
      console.log(item.id, item.width, item.height, item.durationMs)
    })
  },
  fail(err) {
    console.log('元数据任务无法启动', err.errCode, err.errMsg)
  }
})

批量读取允许部分成功,items 始终与输入 ids 顺序一致。位置不会写入插件缓存,也不会被上传或转换成地址;业务只有在确实需要时才应开启位置读取,并避免把坐标写入日志。

模块七:相册变化实时监听与增量同步

页面正在展示相册时,可以注册变化监听。success 返回的 observerId 要保存下来,并在页面卸载时停止。

let galleryObserverId = ''

GalleryPro.startGalleryChangeObserver({
  mediaType: 'all',
  debounceMs: 500,
  includeChanges: true,
  change(event) {
    console.log('相册发生变化', event.reason, event.changeCount)
    console.log('新增/删除/修改', event.addedIds, event.removedIds, event.updatedIds)
  },
  success(res) {
    galleryObserverId = res.observerId
  },
  fail(err) {
    console.log('注册相册监听失败', err.errCode, err.errMsg)
  }
})

function stopGalleryObserver() {
  if (!galleryObserverId) return
  GalleryPro.stopGalleryChangeObserver({
    observerId: galleryObserverId,
    success() {
      galleryObserverId = ''
    }
  })
}

备份、云盘同步等需要可靠重试的业务,应使用持久化增量游标。首次不传 cursor 会建立基线;处理完变化后再保存新的 nextCursor。当 resetReason 为 cursorExpired 时,原游标已过期,应重新执行一次全量同步并保存新基线。

const savedCursor = uni.getStorageSync('gallery-change-cursor') || ''

GalleryPro.getGalleryChanges({
  cursor: savedCursor,
  mediaType: 'all',
  maxChanges: 2000,
  success(res) {
    if (res.resetRequired) {
      console.log('需要重新执行一次全量同步', res.resetReason)
    } else if (!res.isInitial) {
      console.log('新增', res.addedIds)
      console.log('删除', res.removedIds)
      console.log('修改', res.updatedIds)
    }

    // 业务处理成功后再推进游标,失败时保留旧游标即可重试。
    uni.setStorageSync('gallery-change-cursor', res.nextCursor)
  },
  fail(err) {
    console.log('读取相册增量失败', err.errCode, err.errMsg)
  }
})

退出账号或不再使用某条基线时,调用 clearGalleryChangeCursor({ cursor })。监听只在应用进程存活期间有效,不能替代系统后台任务。

模块八:判断能力并管理缓存

先读取能力矩阵,可以在不支持的平台隐藏对应入口。

const capabilities = GalleryPro.getGalleryCapabilities()

if (!capabilities.images && !capabilities.videos) {
  console.log(capabilities.message)
}

GalleryPro.clearGalleryCache({
  cacheType: 'thumbnail',
  success(res) {
    console.log('已清理数量和字节', res.removedCount, res.releasedBytes)
  },
  fail(err) {
    console.log('清理缓存失败', err.errCode, err.errMsg)
  }
})

cacheType 可使用 thumbnail / export / changeCursor / metadata / all。清理导出缓存后,之前返回的临时路径可能失效;业务需要再次预览或上传时应重新导出。

只清理缩略图时也可以简写为 clearGalleryCache({ cacheType: 'thumbnail' })。Web/H5 和小程序等不支持平台会明确失败,不会返回伪造成功结果。

常用 API 与配置

API 用途总览

业务模块 适用业务 常用方法 使用结果
权限 页面入口、首次授权 checkGalleryPermission、requestGalleryPermission 当前授权状态和设置引导
媒体列表 图片、视频、混合素材选择 getGalleryImages、getGalleryVideos、getGalleryMedia 分页媒体列表
缩略图与单项 九宫格、详情页 渐进列表、getGalleryThumbnails、getMediaById 缩略图或单个媒体信息
准备、导出与上传 预览、poster、编辑、业务提交 prepareGalleryMedia、exportMediaToTempFile、uploadGalleryMedia 可渲染、可上传路径和逐项结果
保存 保存生成或下载的本地媒体 saveMediaToGallery 按输入顺序返回保存明细
相册分组 相册入口、来源分类 getGalleryAlbums 相册、封面和数量
元数据 素材详情、拍摄参数 getGalleryMetadata EXIF、视频参数和可选位置
实时变化 页面刷新 startGalleryChangeObserver、stopGalleryChangeObserver 变化事件和监听器 ID
增量同步 备份、云盘、局部刷新 getGalleryChanges、clearGalleryChangeCursor 新增、删除、修改 ID 和新游标
能力与缓存 跨平台入口、空间管理 getGalleryCapabilities、clearGalleryCache 能力矩阵和清理结果

通用回调

异步方法按需要支持以下回调:

回调 触发时机
success 当前任务成功完成;批量任务可能包含单项失败,仍需检查结果明细
fail 参数、权限、平台能力或整个任务无法完成
complete 成功或失败后均触发一次
progress 上传、保存或元数据批处理完成一个阶段或单项时触发

权限参数 GalleryPermissionOptions

参数 类型 默认值 说明
mediaType image / video / all all 检查或请求的媒体类型
preferFullAccess boolean false iOS 有限权限时是否更倾向请求完整访问
success / fail / complete function 无 权限动作回调

列表参数 GalleryQueryOptions

参数 类型 默认值 说明
mediaType image / video / all all 专用图片或视频方法会覆盖该值
pageSize number 30 每页数量,建议 1~100
pageToken string 空字符串 使用上次返回的 nextPageToken
startTime / endTime number 无 毫秒时间戳范围
albumId string 无 getGalleryAlbums 返回的相册 ID
sourceType GallerySourceType all 来源分类过滤
sortOrder desc / asc desc 时间排序方向
includeHidden boolean false Android/HarmonyOS 仍受系统可见资产范围限制
includeThumbnail boolean false 旧的同步缩略图开关;未传 thumbnailMode 时保持原行为
thumbnailMode none / sync / progressive 兼容旧开关 progressive 先返回列表,再按当前页分批补缩略图
thumbnailBatchSize number 4 渐进模式每批数量,范围 1~20
thumbnailWidth / thumbnailHeight number 240 查询时请求的缩略图尺寸
thumbnailProgress function 无 渐进模式批次回调,包含 items/current/total/done

options.includeHidden 只表达查询偏好;Android 与 HarmonyOS 仍受系统公开媒体范围限制,不保证包含系统隐藏媒体。

缩略图、单项与导出参数

方法 必填参数 常用可选参数
getGalleryThumbnails ids width=240、height=240、quality=80
getMediaById id includeThumbnail=false
exportMediaToTempFile id exportType=render、fileName
prepareGalleryMedia id includePoster=true、posterWidth=320、posterHeight=320

exportType 可使用 render / upload / original,它只表示本次使用意图,不会生成三份文件。一次导出始终同时返回同一文件的 renderPath 和 uploadPath;相同媒体未变化时会复用有效缓存,并通过 cacheHit 告知是否命中。

上传参数 GalleryUploadOptions

参数 类型 默认值 说明
ids Array<string> 无 必填,结果顺序与该数组一致
url string 无 dryRun=true 时可以不传
dryRun boolean false 只验证导出,不发起网络请求
name string file 文件表单字段名
formData UTSJSONObject 无 附加表单字段
concurrency number 1 建议 1~3
retryCount number 0 单项失败重试次数
timeoutMs number 60000 单文件上传超时毫秒数

保存参数 GallerySaveOptions

参数 类型 默认值 说明
paths Array<string> 无 必填,本地绝对路径或 file:// 路径
albumName string 系统默认相册 自定义目标相册名称
duplicatePolicy allow / skip allow 保存重复项或跳过可见重复项
progress function 无 每处理完一项触发

相册与元数据参数

方法 必填参数 常用可选参数
getGalleryAlbums 无 mediaType=all、sourceType=all、includeCoverThumbnail=false
getGalleryMetadata ids includeExif=true、includeLocation=false、useCache=true

includeCoverThumbnail=false 是默认快速模式,coverThumbnailPath 返回空字符串;设为 true 才会在相册结果返回前处理封面。需要首屏流畅时,推荐使用 latestMediaId + getGalleryThumbnails 在列表显示后补封面。

getGalleryMetadata 接受 1~100 个不重复 ID。位置必须由 includeLocation: true 显式开启,并受平台权限控制。

监听与增量参数

方法 必填参数 常用可选参数
startGalleryChangeObserver change mediaType=all、debounceMs、includeChanges=false、maxChanges=2000
stopGalleryChangeObserver observerId 无
getGalleryChanges 无 cursor、mediaType=all、maxChanges=2000
clearGalleryChangeCursor cursor 无

首次不传 cursor 调用 getGalleryChanges 会建立基线。旧游标在有效期内保持不变,业务处理失败时可继续使用旧游标重试。

缓存参数 GalleryClearCacheOptions

参数 类型 默认值 说明
cacheType GalleryCacheType all thumbnail / export / changeCursor / metadata / all
olderThanMs number 无 只清理早于该毫秒时间戳的缓存

主要返回值

权限与列表

类型 关键字段 说明
GalleryPermissionResult granted、status、limited、shouldOpenSettings、platform、message success 回调后仍需依据 granted/status 判断授权结果
GalleryQueryResult total、items、hasMore、nextPageToken、mediaType 当前查询条件下的一页结果
GalleryMediaByIdResult item、message 返回单个媒体;媒体已删除时会失败

媒体项 GalleryMediaItem

字段 类型 说明
id string 当前平台稳定媒体 ID,后续 API 使用该值
mediaType image / video 媒体类型
fileName / mimeType string 文件名和 MIME 类型
width / height number 像素宽高
durationMs number 视频时长,图片为 0
size number 文件大小,单位字节
createTime / modifiedTime number 毫秒时间戳
albumId / albumName string 所属相册
sourceType / sourceLabel string 来源分类和中文说明
originalPath string 原始路径或平台资产标识,不保证可直接渲染
renderPath string 页面可显示路径
uploadPath string 上传可用路径
thumbnailPath string 缩略图路径
requiresExport boolean 是否需要先导出才能稳定显示

缩略图、导出、上传与保存

类型 关键字段 说明
GalleryThumbnailItem id、thumbnailPath、width、height、message 单个缩略图结果
GalleryThumbnailResult success、items、message 批量缩略图结果
GalleryThumbnailProgress items、current、total、done、message 当前页渐进缩略图批次
GalleryExportResult id、renderPath、uploadPath、size、cacheHit、message 导出后的临时文件信息
GalleryPrepareResult id、mediaType、renderPath、uploadPath、posterPath、size、cacheHit 一次准备预览、上传和 poster 路径
GalleryUploadResult successCount、failCount、items、message items 与输入 ids 顺序一致
GallerySaveResult successCount、failCount、skippedCount、items、message items 与输入 paths 顺序一致

GalleryUploadItemResult 和 GallerySaveItemResult 都包含输入下标、单项成功状态、错误码和中文说明;批量结果的 success=false 不代表所有单项都失败。

相册分组 GalleryAlbumItem

字段 说明
albumId / albumName 相册 ID 和名称
sourceType 来源分类
count / imageCount / videoCount 媒体总数和分类数量
coverThumbnailPath 相册封面缩略图;默认快速模式下为空字符串
latestMediaId / latestMediaType 最新媒体 ID 和类型;可交给 getGalleryThumbnails 按需生成封面
latestFileName / latestCreateTime 最新媒体文件名和创建时间

元数据结果 GalleryMetadataItem

字段 说明
id / success / mediaType 输入 ID、单项状态和媒体类型
width / height / durationMs / orientation 宽高、视频时长和方向
captureTime 拍摄时间,未知为 0
cameraMake / cameraModel / lensModel 相机、机型和镜头信息
iso / exposureTime / aperture ISO、曝光时间和光圈,未知时省略
focalLength / focalLength35mm 焦距和 35mm 等效焦距,未知时省略
videoCodec / videoBitrate / videoFrameRate 视频编码、码率和帧率
locationAvailable / location 本次是否返回位置及经纬度;默认不读取
fromCache 非敏感字段是否来自缓存
errCode / message 单项诊断码和中文结果

GalleryMetadataResult.items 与输入 ids 顺序一致。success=true 的单项也可能携带非致命 9070032,表示缓存读写失败,但原始媒体元数据仍读取成功。

监听、增量和缓存结果

类型 关键字段 说明
GalleryChangeObserverStartResult observerId、message 保存 ID 以便停止监听
GalleryChangeEvent reason、addedIds、removedIds、updatedIds、changeCount includeChanges=false 时精确 ID 可能为空
GalleryChangesResult isInitial、resetRequired、resetReason、三类 ID、nextCursor 成功处理后再保存新游标
GalleryClearChangeCursorResult cursor、removed、message 游标不存在仍可按幂等成功处理
GalleryClearCacheResult removedCount、releasedBytes、message 返回本次实际清理结果

能力矩阵 GalleryCapabilities

常用字段包括 images、videos、mixed、pagination、timeRange、sourceClassification、thumbnails、exportTempFile、upload、saveMedia、metadata、exif、locationMetadata、changeObserver、incrementalChanges、persistentChangeCursor、customBaseRecommended 和 message。

错误码

错误码 含义 说明
9070001 unsupported or context unavailable 当前平台不支持,或 App 上下文不可用
9070002 permission denied 相册读取权限未授权或请求失败
9070003 invalid options 参数为空、ID 列表为空或格式不正确
9070004 media not found 指定媒体不存在,可能已被删除或 ID 不属于当前平台
9070005 album query failed 相册分组查询失败
9070006 cache failed 缓存目录创建或写入失败
9070007 query failed 相册列表、分组或平台桥接查询失败
9070008 thumbnail failed 缩略图生成失败
9070009 export failed 媒体导出失败,iOS 可能需要先下载 iCloud 原图
9070010 upload failed 上传过程失败,包含上传地址为空、网络请求失败或超时
9070011 cache clear failed 缓存清理失败
9070012 cancelled 任务被取消或系统中断
9070013 file unavailable 导出后的文件不可访问
9070014 internal failed 插件内部异常,建议保留日志排查
9070015 observer register failed 原生相册变化观察器注册失败
9070016 observer not found observerId 不存在或已经停止
9070017 invalid observer options 缺少 change 回调或监听参数不合法
9070018 invalid save options paths 为空、全部为空字符串或参数不合法
9070019 source unavailable 本地源文件不存在、不可读或不是普通文件
9070020 unsupported media type 输入文件无法识别为支持的图片或视频
9070021 add permission denied 系统相册写入或判重所需读取权限被拒绝
9070022 album operation failed 创建、查找或更新指定目标相册失败
9070023 save media failed 创建相册记录、复制文件或 PhotoKit 保存失败
9070024 save unsupported 当前平台没有系统相册保存实现
9070025 invalid change cursor options 增量参数或游标格式不合法
9070026 change snapshot failed 增量快照扫描、读取或写入失败
9070027 gallery changes unsupported 当前平台不支持系统相册增量变化
9070028 clear change cursor failed 指定增量游标清理失败
9070029 invalid gallery metadata options 元数据参数无效,例如 ID 为空、超过 100 个或存在重复 ID
9070030 gallery metadata read failed 单个媒体的元数据读取失败
9070031 gallery metadata unsupported 当前平台不支持系统相册元数据读取
9070032 gallery metadata cache failed 非敏感元数据缓存读写失败;属于非致命错误,插件继续读取原始媒体

常见问题

为什么权限检查成功后仍然不能读取相册

权限 API 的 success 表示检查动作完成,不代表已经授权。请检查 granted 和 status;denied 或 restricted 时不要继续读取,也不要把结果展示为“相册为空”。

HarmonyOS 为什么返回 9070002

HarmonyOS 完整相册访问需要同时满足三层条件:应用已通过 AppGallery Connect(AGC)受限权限审核且 Profile 取得 READ_IMAGEVIDEO、WRITE_IMAGEVIDEO 等所需 ACL,应用安装包已经声明对应权限,用户在设备上完成运行时授权。任一条件缺失都可能返回 9070002。

ohos.permission.MEDIA_LOCATION 用于受控读取媒体位置,属于运行时敏感权限,不是 Gallery Pro 需要申请的 ACL 项。只有业务显式开启 includeLocation 时才需要处理位置授权。

返回空数组是没有权限吗

不是。权限失败会通过权限状态或 fail 返回明确错误;成功返回空数组通常表示当前相册没有可见媒体,或时间、相册、来源等筛选条件没有匹配结果。

为什么列表中的路径不能直接预览

不同平台可能返回系统资产标识,而不是普通文件路径。Android 列表中的 originalPath / renderPath / uploadPath 可能都是 content://,它们用于标识 MediaStore 资产,不保证能直接交给 <image>、<video> 或 uni.uploadFile。列表先使用 thumbnailPath;需要大图、视频、poster 或上传路径时调用 prepareGalleryMedia。旧代码也可继续调用 exportMediaToTempFile,页面使用其 renderPath,上传使用 uploadPath。

为什么 getGalleryImages 获取的图片在部分手机上很模糊

getGalleryImages 不会修改或压缩系统相册中的原文件,但启用 includeThumbnail 或随后调用 getGalleryThumbnails 时,返回的 thumbnailPath 是经过缩放和 JPEG 编码的缓存缩略图。缩略图用于列表快速显示;如果把较小的缩略图放大到详情页或全屏区域,在高分辨率设备上会明显模糊。

  • 列表小图使用 thumbnailPath,并让 thumbnailWidth / thumbnailHeight 或 width / height 接近实际显示所需的物理像素。不要把 180 × 180 的缩略图放大到数百像素区域。
  • 2:1 全景图列表可以按页面尺寸请求较大的同比例缩略图,例如 800 × 400;希望保留完整画面时,页面图片使用 aspectFit,使用 aspectFill 会裁剪画面边缘。
  • 详情页、全屏预览、图片编辑必须调用 exportMediaToTempFile,使用该方法返回的 renderPath。不要把列表结果中的 thumbnailPath 当作原图路径。
  • iOS 列表结果中的 renderPath 可能与 thumbnailPath 相同,因此也不能把它当作原图;仍应以 exportMediaToTempFile 返回的 renderPath 为准。
  • 上传原文件时使用导出结果中的 uploadPath,不要上传 thumbnailPath。

如果同一套页面代码在部分手机清晰、部分手机模糊,请优先记录实际绑定到 <image :src> 的字段、缩略图请求尺寸和图片显示尺寸,检查是否在不同设备上把小尺寸 thumbnailPath 放大显示。

为什么文件夹已经显示,但相册封面为空

这是 getGalleryAlbums 的默认快速模式。插件会先返回文件夹名称、数量和最新媒体信息,避免等待全部缩略图后才显示侧栏。需要封面时,使用每个相册的 latestMediaId 调用 getGalleryThumbnails;如果确实需要一次返回全部封面,再显式传入 includeCoverThumbnail: true。

大图库如何避免卡顿

媒体列表使用合理的 pageSize,保存 nextPageToken 并按需加载下一页;推荐设置 thumbnailMode: 'progressive',先渲染当前页基础信息,再通过 thumbnailProgress 分批补图。文件夹列表保持 includeCoverThumbnail: false,先渲染名称和数量,再分批补封面。不要在首屏串行生成全部缩略图,也不要为了“读取全部”把 pageSize 设置得非常大。

iOS 为什么只能看到部分照片

用户可能选择了有限照片权限。此时 status 通常为 limited,插件只能读取系统允许当前应用访问的媒体。业务可以说明用途并让用户自行调整授权范围,但不能绕过系统选择。

为什么默认读不到照片位置

位置属于敏感信息,includeLocation 默认是 false。显式开启后仍受平台权限和媒体本身是否包含位置影响。位置不会进入插件缓存,locationAvailable=false 也不能直接证明原媒体没有 GPS。

保存后为什么仍可能出现重复媒体

默认策略 allow 会正常保存每个输入文件。skip 只能根据系统当前可见范围判断可见重复项;文件内容变化、权限范围变化或不同设备之间都可能无法命中。

为什么相册监听没有触发

先确认监听注册成功并保存了 observerId。监听只在应用进程存活期间有效,系统变化可能经过 debounceMs 防抖;需要跨启动可靠同步时改用 getGalleryChanges 和持久化游标。

为什么只更新页面资源后原生能力没有变化

本插件包含 Android、iOS 和 HarmonyOS 原生实现。首次集成,或修改插件原生代码、权限声明、原生依赖后,需要重新制作并安装对应平台的自定义基座、正式安装包或 HAP。普通页面和 README 修改不需要重新制作基座。

完整示例

  • uni-app:uni_modules/lizhao-gallery-pro/example/uniapp/galleryPro.vue
  • uni-app x:uni_modules/lizhao-gallery-pro/example/uniappx/index.uvue

完整示例包含权限、图片/视频/混合列表、分页、相册分组、缩略图、临时导出、上传 dry-run、保存、元数据、变化监听、增量游标和缓存管理。

注意事项

  • 页面必须从插件根目录导入,不要直接引用 utssdk 内部文件。
  • Android 13 及以上按图片和视频分别授权;Android 12 及以下使用外部存储读取权限。用户永久拒绝后,根据 shouldOpenSettings 引导到系统设置。
  • iOS limited 表示用户只授权部分照片,所有列表、分组、判重和变化结果都以系统当前可见范围为准。
  • HarmonyOS 完整相册能力需要 ACL、应用权限声明和用户授权同时生效。没有 ACL 时,重复调用运行时权限请求不能解决问题。
  • 读取位置必须显式设置 includeLocation: true;插件不进行逆地理编码,不上传、不记录、不缓存位置。
  • 图片 EXIF、视频参数和位置均由系统公开 API 在本地读取;云端原图尚未下载时可能出现单项失败。
  • originalPath 可能是 content:// 等平台资产标识,不保证能直接交给页面或上传接口;优先使用缩略图和 prepareGalleryMedia 结果。
  • 临时导出文件与缩略图受缓存清理影响。清理后原路径失效时,应重新调用对应 API。
  • 上传和保存是批量任务,必须查看逐项结果,不能只依据整体 success 判断每个文件。
  • 来源分类能覆盖常见目录,但不同系统、ROM 和第三方应用保存路径可能导致分类差异。
  • 页面卸载时停止变化监听;增量同步只在业务处理成功后保存新的 nextCursor。
  • Web/H5 和小程序不支持本插件的系统相册整库读取;请使用各平台提供的选择器能力。
  • 只修改 README、普通页面或样式时不需要重新制作自定义基座;修改原生实现、权限或依赖时必须重新制作并安装匹配包。

联系方式

微信:l-z-1-8-7-1512-5421(使用时去掉连字符)。

作者系列 UTS 插件

以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。

插件 能力方向 插件市场
lizhao-nfc-pro NFC 标签读写、NDEF、IsoDep 与诊断 查看插件
lizhao-float-window 悬浮窗、画中画、权限与诊断 查看插件
lizhao-device-id 设备标识、隐私策略与诊断 查看插件
lizhao-scan-pro 原生扫码、连续扫码、相册识别 查看插件
lizhao-choose-file 原生文件选择、上传、进度与取消 查看插件
lizhao-bg-audio 背景音频播放、队列、倍速与事件 查看插件
lizhao-smart-tts 系统 TTS、云端合成、听书方案 查看插件
lizhao-share-plus 系统分享、远程文件下载后分享 查看插件
lizhao-sqlite-pro 原生 SQLite、迁移、备份与诊断 查看插件
lizhao-icon-pro SVG 图标组件、多主题与缓存 查看插件
lizhao-cast-screen DLNA 投屏、AirPlay 路由入口 查看插件
lizhao-call-kit 电话、短信、通讯录原生能力 查看插件
lizhao-app-keepalive 应用保活、唤醒、自愈与报告 查看插件
lizhao-doc-corrector 文档扫描、矫正、增强与识别 查看插件
lizhao-emu-detect 模拟器环境检测、风险评分与证据 查看插件
lizhao-gallery-pro 相册媒体分页、筛选、缩略图与导出 查看插件
lizhao-video-thumb 视频封面、批量取帧与 Base64 返回 查看插件
lizhao-ble BLE 扫描、连接、读写、通知与自动重连 查看插件
lizhao-sse-pro SSE、Line、JSONL 与 Raw 流式请求 查看插件
lizhao-pdf-pro PDF 阅读、签批、真实写回与页面处理 查看插件
lizhao-serial-port 路径串口、USB 串口、多会话收发与诊断 查看插件
lizhao-wechat-kit 微信登录、分享、支付、小程序与客服 查看插件
lizhao-video-editor 视频裁剪、压缩、取帧与 FFmpeg/FFprobe 查看插件
lizhao-vpn-pro 企业 VPN、IKEv2、安全接入与脱敏诊断 查看插件
lizhao-camera-pro 原生相机、拍照录像、水印与媒体保存 查看插件
lizhao-tcp-pro TCP 客户端、服务端、多连接与诊断 查看插件
lizhao-notify-pro 本地通知、点击动作、进度与定时提醒 查看插件

隐私、权限声明

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

Android 需要读取图片/视频媒体权限;Android 9 及以下保存媒体需要 WRITE_EXTERNAL_STORAGE;iOS 需要 NSPhotoLibraryUsageDescription 与 NSPhotoLibraryAddUsageDescription;HarmonyOS 完整相册访问需要应用通过 AGC 受限权限审核并完成用户授权。

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

插件仅在用户授权后读取本机相册媒体索引和生成本地临时文件,不上传相册内容;如使用 uploadGalleryMedia,上传地址由业务方显式传入。

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

无