更新记录

v1.0.0(2026-05-09)

新版本


平台兼容性

uni-app(3.96)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

excel-saf-picker(UTS):Android SAF 选文件使用说明

本文面向 从插件市场安装本插件的开发者,说明环境要求、manifest 配置、UTS 插件使用方式及 API 说明。演示源码见同目录 index.vue


一、插件能力简介

  • App-Android 上通过系统 存储访问框架(SAF) 打开「打开文件」选择器,用户任选图片 / 视频 / 音频 / 文档等文件(能力取决于传入的 MIME / 分类配置)。
  • 将所选内容 拷贝到应用私有目录,得到 uni.uploadFile 可直接使用的本地路径
  • 提供两类入口:通用选文件 chooseFileFromSaf偏表格场景 chooseExcelFromSaf(默认表格 MIME + 默认 .xls/.xlsx 校验,可被 options 覆盖)。

不支持:H5、小程序、iOS;非 Android App 调用会走占位实现并 fail(如 errCode: 9001)。


二、Android 系统权限说明(集成清单)

2.1 本插件为「选文件 + 拷贝」通常不要求单独申请的权限

实现流程为:ACTION_OPEN_DOCUMENT + FLAG_GRANT_READ_URI_PERMISSION 读取用户选中的 单个 content:// Uri,再写入 getExternalFilesDir / getFilesDir 下应用专属目录。因此 一般无需 仅为本插件在 manifest 中额外声明下列权限(与是否使用本插件无直接对应关系):

权限(Android 常见常量) 说明
READ_EXTERNAL_STORAGE 不依赖扫描全盘/共享存储;读范围为用户在系统选择器里授权的那一个 Uri。
WRITE_EXTERNAL_STORAGE 不写公共下载目录等;拷贝目标为应用专属路径下的 saf_uploads/
READ_MEDIA_IMAGES / READ_MEDIA_VIDEO / READ_MEDIA_AUDIO(Android 13+) 不直接枚举相册或媒体库;选文件走 SAF,非「读媒体库」权限模型。
MANAGE_EXTERNAL_STORAGE 不需要「所有文件访问」。

注意:若你的 App 同时还做了「打开相册列表拍照选图」「遍历 DCIM」等其它能力,仍需按 Google / 国内厂商规范 单独申请 对应权限,那是 宿主业务 需求,不是本插件强制增加的权限清单

2.2 数据访问方式(隐私政策 / 应用商店问卷可引用)

  • :系统返回的 Uri,仅在本次授权下通过 ContentResolver 读取所选文件内容。
  • :流式写入应用私有或应用外部 专属 目录下的子目录,供后续 uni.uploadFile 等使用。

2.3 宿主应用常见、但不属于本插件 API 本身的权限

  • INTERNET:选完文件后若使用 uni.uploadFile、接口请求等,多数工程会配置网络权限。
  • 其它:定位、相机、推送、蓝牙等按业务在 manifest 勾选,与本插件无关。

2.4 模块(非「权限」但易混淆)

  • 若页面使用 内置原生 video 组件 播本地文件,需在 app-plus.modules 勾选 VideoPlayer 并重打基座/安装包;这与「存储权限」是两类问题。

三、购买 / 集成后需要满足的环境

项目 说明
HBuilderX 建议使用 uni_modules/excel-saf-picker/package.jsonengines.HBuilderX 要求的版本或更高(含 UTS 编译能力)。
项目类型 uni-app,Vue2 / Vue3 均可(以插件 package.jsonuni_modules.platforms.client.Vue 为准)。
运行平台 Android AppminSdkVersion 以插件内 utssdk/app-android/config.json 及工程 manifest 为准(常见 ≥ 21)。

导入插件后,工程中会出现目录:uni_modules/excel-saf-picker/


四、使用 UTS 插件必知的配置与打包

UTS 代码会在 原生层 参与编译,仅改 .vue 或只刷新前端 != 已更新原生逻辑

  1. 首次接入或升级插件版本后

    • 重新编译包含该 UTS 的工程:自定义调试基座、云打包 APK、或本地离线打包。
    • 真机调试:建议使用 「自定义调试基座」(随当前 manifestuni_modules 生成),避免与旧基座不一致。
  2. manifest.json(应用根目录)

    • 选文件 + 拷贝 能力本身见上文「二、系统权限说明」,一般不依赖额外存储读写权限。
    • 若业务页面使用 内置原生 video 组件 播放本地文件,需在 app-plusmodules 中勾选 VideoPlayer,并 重做自定义基座 / 安装新包;否则真机可能提示「打包时未添加 VideoPlayer 模块」。演示页视频预览改为系统播放器打开时可不依赖 VideoPlayer(见演示 index.vue)。
  3. 演示页路由(可选)

    • pages/项目名称/utsExcelUploadDemo/index 加入项目的 pages.json 后,方可从路由进入演示。

