阅读视图

发现新文章,点击刷新页面。

H5 WebView 文件下载到手机中(仅安卓与 iOS)

H5 WebView 文件下载(仅安卓与 iOS)

原理

  • 使用 H5+ 原生接口 plus.downloader.createDownload 将文件下载到本地;下载完成后通过 plus.runtime.openFile 打开。
  • 不同平台保存路径不同:
    • Android:保存到系统公共 Download 目录(需要存储权限)。
    • iOS:保存到应用沙箱 _doc 持久目录(无需额外权限)。

使用方法(代码)

  • 页面按钮“原生下载PDF”触发函数:src/views/w-success.vue:323
  • 关键实现(节选):
// src/views/w-success.vue:323-388
const downloadByPlus = async () => {
  const p = (window as any).plus;
  if (!p) { alert("当前不在App环境"); return; }
  if (isDownloading.value) return;
  isDownloading.value = true;
  downloadStatus.value = "原生下载中...";

  try {
    const fileOnly = getFileName(downloadUrl);
    const isAndroid = p.os && p.os.name === "Android";
    const isiOS = p.os && p.os.name === "iOS";
    const filename = isAndroid
      ? `file:///storage/emulated/0/Download/${fileOnly}`
      : isiOS
      ? `_doc/${fileOnly}`
      : `_downloads/${fileOnly}`;

    const startDownload = () =>
      p.downloader.createDownload(
        downloadUrl,
        { filename },
        (d: any, status: number) => {
          isDownloading.value = false;
          if (status === 200) {
            let localPath = "";
            try { localPath = p.io.convertLocalFileSystemURL(d.filename); } catch (err) { localPath = ""; }
            downloadStatus.value = localPath ? `下载完成,路径:${localPath}` : "下载完成";
            try { p.runtime.openFile(d.filename); } catch (e: any) { downloadStatus.value = `${downloadStatus.value},打开失败: ${e?.message || e}`; }
          } else {
            downloadStatus.value = `下载失败,状态码:${status}`;
          }
        }
      ).start();

    if (isAndroid) {
      try {
        await new Promise((resolve, reject) => {
          p.android.requestPermissions(
            ["android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"],
            () => resolve(null),
            (err: any) => reject(err)
          );
        });
      } catch (err: any) {
        isDownloading.value = false;
        downloadStatus.value = `缺少存储权限: ${err?.message || err}`;
        return;
      }
    }
    startDownload();
  } catch (e: any) {
    isDownloading.value = false;
    downloadStatus.value = `原生下载失败: ${e?.message || e}`;
  }
};

保存路径

  • Android:/storage/emulated/0/Download/<文件名>(绝对路径显示为 file:///storage/emulated/0/Download/<文件名>)。
  • iOS:_doc/<文件名>(绝对路径通过 plus.io.convertLocalFileSystemURL 转换后显示为 file:///.../Documents/<文件名> 等沙箱路径)。

平台要求

  • Android:需要申请 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE 权限;代码中已请求(src/views/w-success.vue:356-371)。
  • iOS:若下载地址为 http://,需在原生打包的 ATS 配置中允许该域名的非 HTTPS 访问;文件仅可写入应用沙箱。
❌