更新记录
1.0.1(2026-09-29) 下载此版本
- 插件更名为
file-downloader,面向插件市场发布(功能与内部版本 lv-downloader 一致) downloadToPublic增加扩展名补全:保存文件名无扩展名时,优先取 URL 中的扩展名;两者都没有时兜底.docx- 修复下载无扩展名接口(如
downfile?type=...、服务端 Content-Type 返回 text/html)导致落盘文件无后缀被识别为 txt 的问题
平台兼容性
uni-app(3.8.4)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | √ | 6.0 | 12 | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
file-downloader 文件下载(保存到系统公共目录)
下载网络文件(URL)并保存到系统公共目录,支持 Android / iOS 双端。文件不落隐藏目录、不落应用沙盒缓存,用户在系统「文件管理 / 文件 App」中可直接查看。
- Android:保存到公共
Download目录(Android 10+ 基于 MediaStore,免存储权限静默保存) - iOS:保存到
Documents目录,保存成功后自动弹出系统分享面板,选「存储到文件」可存到任意位置
适配 uni-app Vue2(webpack 编译) 项目,同时兼容 Vue3。UTS 原生层(utssdk/)与 Vue 版本无关;JS 调用层为 ES5 风格,兼容 Vue2 老 babel 配置。
本插件基于 lvxiaowu 项目的 lv-downloader 1.2.1 重写并适配 Vue2,在此感谢原作者。
功能特性
- 一行代码下载网络文件到系统公共目录,带实时进度回调
- Android 10+ 免存储权限、无弹窗静默保存;Android 9 及以下自动申请存储权限
- iOS 保存后自动弹系统分享面板(含「存储到文件 / AirDrop / 微信」等入口)
- 支持自定义请求头(token 鉴权下载)、超时时间、公共目录下子目录
- 自动解析/过滤文件名非法字符;无扩展名时自动补全(优先取 URL 扩展名,兜底
.docx) - 支持中断下载;支持把应用沙盒内已有本地文件转存到公共目录
环境要求
- HBuilderX
3.6.5+ - 必须使用自定义基座或正式打包(标准基座不含 UTS 插件):运行 → 运行到手机或模拟器 → 制作自定义调试基座
快速开始
import { downloadToPublic } from '@/uni_modules/file-downloader/js_sdk/index.js'
const { promise, abort } = downloadToPublic({
url: 'https://example.com/files/report.docx',
fileName: '检测报告.docx', // 可选,默认从 URL 提取
headers: { Authorization: 'Bearer xxx' }, // 可选,鉴权下载
subDir: 'myDocs', // 可选,公共目录下的子目录
: function (progress, received, total) {
console.log('进度 ' + progress + '%(' + received + '/' + total + ')')
}
})
promise.then(function (res) {
uni.showToast({ title: '已保存到:' + res.path, icon: 'none' })
}).catch(function (err) {
uni.showToast({ title: err.message, icon: 'none' })
})
// 需要中断下载时
// abort()
把应用沙盒内已有的本地文件(缓存文件、生成的文件等)转存到公共目录:
import { saveFileToPublic } from '@/uni_modules/file-downloader/js_sdk/index.js'
saveFileToPublic('_doc/temp/report.pdf', '检测报告.pdf').then(function (res) {
console.log('已保存到', res.path)
})
双端保存位置
| 平台 | 保存位置 | 用户如何看到 | 是否弹窗 | 权限 |
|---|---|---|---|---|
| Android | /storage/emulated/0/Download/<subDir>/ |
文件管理 → 下载 | 否(静默) | Android 10+ 免权限;Android 9- 自动申请存储权限 |
| iOS | 应用 Documents/<subDir>/ |
保存成功后自动弹系统分享面板,选「存储到文件」可存到任意位置 | 保存后弹系统面板 | 无 |
iOS 系统没有全局公共下载目录,Apple 官方规定的对外公开位置就是 Documents(如需在「文件」App 中直接查看,需在 manifest.json 开启
UIFileSharingEnabled,见下文配置)。
API
downloadToPublic(options) → { promise, abort }
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
options.url |
String | 是 | 网络文件地址 |
options.fileName |
String | 否 | 保存文件名(含扩展名),默认从 URL 提取,自动过滤非法字符;无扩展名时自动补全:优先取 URL 扩展名,都没有则兜底 .docx |
options.headers |
Object | 否 | 附加请求头(token 鉴权下载) |
options.subDir |
String | 否 | 公共目录下的子目录,默认存根目录 |
options.timeout |
Number | 否 | 下载超时毫秒,默认 60000 |
options.onProgress |
Function | 否 | 进度回调 (progress, receivedBytes, totalBytes) |
promiseresolve 值:{ path: 公共目录最终路径, fileName: 文件名 }abort()中断下载,promise 会 reject「已取消下载」
saveFileToPublic(path, fileName, subDir) → Promise
把应用沙盒内的本地文件转存到公共目录,参数同上。
manifest.json 配置
Android 权限(Android 9 及以下兜底需要)
"app-plus": {
"distribute": {
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" android:maxSdkVersion=\"28\"/>"
]
}
}
}
Android 10+ 走 MediaStore,无需存储权限;
maxSdkVersion=28保证不会因此多弹权限申请。⚠️ 注意:部分云打包服务会自动注入不带属性的
android.permission.WRITE_EXTERNAL_STORAGE(来自 App 运行时/已选模块/云原生插件)。若再手动声明带maxSdkVersion="28"的同名权限,Gradle Manifest Merger 可能因属性不一致报duplicated错误导致打包失败。遇到该错误时请移除手动声明,自动注入的声明已足够 Android 9 及以下的运行时权限申请。
iOS「文件」App 可见(可选)
"app-plus": {
"distribute": {
"ios": {
"UIFileSharingEnabled": true,
"LSSupportsOpeningDocumentsInPlace": true
}
}
}
配置后用户在系统「文件」App →「我的 iPhone」→ 应用名下即可直接看到下载的文件,也可通过 iTunes/AirDrop 分享。
实现原理
JS 层(js_sdk/index.js) UTS 层(utssdk/*/index.uts)
┌─────────────────────────┐ ┌──────────────────────────────┐
│ uni.downloadFile 下载到 │ 沙盒路径 │ saveFileToPublicDir: │
│ 沙盒临时目录(带进度回调)│ ────────→ │ Android: MediaStore → Download│
│ 解析文件名/MIME │ │ iOS: NSFileManager → Documents│
└─────────────────────────┘ └──────────────────────────────┘
- Android:API 29+ 用
MediaStore.Downloads插入记录并流式拷贝(512KB 缓冲,io 线程执行),文件秒级出现在系统「下载」;API 28 及以下直接写Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS),运行时自动申请权限 - iOS:
FileManager把文件从缓存目录拷到 Documents(同名覆盖);保存成功后 UTS 层直接弹UIActivityViewController系统分享面板(NSURL.fileURLWithPath传真实文件),用户选「存储到文件」可存到任意位置。不走plus.share.sendWithSystem——其type:'file'无法稳定识别文件类型,会退化成文本分享(存出内容为路径字符串的 txt)
Vue2 / Vue3 兼容说明
| 项目 | 说明 |
|---|---|
| Vue 版本 | Vue2(webpack 编译)与 Vue3(vite 编译)均支持 |
| 条件编译宏 | #ifdef APP-PLUS(Vue2/webpack 老编译器可靠识别) |
| js_sdk 语法 | ES5 风格 function + var(无默认参数、可选链),兼容 Vue2 老 babel 配置 |
| HarmonyOS | 不支持(UTS 原生层仅 Android / iOS) |
错误码
| code | 平台 | 说明 |
|---|---|---|
| 2000 | Android | 写入异常(IO/权限) |
| 2001-2003 | Android | 权限申请失败 |
| 3001 | iOS | 读取沙盒源文件失败 |
| 3002 | iOS | 写入 Documents 失败 |
常见问题
- 点了没反应 / 提示「当前环境不支持」:用的是标准基座。UTS 插件必须自定义基座或正式打包。
- iOS 保存后弹出的系统面板:保存到 Documents 成功后自动弹出,选「存储到文件」即可存到任意位置(我的 iPhone 任意文件夹 / iCloud)。若在面板中取消,文件仍保留在 App 的 Documents 中——需打包时启用
UIFileSharingEnabled才会在「文件 App → 我的 iPhone → 应用名」中显示。 - Android 9 及以下保存失败:检查 manifest 权限声明(含
maxSdkVersion="28"),并确认用户在权限弹窗中点了允许。 - 同名文件:双端均直接覆盖同名旧文件。
- 小程序端 / H5 端:不支持,调用会 reject「当前环境不支持保存到公共目录」,请自行用各自平台的保存方案。
- 文件无扩展名:
fileName未传扩展名时会自动补全——优先取 URL 中的扩展名,都没有则兜底.docx;建议调用时显式传入完整文件名。
目录结构
uni_modules/file-downloader
├── package.json
├── readme.md
├── changelog.md
├── js_sdk/index.js # JS 调用层:下载编排 + 进度 + 文件名解析(Vue2 适配)
└── utssdk
├── interface.uts # 跨平台类型定义
├── app-android/index.uts # Android:MediaStore / 直接写入
└── app-ios/index.uts # iOS:NSFileManager → Documents

收藏人数:
下载插件并导入HBuilderX
赞赏(0)
下载 19
赞赏 0
下载 12648765
赞赏 1953
赞赏
京公网安备:11010802035340号