更新记录
1.0.0(2026-04-29) 下载此版本
更新日志
[1.0.0] - 2025-04-29
新增
平台兼容性
uni-app(4.42)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | × | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
uni-file-upload-plugin
一个用于 uni-app 的 Android 文件选择插件,完美解决小米等 Android 手机 content:// URI 访问限制问题。
特性
- ✅ 支持 Android 平台原生文件选择
- ✅ 自动处理 content:// URI 转换(三重复制方案)
- ✅ 支持所有常见文件类型(PDF、Office、图片、音频等)
- ✅ 零依赖,纯原生实现
- ✅ 完美兼容小米、华为、OPPO、VIVO 等主流手机
- ✅ 完善的错误处理和权限管理
平台支持
| 平台 | 支持情况 | 说明 |
|---|---|---|
| Android | ✅ 完全支持 | 使用原生 Android API,三重复制方案 |
| iOS | ❌ 不支持 | 建议使用 xe-upload 等第三方组件 |
| H5 | ❌ 不支持 | 建议使用 uni.chooseFile |
| 小程序 | ❌ 不支持 | 建议使用 uni.chooseFile |
为什么需要这个插件?
在 Android 平台上,从系统文件选择器获取的文件 URI 通常是 content:// 格式,这种 URI 在某些手机(特别是小米)上存在安全访问限制,导致 uni.uploadFile 无法直接读取文件内容。
本插件通过三重复制方案将 content:// URI 指向的文件复制到应用缓存目录,完美解决这个问题:
- 方案 1:FileChannel.transferTo(OS 内核级复制,兼容鸿蒙)
- 方案 2:NIO Files.copy(Android 8.0+ / API 26+)
- 方案 3:InputStream.transferTo(Java 9+ / Android 8.0+)
安装
方式一:本地导入
- 将
uni-file-upload-plugin文件夹复制到项目根目录 - 在需要使用的页面中导入:
import {
selectFileAndroid,
getMimeTypesFromExtensions,
requestAndroidStoragePermission,
} from '@/uni-file-upload-plugin/index.js';
方式二:DCloud 插件市场
(待发布)
快速开始
基础用法
import {
selectFileAndroid,
getMimeTypesFromExtensions,
requestAndroidStoragePermission,
} from '@/uni-file-upload-plugin/index.js';
// 选择文件
async function selectFile() {
try {
// 1. 请求权限
const hasPermission = await requestAndroidStoragePermission();
if (!hasPermission) {
uni.showToast({ title: '需要文件访问权限', icon: 'none' });
return;
}
// 2. 选择文件
const mimeTypes = getMimeTypesFromExtensions(['.pdf', '.doc', '.docx']);
const result = await selectFileAndroid(mimeTypes);
console.log('文件路径:', result.filePath);
console.log('文件名:', result.fileName);
// 3. 上传文件
uni.uploadFile({
url: 'https://your-api.com/upload',
filePath: result.filePath,
name: 'file',
success: (res) => {
console.log('上传成功:', res);
},
});
} catch (error) {
console.error('选择文件失败:', error);
}
}
完整示例
<template>
<view>
<button @click="selectAndUploadFile">选择并上传文件</button>
</view>
</template>
<script setup>
import {
selectFileAndroid,
getMimeTypesFromExtensions,
requestAndroidStoragePermission,
} from '@/uni-file-upload-plugin/index.js';
const selectAndUploadFile = async () => {
try {
// 请求权限
const hasPermission = await requestAndroidStoragePermission();
if (!hasPermission) return;
// 定义允许的文件类型
const extensions = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.jpg', '.png'];
const mimeTypes = getMimeTypesFromExtensions(extensions);
// 选择文件
const { filePath, fileName } = await selectFileAndroid(mimeTypes);
// 上传文件
uni.showLoading({ title: '上传中...' });
uni.uploadFile({
url: 'https://your-api.com/upload',
filePath: filePath,
name: 'file',
formData: {
fileName: fileName,
},
success: (res) => {
uni.hideLoading();
uni.showToast({ title: '上传成功', icon: 'success' });
},
fail: (err) => {
uni.hideLoading();
uni.showToast({ title: '上传失败', icon: 'none' });
},
});
} catch (error) {
console.error('操作失败:', error);
uni.showToast({ title: '操作失败', icon: 'none' });
}
};
</script>
API 文档
selectFileAndroid(mimeTypes)
选择文件(Android 平台)
参数:
mimeTypes(Array): MIME 类型数组,如 ['application/pdf', 'image/jpeg']
返回值:
Promise<Object>:filePath(String): 本地文件路径fileName(String): 文件名
示例:
const result = await selectFileAndroid(['application/pdf']);
console.log(result.filePath); // /data/user/0/.../cache/temp_file_xxx
console.log(result.fileName); // document.pdf
getMimeTypesFromExtensions(extensions)
将文件扩展名转换为 MIME 类型
参数:
extensions(Array): 扩展名数组,如 ['.pdf', '.doc', 'docx']
返回值:
Array<String>: MIME 类型数组
支持的扩展名:
- 文档:pdf, doc, docx, xls, xlsx, ppt, pptx, txt
- 图片:jpg, jpeg, png, gif, webp
- 音频:mp3, wav, m4a, aac, ogg, flac, opus
示例:
const mimeTypes = getMimeTypesFromExtensions(['.pdf', '.doc', '.jpg']);
// 返回: ['application/pdf', 'application/msword', 'image/jpeg']
requestAndroidStoragePermission()
请求 Android 文件访问权限
返回值:
Promise<Boolean>: 是否授权成功
示例:
const hasPermission = await requestAndroidStoragePermission();
if (hasPermission) {
// 继续文件操作
}
copyContentUriToTemp(uri, fileName)
将 content:// URI 复制到临时目录(内部方法,一般不需要直接调用)
参数:
uri(Object): Android URI 对象fileName(String): 文件名
返回值:
Promise<String>: 本地文件绝对路径
常见问题
1. 为什么选择文件后上传失败?
确保已经调用 requestAndroidStoragePermission() 请求权限。
2. 支持哪些文件类型?
支持所有常见文件类型,包括:
- 文档:PDF, Word, Excel, PowerPoint, TXT
- 图片:JPG, PNG, GIF, WebP
- 音频:MP3, WAV, M4A, AAC, OGG, FLAC, OPUS
3. 为什么不支持 iOS?
iOS 平台的文件访问机制与 Android 不同,建议使用 xe-upload 等成熟的第三方组件。
4. 文件会保存在哪里?
文件会临时复制到应用缓存目录(getCacheDir()),上传完成后可以手动删除。
5. 如何限制文件大小?
在上传前检查文件大小:
const { filePath } = await selectFileAndroid(mimeTypes);
// 使用 plus.io 获取文件大小
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
entry.file((file) => {
if (file.size > 10 * 1024 * 1024) {
// 10MB
uni.showToast({ title: '文件不能超过10MB', icon: 'none' });
return;
}
// 继续上传
});
});
技术原理
三重复制方案
-
FileChannel.transferTo
- OS 内核级复制,性能最优
- 兼容鸿蒙系统
- 适用于大部分 Android 设备
-
NIO Files.copy
- Android 8.0+ (API 26+) 支持
- 标准 Java NIO API
- 兼容性好
-
InputStream.transferTo
- Java 9+ / Android 8.0+ 支持
- 最后的兜底方案
- 确保所有设备都能正常工作
插件会依次尝试这三种方案,直到成功复制文件。
更新日志
v1.0.0 (2026-04-29)
- 🎉 首次发布
- ✅ 支持 Android 平台文件选择
- ✅ 三重复制方案处理 content:// URI
- ✅ 完善的权限管理
- ✅ 支持所有常见文件类型
许可证
MIT License
作者
Your Name
反馈与贡献
如有问题或建议,欢迎提交 Issue 或 PR。

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 2
赞赏 0
下载 11763224
赞赏 1911
赞赏
京公网安备:11010802035340号