uni.chooseFile在App端实际调用相册而非文件管理器,需通过原生API(Android用ACTION_GET_CONTENT、iOS用UIDocumentPickerViewController)获取真实路径,并用uni.getFileSystemManager.readFile读取后上传。

uni.chooseFile 在 App 端根本不会打开系统文件管理器
直接调用 uni.chooseFile({ type: 'file' }) 在 Android 或 iOS 的 App 端,实际唤起的是相册/媒体库,不是你想要的“文件管理器”(如系统自带的“文件”App 或第三方 ES 文件浏览器)。这是最常被误判的起点——你以为选了“file”,就进了文件系统,其实只是媒体沙盒。
原因很实在:uni-app 封装层在 App 平台默认走的是原生相册 API(UIImagePickerController / Intent.ACTION_PICK),而非通用文档选择器。要突破这个限制,必须绕过封装,直连原生能力。
- Android 必须用
Intent.ACTION_GET_CONTENT(推荐)或Intent.ACTION_OPEN_DOCUMENT,并显式设置intent.setType("*/*")或具体 MIME 类型(如"application/pdf") - iOS 必须用
UIDocumentPickerViewController,且需在manifest.json中配置NSDocumentPickerUsageDescription权限说明 - 返回的
uri是content://或file:///private...格式,不能直接当路径传给uni.uploadFile
Android 端用 plus.android 调起系统文件选择器并解析真实路径
核心是两步:启动 Intent → 拿到 content:// URI 后解析出可读的真实文件路径。HBuilderX 3.9.12+ 提供了 plus.android.resolveNativeUri(),但低版本或特殊 ROM(如华为 EMUI、小米 MIUI)仍可能失败,建议保留 fallback 解析逻辑。
关键注意事项:
- manifest.json 中必须开启
READ_EXTERNAL_STORAGE权限(Android 10+ 建议同时设requestLegacyExternalStorage: true) -
intent.addCategory(Intent.CATEGORY_OPENABLE)必须加,否则部分 ROM(如三星)会报错或无响应 - 不要依赖
cursor.getString(cursor.getColumnIndex("_data"))—— Android 10+ 已废弃该字段,应改用DocumentFile.fromSingleUri()+getUri()+openInputStream()流式读取(若需兼容旧版,可用plus.io.resolveLocalFileSystemURL())
简短示意(仅关键逻辑):
const Intent = plus.android.importClass('android.content.Intent');
const intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType('*/*');
intent.addCategory(Intent.CATEGORY_OPENABLE);
plus.android.startActivityForResult(intent, (intentData) => {
if (intentData) {
const uri = intentData.getData();
// ✅ 优先用新 API(HBuilderX ≥ 3.9.12)
const realPath = plus.android.resolveNativeUri(uri);
// ❌ 不要直接用 uri.toString() 或 getPath()
}
});
iOS 端必须用 UIDocumentPickerViewController,且路径不能直接上传
iOS 没有“全局文件管理器”的概念,UIDocumentPickerViewController 只能选 iCloud 或“文件”App 中用户授权的目录。它返回的是临时可读的 file:// URL,但该路径带随机 UUID,且有效期极短(通常仅本次运行内有效)。
常见错误操作:
- 把返回的
file://路径直接塞进uni.uploadFile({ filePaths: [...] })→ 报错no permission或空内容 - 未在
manifest.json的ios > permissions下添加NSDocumentPickerUsageDescription→ 应用闪退或静默失败 - 未在 Xcode 工程中开启
Supports Document Browser和Ubiquity Container Identifiers(真机调试必需)
正确做法是:用 uni.getFileSystemManager().readFile() 读取二进制内容,再转成 base64 或 Blob 上传;或更稳妥地,用 plus.ios.invoke() 获取原生 NSData 对象后交给原生模块处理。
上传前必须用 uni.getFileSystemManager 读取,别碰 uni.readFile
uni.readFile 在 App 端只认 uni.uploadFile 或 uni.downloadFile 生成的临时路径,对 chooseMessageFile 或原生返回的真实路径完全无效。直接调用只会返回空或权限错误。
唯一可靠方式是:
- 用
uni.getFileSystemManager()(App 端专属)调readFile({ filePath, encoding: 'base64' })→ 得到 base64 字符串,适合小文件( - 或用
plus.io.resolveLocalFileSystemURL(filePath)→ 返回Entry对象,再调file()方法获取Blob,配合uni.uploadFile的fileType: 'blob'(需 HBuilderX ≥ 3.8.0) - 大文件(>10MB)务必分片上传,避免内存溢出;iOS 上尤其注意,
readFile读大文件极易触发 OOM
容易忽略的一点:所有通过原生方式拿到的路径,都必须做存在性校验(plus.io.isFile())和可读性校验(plus.io.canRead()),某些 ROM 或越狱设备会返回不可访问路径。


