五、API 与调用示例

5.1 导入方式(推荐)

import { chooseFileFromSaf, chooseExcelFromSaf } from '@/uni_modules/excel-saf-picker'

路径以工程别名 @ 指向源码根目录为准;若别名不同,请改为相对路径引用 uni_modules/excel-saf-picker

5.2 通用选文件(推荐)

不强制 Excel,返回路径适用于任意所选类型(由系统与 MIME 决定可选范围)。

chooseFileFromSaf({
  success: (res) => {
    // res.path / res.name / res.size / res.mimeType / res.ext
    uni.uploadFile({
      url: 'https://your-api.example.com/upload',
      filePath: res.path,
      name: 'file',
      header: { /* 鉴权等 */ },
      formData: {
        clientMimeType: res.mimeType || '',
        clientExt: res.ext || '',
        originalName: res.name || ''
      }
    })
  },
  fail: (err) => {
    console.error(err.errCode, err.errMsg)
  },
  complete: (res) => { /* 成功或失败都会回调 */ }
})

5.3 按「大类」动态限制可选类型(可选)

通过 categories 组合 image / video / audio / documentdoc 同 document),不传且未传 mimeTypes 时等价于四类全开。

chooseFileFromSaf({
  categories: ['image', 'document'], // 示例:仅希望放开图片与文档相关 MIME
  success: (res) => { /* ... */ },
  fail: (err) => { /* ... */ }
})

注意:系统 SAF 左侧侧栏由 ROM 决定,不能保证只显示你勾选的类别;多类(如「音频 + 文档」)并存时侧栏四项仍可能全部出现,插件主要通过 MIME 列表 约束最终可选文件类型。仅 单一大类(如只要 audio)时,部分机型界面更容易收窄。

5.4 完全自定义 MIME(可选)

categories 同时传时,mimeTypes 为准(将忽略 categories):

chooseFileFromSaf({
  mimeTypes: ['application/pdf', 'image/png'],
  success: (res) => { /* ... */ }
})

5.5 后缀白名单(可选)

allowedExts 非空时,拷贝前按显示文件名后缀校验(小写带点,如 .pdf)。chooseFileFromSaf 不传则不校验;chooseExcelFromSaf 不传则默认仅允许 .xls.xlsx

5.6 仅 Excel 场景

import { chooseExcelFromSaf } from '@/uni_modules/excel-saf-picker'

chooseExcelFromSaf({
  success: (res) => { /* ... */ },
  fail: (err) => { /* ... */ }
})

chooseExcelFromSaf 不使用 categories,默认使用表格相关 MIME 及 .xls/.xlsx 校验;可用 mimeTypes / allowedExts 覆盖。


六、success 返回字段

字段 类型 说明
path string 已拷贝后的绝对路径,可直接作为 uni.uploadFilefilePath
name string 展示用文件名(含后缀),已做简单安全处理
size number 字节数
mimeType string ContentResolver.getType(uri),可能为空字符串
ext string 小写带点后缀,如 .xlsx;无法识别时可能为空

七、failerrCode(节选)

errCode 含义
1001 当前 Activity 不可用
1002 用户取消选择
1003 返回 URI 为空
1004 无法打开输入流
1005 拷贝失败
1006 后缀不在 allowedExts 白名单
1007 categories 无效或未展开出任何 MIME
1099 其它异常
9001 非 Android App(Web 等占位实现)

八、拷贝后文件位置(调试)

拷贝目录位于应用外部私有目录(随系统与包名略有差异),形如:

/Android/data/<应用包名>/files/saf_uploads/<时间戳>/<文件名>

上传完成后可按业务需要自行删除临时文件以节省空间。


九、大文件上传建议

uni.uploadFile 默认超时可能较短;视频等大文件建议在调用侧 增大 timeout(毫秒),并在弱网下做好重试与进度提示(演示 index.vue 中有可参考示例)。


十、演示页

说明
文件 pages/项目名称/utsExcelUploadDemo/index.vue
路由 path pages/项目名称/utsExcelUploadDemo/index

演示包含:categories 勾选、chooseFileFromSaf + uni.uploadFile、按类型预览(App 端视频可走系统播放器)、日志区。


十一、依赖与声明

详见 uni_modules/excel-saf-picker/package.jsondcloudext.declaration(数据、广告、权限说明等)。若上架插件市场,发布者应以实际审核要求核对并更新该声明。

十二、文档演示页面在本地,如需要,我再更新文档进行演示代码展示

隐私、权限声明

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

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

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

暂无用户评论。