更新记录

V1.2.2(2026-05-29) 下载此版本

新增

  • 新增 saveDirName,支持自定义保存目录,例如 Download/HugeAuto/文件名
  • 新增 saveLocation: 'sandbox',用于兼容保存到 APP 沙盒目录的场景。
  • 新增 debug 调试参数,可打印 Base64 转换、文件写入、文件校验等耗时日志。
  • 新增文件名后缀自动补齐能力,可根据 mime测试文档 自动保存为 测试文档.pdf

修复

  • 修复 APP 端保存较大 ArrayBuffer 文件时可能出现空文件的问题。
    • 典型报错:文件大小不一致:expect=xxx, actual=0
  • 修复 Android 使用 _downloads/ 时文件实际保存到 Android/data/包名/downloads 私有目录,用户在文件管理器中不易找到的问题。
  • 修复部分 Android/HBuilder 环境公共下载目录解析为空,导致 getAbsolutePath of null 的问题。
  • 修复部分 Android/HBuilder 环境查询 DownloadManager 状态时 cursor.moveToFirst is not a function 的兼容问题。

优化

  • Android appAction: 'save' 默认保存到系统公共 Download/下载 目录。
  • 在线 URL 保存优先使用系统下载能力,适合 CDN/OSS 等远程文件。
  • 接口文件流保存使用 ArrayBuffer -> Base64 -> 分片写入,提升大文件保存稳定性。
  • 移除逐字节 JS -> Native 写入兜底,避免 1MB+ 文件保存耗时过长。
  • 保持原有分享逻辑兼容:旧代码不传 appAction 时仍默认走系统分享。

V1.2.1(2026-05-28) 下载此版本

  • 修复部分 APP 环境中较大 ArrayBuffer 调用 uni.arrayBufferToBase64 后可能得到空内容,导致保存时报 文件大小不一致:actual=0 的问题。
  • 新增 ArrayBuffer 转 Base64 分片兜底逻辑。
  • 新增 Base64 字节长度校验,避免空文件被写入。

V1.2.0(2026-05-21) 下载此版本

1.新增 appAction 参数。 2.share:保持原来的 APP 系统分享逻辑。 3.save:APP 只保存文件,不打开分享面板。 4.Android 保存前增加存储权限检查。 5.保存成功后返回 path / localPath / filename / size / action。 6.新增 saveDirName,可以控制保存文件夹名。

查看更多

平台兼容性

uni-app(4.87)

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

文件下载与系统分享

版本说明:1.2.2

功能特点

  • 支持 ArrayBuffer 文件流下载、分享、保存。
  • 支持在线文件 URL 下载、分享、保存。
  • 支持图片、视频、PDF、Excel、Word、ZIP 等常见文件类型。
  • 兼容 H5、Android、iOS。
  • 旧代码不传 appAction 时仍默认调起 APP 系统分享。
  • Android 支持 FileProvider 系统分享。
  • Android 保存模式支持公共 Download/下载 目录。
  • 保存成功后返回文件路径、相对路径、文件名、文件大小。

引入方式

import {
  downloadOrShareArrayBuffer,
  downloadOrShareByUrl,
  shareOnlineImage,
  shareOnlineVideo,
  shareResource,
  getResourceTypeByFilename
} from '@/utils/download-share'

请按你的实际插件安装路径调整导入地址。


核心参数

appAction

APP 端新增 appAction 参数,用来控制 APP 环境下的行为。

参数值 说明
share 默认值。APP 端写入临时文件后调起系统分享
save APP 端只保存到手机文件管理,不调起系统分享

不传 appAction 时,默认仍然是 share,原有分享代码无需修改。

常用 options

字段 类型 必填 默认值 说明
appAction string share APP 端行为:share / save
filename string 自动推断 在线 URL 保存/分享时使用的文件名
mime string 根据文件名推断 文件 MIME 类型
chooserTitle string 分享文件 系统分享面板标题,仅 share 时有效
saveDirName string file_save 保存到手机文件管理时的文件夹名称
shareDirName string share_temp 系统分享临时目录名称
saveLocation string public Android 保存位置;传 sandbox 可保存到旧沙盒目录
debug boolean false 是否打印保存耗时日志
androidBase64ChunkSize number 1024 * 1024 Android Base64 分片大小
androidWriteBufferSize number 512 * 1024 Android 写入缓冲区大小

返回值

{
  platform: 'H5' | 'Android' | 'iOS',
  action: 'download' | 'share' | 'save',
  path: string,
  localPath: string,
  filename: string,
  size: number,
  isPublic: boolean
}
字段 说明
platform 当前处理平台
action 当前执行动作
path APP 端为本地绝对路径;H5 场景为空或原始地址
localPath 本地相对路径,例如 Download/HugeAuto/test.pdf
filename 最终文件名,可能会根据 mime 自动补后缀
size 文件大小,单位 byte
isPublic 是否保存到 Android 公共下载目录

方法说明

1. downloadOrShareArrayBuffer(buffer, filename, options)

处理接口返回的二进制文件流。

