更新记录

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 位置需显式开启并满足系统权限
相册刷新、增量备份 变化监听、持久化增量游标 监听依赖进程存活;游标在业务处理成功后推进

下载与导入

宿主 示例代码位置
uni-app uni_modules/lizhao-gallery-pro/example/uniapp/galleryPro.vue
uni-app x uni_modules/lizhao-gallery-pro/example/uniappx/index.uvue

从基础到进阶

基础功能配置示例(简单示例)

用途:申请权限并读取第一批媒体;前置:已导入插件,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 页面、uni-app x 页面 视频列表
相册 相册读取授权 同上两种宿主页面 截图相册及封面
处理 已取得真实媒体 ID 同上两种宿主页面 不复用缓存的视频参数
输出 用户确认导出或保存 同上两种宿主页面 不生成 poster 并保存
管理 当前任务不再使用待清理缓存 同上两种宿主页面 清理元数据缓存

媒体:只读取视频列表

用途:为视频素材页读取一页数据;前置:视频读取授权。宿主: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

示例与平台接入

宿主 页面语法 完整操作页面 阅读方式
uni-app Vue2/Vue3 页面 uni_modules/lizhao-gallery-pro/example/uniapp/galleryPro.vue 从媒体页签开始,按需使用相册、处理、输出和管理
uni-app x UTS 页面 uni_modules/lizhao-gallery-pro/example/uniappx/index.uvue 使用强类型参数,公开方法与 uni-app 相同
平台 使用范围 接入条件
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 小红书图文视频分享与回执诊断 查看插件

隐私、权限声明

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

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

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

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

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

无