taro小程序如何实现大文件(视频、图片)后台下载功能?

一、需求背景

1、需要实现小程序下载最大500M视频

2、同时需支持图片下载

3、退到其他页面再次回到当前页面时,下载进度也需要展示

二、实现步骤

1、在app.ts文件定义一个全局变量globalDownLoadData

2、写一个独立的下载hooks,代码如下(hooks/useDownLoad.ts文件)

bash 复制代码
import Taro, { useDidShow } from '@tarojs/taro';
import { useState, useCallback, useEffect, useRef } from 'react';
import { tips } from '@/modules/utils/log';
import { GET_ENV } from '@/modules/core/env';

// 下载选项接口
interface DownloadOptions {
  /** 下载文件的URL */
  url: string;
  // 下载的是图片还是视频,默认是视频
  isImg?: boolean;
  // 下载成功后的回调
  successFn?: () => void;
}

// 请注意_taskId格式应该为:`material_${routerParams.id}`
// material为页面标志,请注意唯一性,避免不同页面的id重复
export const useDownLoad = _taskId => {
  const taskId = `${GET_ENV()}_${_taskId}`;
  const globalDownLoadData = useRef(Taro.getApp().globalDownLoadData);

  const [progress, setProgress] = useState(0);

  useDidShow(() => {
    // 恢复目标页面下载进度
    setProgress(globalDownLoadData.current[taskId]?.progress || 0);
  });
  useEffect(() => {
    globalDownLoadData.current[taskId] = {
      progress,
      downloadTask: globalDownLoadData.current[taskId]?.downloadTask
    };
  }, [progress]);
  // 赋值数据给全局
  useEffect(() => {
    Taro.getApp().globalDownLoadData = globalDownLoadData.current;
  }, [globalDownLoadData]);
  useEffect(() => {
    // 再次进入页面时,将监听加上
    addProgressUpdate();
  }, []);

  /**
   * 执行文件下载
   * @param options 下载选项
   */
  const downloadFn = useCallback(async (options: DownloadOptions) => {
    try {
      setProgress(0);

      // 创建下载任务
      globalDownLoadData.current[taskId].downloadTask = Taro.downloadFile({
        url: options.url,
        success: async res => {
          if (res.statusCode === 200) {
            // 下载成功,保存到相册
            Taro.getSetting({
              success(settingRes) {
                // 是否相册授权,已授权直接保存图片
                if (settingRes.authSetting['scope.writePhotosAlbum']) {
                  const Api = options.isImg ? 'saveImageToPhotosAlbum' : 'saveVideoToPhotosAlbum';
                  Taro[Api]({
                    filePath: res.tempFilePath,
                    success() {
                      tips('下载完成');
                      options.successFn?.();
                      // 下载完成后清除进度
                      setProgress(0);
                    },
                    fail(err) {
                      console.log('saveImageToPhotosAlbum err', err);
                      setProgress(0);
                    }
                  });
                  // 未授权,则先授权
                } else {
                  Taro.authorize({
                    scope: 'scope.writePhotosAlbum',
                    fail() {
                      tips('下载失败,请先点击右上角获取授权');
                      setProgress(0);
                    }
                  });
                }
              },
              fail(err) {
                setProgress(0);
                tips('下载失败,请稍后再试');
                console.log('getSetting err', err);
              }
            });
          } else {
            // 下载失败
            setProgress(0);
            tips('下载失败,请稍后再试');
            console.log('downloadFile下载出错了:', res);
          }
        },
        fail: error => {
          // 下载出错
          setProgress(0);
          globalDownLoadData.current[taskId] = {
            progress: 0,
            downloadTask: null
          };
          console.log('下载出错了:', error);
          Taro.showModal({
            title: '下载异常',
            content: '下载异常或文件大小超过小程序限制,请通过浏览器下载!',
            confirmColor: '#3f57ff',
            success: modalRes => {
              if (modalRes.confirm) {
                Taro.setClipboardData({
                  data: options.url,
                  success() {
                    tips('资源链接已复制');
                  }
                });
              }
            }
          });
        }
      });

      addProgressUpdate();
    } catch (error) {
      // 捕获其他异常
      tips('下载失败,请稍后再试');
      console.log('downloadFn下载失败======>', error);
      setProgress(0);
    }
  }, []);
  // 监听下载进度变化
  const addProgressUpdate = () => {
    const downloadTask = globalDownLoadData.current[taskId]?.downloadTask;
    if (!downloadTask) {
      setProgress(0);
      return;
    }
    downloadTask.onProgressUpdate(res => {
      if (res.progress >= 100) {
        // 下载完成时,延迟2秒后清除进度
        setTimeout(() => {
          setProgress(0);
          downloadTask.abort();
          delete globalDownLoadData.current[taskId];
        }, 2000);
      } else {
        setProgress(res.progress);
      }
    });
  };

  return {
    downloadFn,
    progress
  };
};

3、页面使用

bash 复制代码
import { useDownLoad } from '@/subPages/hooks/useDownLoad';

const { downloadFn, progress } = useDownLoad(`material_${routerParams.id}`);

const onDownload = () => {
    if (!curUrl) {
      tips('下载资源不存在');
      return;
    }
    Taro.showModal({
      title: '提示',
      confirmColor: '#3f57ff',
      content: '确定要下载该素材吗?',
      success: async res => {
        if (res.confirm) {
          downloadFn({
            url: curUrl,
            isImg: false
          });
        }
      }
    });
  };

四、参考文档:

https://developers.weixin.qq.com/miniprogram/dev/api/network/download/wx.downloadFile.html

https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.saveImageToPhotosAlbum.html

https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.saveVideoToPhotosAlbum.html

相关推荐
martindelophy41 分钟前
开源 AI 视频编辑器实战:用结构化命令连接视频生成、对话剪辑与浏览器导出
人工智能·编辑器·音视频
m0_587383001 小时前
无人自助拼豆系统开发实战指南 核心功能架构搭建与落地经验分享
java·经验分享·spring·小程序·架构·需求分析
l14372332671 小时前
短剧视频翻译配音哪家好?批量多语种方案对比
音视频
常州晟凯电子科技2 小时前
8路CVBS/AHD合成一路视频无线传输系统评测
音视频·视频编解码
Ai-_Man2 小时前
DeepSeek生成的内容能否下载吗?
开发语言·javascript·人工智能·小程序·ecmascript
youandyouyou2 小时前
教师远程教研共享屏幕:技术拆解与落地实践
音视频·网络通信
Dovis(誓平步青云)2 小时前
一年1956亿行:智能电表场景下的时序数据存储实践
运维·前端·自动化·音视频·prometheus
开开心心就好2 小时前
Windows视频播放器推荐,精简版体积更小
java·服务器·开发语言·eclipse·pdf·ocr·音视频
Sayai3 小时前
ComfyUI+MiniMax H3 图生视频实战:一张静态图 5 分钟变带音效大片(12G 显存,附工作流)
人工智能·aigc·音视频·comfyui·图生视频·minimax
头发还在的女程序员3 小时前
2026智慧充电桩管理系统-充电桩小程序-云快充2.1 版本通讯协议
小程序·充电桩·充电系统·充电小程序