uni-app多端资源文件下载实现方案

一、背景介绍

在开发 uni-app 应用时,经常需要实现文件下载功能。但由于不同平台(H5、小程序、App)的运行环境和API差异,我们需要采用条件编译来实现跨平台的文件下载功能。

二、平台差异分析

2.1 H5平台特点

  • 运行在浏览器环境中

  • 可以使用浏览器原生的 XMLHttpRequest 和 Blob API

  • 通过创建临时 <a />标签下载

  • 受同源策略限制,需要注意跨域问题

2.2 小程序和App平台特点

  • 运行在原生环境中
  • 使用平台提供的专有API
  • 需要申请相关权限
  • 可以监听下载进度
  • 下载完成后需要调用特定API保存到相册

三、实现方案

3.1 H5端实现

js 复制代码
async function saveFileToLocal(fileUrl) {
    // #ifdef H5
    uni.showLoading({
      title: '正在下载中...',
      mask: true
    })
    const xhr = new XMLHttpRequest();
    xhr.open('GET', fileUrl, true);
    xhr.responseType = 'arraybuffer';    // 返回类型blob
    xhr.onload = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let blob = this.response;
        // 转换为blob链接
        let url = window.URL.createObjectURL(
          new Blob([blob], { 
            type: 'video/mp4'  // 根据文件类型设置
          })
        )
        // 创建临时下载链接
        let a = document.createElement('a');
        a.download = 'filename';  // 设置下载文件名
        a.href = url;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        uni.hideLoading();
        document.body.removeChild(a);
      }
    };
    xhr.send();
    // #endif
}

3.2 小程序和App实现

js 复制代码
async function saveFileToLocal(fileUrl) {
    // #ifndef H5
    return new Promise((resolve, reject) => {
      // 下载状态控制
      isDownloading.value = true;
      downloadProgress.value = 0;

      const downloadTask = uni.downloadFile({
        url: fileUrl,
        success: (res) => {
          if (res.statusCode === 200) {
            // 下载成功后保存到相册
            uni.saveVideoToPhotosAlbum({
              filePath: res.tempFilePath,
              success: () => {
                uni.showToast({
                  title: '保存成功',
                  icon: 'success'
                });
                resolve('保存成功');
              },
              fail: (err) => {
                uni.showToast({
                  title: '保存失败',
                  icon: 'none'
                });
                reject(err);
              }
            });
          }
        },
        fail: (err) => {
          uni.showToast({
            title: '下载失败',
            icon: 'none'
          });
          reject(err);
        },
        complete: () => {
          isDownloading.value = false;
          downloadProgress.value = 0;
        }
      });

      // 监听下载进度
      downloadTask.onProgressUpdate((res) => {
        downloadProgress.value = res.progress;
      });
});
// #endif
}

四、条件编译说明

uni-app 使用条件编译来处理平台差异:

  • // #ifdef H5:仅在 H5 平台编译
  • // #ifndef H5:除了 H5 平台都编译
  • // #endif:条件编译结束标志 这样做的原因:
  1. API差异:不同平台提供的API不同
  2. 运行环境差异:H5运行在浏览器中,而小程序和App运行在各自的容器中
  3. 安全限制差异:不同平台有不同的安全策略
  4. 用户体验优化:可以针对不同平台提供最优的实现方案

五、实现细节解析

5.1 H5端实现要点

  1. 使用 XMLHttpRequest 请求文件数据
  2. 设置 responseType 为 arraybuffer
  3. 使用 Blob 创建临时URL
  4. 通过动态创建 <a /> 标签元素触发下载
  5. 下载完成后清理临时元素

5.2 小程序和App实现要点

  1. 使用 uni.downloadFile 下载文件
  2. 使用 uni.saveVideoToPhotosAlbumuni.saveImageToPhotosAlbum保存文件
  3. 实现下载进度监听
  4. 完善的状态管理和错误处理
  5. 注意权限申请

5.3 权限说明

1.Android权限解释:

  • WRITE_EXTERNAL_STORAGE: 写入外部存储权限
  • READ_EXTERNAL_STORAGE: 读取外部存储权限
  • INTERNET: 网络访问权限
  • MOUNT_UNMOUNT_FILESYSTEMS: 挂载文件系统权限
  • MANAGE_EXTERNAL_STORAGE: Android 10及以上的存储权限
  • MEDIA_CONTENT_CONTROL: 媒体文件控制权限

六、注意事项

1.权限处理

  • 小程序需要在 manifest.json 中声明相关权限
  • App 需要动态申请存储权限
  • H5 需要注意跨域问题

2.文件类型

  • 图片:image/jpeg、image/png 等
  • 视频:video/mp4 等
  • 需要根据实际文件类型设置正确的 MIME type

3.错误处理

  • 网络错误
  • 权限拒绝
  • 存储空间不足
  • 文件格式不支持

4.用户体验

  • 添加下载进度提示
  • 适当的 loading 提示
  • 成功/失败的反馈

七、最佳实践建议

  1. 封装统一的下载方法,内部根据平台调用不同实现
  2. 添加完善的错误处理和状态管理
  3. 实现下载进度提示
  4. 注意内存管理,及时清理临时文件
  5. 考虑网络状态和存储空间检查

八、总结

条件编译实现多端文件下载是一个很好的跨平台解决方案。它让我们能够:

  1. 充分利用各平台特性
  2. 提供最佳的用户体验
  3. 保持代码的可维护性
  4. 实现统一的业务逻辑

这篇文章能帮助你更好地理解和实现uni-app多端文件下载功能!

相关推荐
米粒宝的爸爸2 小时前
uniapp在app端,在导航栏设置自定义按钮
uni-app
Hexene...2 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
初遇你时动了情2 小时前
腾讯地图 vue3 使用 封装 地图组件
javascript·vue.js·腾讯地图
dssxyz2 小时前
uniapp打包微信小程序主包过大问题_uniapp 微信小程序时主包太大和vendor.js过大
javascript·微信小程序·uni-app
华子w9089258592 小时前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端
xw53 小时前
我犯了错,我于是为我的uni-app项目引入环境标志
前端·uni-app
!win !3 小时前
被老板怼后,我为uni-app项目引入环境标志
前端·小程序·uni-app
前端小趴菜055 小时前
React-forwardRef-useImperativeHandle
前端·vue.js·react.js
P7Dreamer5 小时前
Vue 3 + Element Plus 实现可定制的动态表格列配置组件
前端·vue.js
I'm写代码5 小时前
el-tree树形结构笔记
javascript·vue.js·笔记