downloadOrShareArrayBuffer(buffer, filename, options)

常用于:接口导出 Excel、前端生成 PDF、接口返回 PDF/Word/ZIP 文件流。

2. downloadOrShareByUrl(url, options)

处理在线文件地址。

downloadOrShareByUrl(url, options)

常用于:OSS/CDN 文件、在线 PDF、在线图片、在线视频。

3. shareOnlineImage(url, options)

处理在线图片。

shareOnlineImage(url, options)

4. shareOnlineVideo(url, options)

处理在线视频。

shareOnlineVideo(url, options)

5. shareResource(params)

统一入口,内部根据 bufferurl 自动选择处理方式。

shareResource(params)

使用示例

一、APP 默认系统分享

不传 appAction,默认系统分享。

await downloadOrShareArrayBuffer(buffer, '报表.xlsx', {
  mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  chooserTitle: '分享Excel'
})

二、保存接口文件流到手机文件管理

const result = await downloadOrShareArrayBuffer(buffer, '测试文档.pdf', {
  appAction: 'save',
  saveDirName: 'HugeAuto',
  mime: 'application/pdf'
})

console.log('保存路径:', result.path)
console.log('本地相对路径:', result.localPath)
console.log('文件大小:', result.size)

Android 公共目录返回示例:

{
  platform: 'Android',
  action: 'save',
  path: '/storage/emulated/0/Download/HugeAuto/测试文档.pdf',
  localPath: 'Download/HugeAuto/测试文档.pdf',
  filename: '测试文档.pdf',
  size: 589238,
  isPublic: true
}

三、保存在线 PDF 到手机文件管理

const result = await downloadOrShareByUrl(
  'https://example.com/test.pdf',
  {
    filename: '测试文档',
    appAction: 'save',
    saveDirName: 'HugeAuto',
    mime: 'application/pdf',
    debug: true
  }
)

console.log('保存路径:', result.path)

如果 filename 没有 .pdf 后缀,插件会根据 mime 自动补齐,最终保存为:

测试文档.pdf

四、APP 系统分享在线 PDF

await downloadOrShareByUrl('https://example.com/test.pdf', {
  appAction: 'share',
  filename: '说明文档.pdf',
  mime: 'application/pdf',
  chooserTitle: '分享PDF'
})

五、保存在线视频

const result = await shareOnlineVideo('https://example.com/test.mp4', {
  appAction: 'save',
  saveDirName: 'HugeAuto',
  filename: '演示视频.mp4'
})

console.log('视频保存路径:', result.path)

六、统一入口:保存文件流

const result = await shareResource({
  buffer,
  filename: '报表.xlsx',
  appAction: 'save',
  saveDirName: 'HugeAuto',
  mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})

console.log(result.path)

七、统一入口:保存在线文件

const result = await shareResource({
  url: 'https://example.com/test.pdf',
  filename: '文档.pdf',
  appAction: 'save',
  saveDirName: 'HugeAuto',
  mime: 'application/pdf'
})

console.log(result.path)

uni-app 页面示例

<script setup>
import {
  downloadOrShareArrayBuffer,
  downloadOrShareByUrl
} from '@/utils/download-share'

const handleSaveExcel = async () => {
  try {
    const res = await uni.request({
      url: 'https://example.com/export',
      method: 'GET',
      responseType: 'arraybuffer'
    })

    const result = await downloadOrShareArrayBuffer(res.data, '报表.xlsx', {
      appAction: 'save',
      saveDirName: 'HugeAuto',
      mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      debug: true
    })

    uni.showToast({
      title: '保存成功',
      icon: 'success'
    })

    console.log('保存路径:', result.path)
  } catch (e) {
    uni.showToast({
      title: e.message || '保存失败',
      icon: 'none'
    })
  }
}

const handleSaveOnlinePdf = async () => {
  try {
    const result = await downloadOrShareByUrl(
      'https://example.com/test.pdf',
      {
        filename: '测试文档',
        appAction: 'save',
        mime: 'application/pdf',
        debug: true
      }
    )

    console.log('保存路径:', result.path)
  } catch (e) {
    uni.showToast({
      title: e.message || '保存失败',
      icon: 'none'
    })
  }
}

const handleSharePdf = async () => {
  try {
    await downloadOrShareByUrl('https://example.com/test.pdf', {
      appAction: 'share',
      filename: '说明文档.pdf',
      mime: 'application/pdf',
      chooserTitle: '分享PDF'
    })
  } catch (e) {
    uni.showToast({
      title: e.message || '分享失败',
      icon: 'none'
    })
  }
}
</script>

保存路径说明

Android

appAction: 'save' 默认保存到系统公共下载目录:

/storage/emulated/0/Download/file_save/文件名

自定义目录:

const result = await downloadOrShareByUrl(url, {
  appAction: 'save',
  saveDirName: 'HugeAuto',
  filename: '测试文档.pdf',
  mime: 'application/pdf'
})

预期路径:

/storage/emulated/0/Download/HugeAuto/测试文档.pdf

