最近需要在 APP 中实现文件的导出功能,研究了有一会的将文件保存到用户目录,并打开文件预览。为了防止后续再次踩坑,所以快速记录一下配置方式。
文件读写授权
在 uniapp 中要首先 IOS 和 Android 将文件保存到用户本地目录, 首先需要在 manifest.json 配置文件读写权限, 如果不配置读写权限则会保存到 Android 的包名路径/ IOS 容器路径中
json
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>"
]
}
"apple": {
"plistcmds": [
"Set :NSFileProviderDomainUsageDescription 需要访问文件以保存用户数据",
"Set :UIFileSharingEnabled true",
"Set :LSSupportsOpeningDocumentsInPlace true"
]
}
在 Android 下, 需要明确指定以 file://storage/emulated/0/
为开头的文件路径,才能保存到本地目录。而在 IOS 中, 可以直接指定 _doc
目录
文件下载保存并打开
为了放置文件重复保存, 建议先使用 resolveLocalFileSystemURL 首先判断一下文件是否下载过了, 如果文件已经存在, 那么就直接执行例如文件打开的操作
如果文件不存在, 就使用 plus.downloader.createDownload 将文件下载到指定的目录,再使用 plus.io.convertLocalFileSystemURL 将下载文件转为平台路径,最后在执行例如文件打开的操作
javascript
/**
* 保存并打开文件
* @param url 文件网络地址
*/
async function saveFile(url: string) {
const fileName = url.split("/").pop()?.split("?")[0];
console.log(url);
// #ifdef APP-PLUS
let realAbs = "";
const platform = uni.getSystemInfoSync().platform;
if (platform === "ios") {
realAbs = "_doc";
}
if (platform === "android") {
let granted = await permision.requestAndroidPermission(
"android.permission.WRITE_EXTERNAL_STORAGE"
);
if (granted === GrantedStatusEnum.GRANTED) {
realAbs = "file://storage/emulated/0/Download";
} else {
// 文件保存到 /Download
realAbs = "_downloads";
notify.showNotify({
message: `未能授权文件权限,文件将临时保存`,
type: "danger",
});
}
}
// 平台路径
const relPath = `${realAbs}/${fileName}`;
// 文件判存
plus.io.resolveLocalFileSystemURL(
relPath,
async () => {
console.log("[saveFile] 文件已存在,直接打开");
if (platform === "android") {
await uni.showToast({
title: `文件已保存至: /Download/${fileName}`,
icon: "none",
});
}
openDocument(relPath);
},
() => {
console.log("[saveFile] 文件不存在,开始下载");
const task = plus.downloader.createDownload(
url,
{ filename: relPath },
async (d, status) => {
if (status === 200) {
if (platform === "android") {
await uni.showToast({
title: `文件已保存至: /Download/${fileName}`,
icon: "none",
});
}
const realAbs = plus.io.convertLocalFileSystemURL(d.filename);
openDocument(realAbs);
} else {
notify.showNotify({
message: `文件导出失败, 请稍后重试`,
type: "danger",
});
}
}
);
task.start();
}
);
// #endif
// #ifdef H5
location.href = url;
// #endif
}
function openDocument(absPath: string) {
plus.runtime.openFile(absPath, {}, (res) => {
if (res.code === -1) {
notify.showNotify({
message: "无法打开文件,请检查是否安装对应应用",
type: "danger",
});
}
});
}
结束语
目前 IOS 的保存路径还没弄清楚,现在 IOS 需要文件预览打开后手动保存一次。指定 _downloads
似乎没有生效,可能需要手动请求一次权限才能完成写入,所以这里先投机取巧写入了 _doc
, 等后续有时间研究好了再完善这个权限配置。