Uniapp IOS 和 Android 下的文件写入用户目录

最近需要在 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, 等后续有时间研究好了再完善这个权限配置。

相关推荐
毕设十刻21 小时前
基于Vue的企业管理系统pk6uy(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
276695829221 小时前
雷池waf 逆向
java·开发语言·前端·python·wasm·waf·雷池waf
w***488221 小时前
解决报错net.sf.jsqlparser.statement.select.SelectBody
android·前端·后端
u***42071 天前
【学术会议论文投稿】Spring Boot实战:零基础打造你的Web应用新纪元
前端·spring boot·后端
v***91301 天前
数据库高安全—openGauss安全整体架构&安全认证
android·前端·后端
shaohaoyongchuang1 天前
vue_06跨域
前端·javascript·vue.js
宠..1 天前
创建标签控件
java·服务器·开发语言·前端·c++·qt
Z_Wonderful1 天前
主题切换(1):css变量的使用(:root)
前端·javascript·css
亮子AI1 天前
【CSS】如何选择父级元素?
前端·css