如果需要使用沙盒目录:

const result = await downloadOrShareByUrl(url, {
  appAction: 'save',
  saveLocation: 'sandbox',
  filename: '测试文档.pdf',
  mime: 'application/pdf'
})

沙盒路径通常类似:

/storage/emulated/0/Android/data/应用包名/downloads/file_save/测试文档.pdf

iOS

appAction: 'save' 默认保存到 _doc 沙盒目录。iOS 如果希望用户在系统「文件」App 中直接看到文档,需要原生侧开启文件共享相关配置。


大文件保存说明

保存接口文件流时,APP 端会对 ArrayBuffer 做可靠转换与分片写入,主要解决:

文件大小不一致:expect=xxx, actual=0

优化了写入逻辑,避免大文件保存非常慢。

建议保存前检查:

console.log('buffer size:', buffer?.byteLength)

如果开启调试:

const result = await downloadOrShareArrayBuffer(buffer, filename, {
  appAction: 'save',
  mime: 'application/pdf',
  debug: true
})

控制台会输出 Base64 转换、文件写入、文件校验等耗时信息,便于判断慢点是在文件生成、转换还是写入。


MIME 参考

文件类型 MIME
PDF application/pdf
XLSX application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
XLS application/vnd.ms-excel
DOCX application/vnd.openxmlformats-officedocument.wordprocessingml.document
DOC application/msword
PPTX application/vnd.openxmlformats-officedocument.presentationml.presentation
PPT application/vnd.ms-powerpoint
ZIP application/zip
TXT text/plain
CSV text/csv
PNG image/png
JPG/JPEG image/jpeg
WEBP image/webp
MP4 video/mp4
MOV video/quicktime

权限说明

Android

Android 10+ 保存到公共 Download/下载 目录时,插件优先使用系统公共下载/媒体存储能力。

Android 9 及以下如需写入外部公共目录,通常需要在 manifest.json 或原生工程中配置:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

插件在 APP 端保存时会尽量执行权限检查;最终是否成功以实际写入和文件校验结果为准。

iOS

iOS 无强制存储权限。插件默认写入 App 沙盒目录。


常见问题

Q1:以前的分享代码要不要加 appAction: 'share'

不需要。不传 appAction 默认就是 share

Q2:appAction: 'save' 会不会弹出系统分享?

不会。save 只保存文件并返回路径。

Q3:在线地址和接口文件流保存后效果一样吗?

效果一致,都会保存到手机文件管理并返回路径。内部实现不同:在线地址优先走系统下载能力,接口文件流走 ArrayBuffer 分片写入。

Q4:保存成功后能不能直接跳转到文件夹?

不建议。UniApp 没有稳定的标准 API 可以直接打开文件管理器并定位到目录。建议保存成功后展示路径,或提供“复制路径 / 打开文件”的交互。

Q5:保存成功后怎么打开文件?

APP 端可以尝试打开具体文件:

// #ifdef APP-PLUS
plus.runtime.openFile(result.path, {}, () => {
  uni.showToast({
    title: '未找到可打开此文件的应用',
    icon: 'none'
  })
})
// #endif

Q6:保存失败怎么办?

建议这样捕获:

try {
  const result = await downloadOrShareByUrl(url, {
    appAction: 'save',
    filename: 'test.pdf',
    mime: 'application/pdf'
  })

  console.log(result.path)
} catch (e) {
  console.error('保存失败:', e)

  uni.showToast({
    title: e.message || '保存失败',
    icon: 'none'
  })
}

注意事项

  1. 保存 PDF 建议传 mime: 'application/pdf'
  2. 保存 Excel 建议传对应 Excel MIME。
  3. 接口返回文件流时必须设置 responseType: 'arraybuffer'
  4. 建议保存按钮增加 loading,避免重复点击导致同名文件并发写入。
  5. URL 文件必须可正常访问,否则下载会失败。
  6. 系统分享依赖 Android 原生 FileProvider 配置,如果分享失败,请检查原生工程配置。
  7. iOS 保存目录与 Android 不同,默认是 App 沙盒目录。

隐私、权限声明

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

Android READ_MEDIA_FILES WRITE_MEDIA_FILES READ_EXTERNAL_STORAGE(仅 targetSdk < 33 时可选) iOS 无强制权限(文件写入 _doc 属于App沙盒)

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

1)采集的数据 本插件采集/处理: 宿主App下载接口返回的 ArrayBuffer 文件名称 filename 系统类型 plus.os.name 2)发送的服务器地址 本插件自身不主动请求服务器,仅处理宿主App提供的接口数据。 示例宿主调用地址: https://<宿主业务域名>/version/specs/share 真实服务器地址由使用方在App中配置,本插件不内置固定域名。 3)数据用途 用途说明: 数据 用途 ArrayBuffer 还原原始文档 filename 创建文件 平台类型 选择分享方式 不会: 采集设备IMEI/OAID 不发送任何隐私信息 不包含行为追踪

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

许可协议

MIT License

Copyright (c) 2026

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.