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

相关推荐
xiangw@GZ1 小时前
音频PA的H桥替代方案研究
音视频
yy我不解释1 小时前
关于comfyui的mmaudio音频生成插件时时间不一致问题(四)(video upload)(解决方法)
开发语言·python·ai作画·音视频·comfyui
却道天凉_好个秋2 小时前
音视频学习(九十八):Profile
学习·音视频·profile
2501_933907213 小时前
本凡科技提供的宁波小程序开发服务全面解决方案
科技·微信小程序·小程序
左师佑图3 小时前
微信小程序集成 Day.js 插件的完整解决方案
微信小程序·小程序
:mnong3 小时前
FramePack视频帧预测设计分析
音视频
2501_933907213 小时前
本凡科技提供宁波小程序服务与定制解决方案
科技·微信小程序·小程序
:mnong3 小时前
MOVA MOSS Video and Audio同步视频-音频设计分析
音视频
chushiyunen3 小时前
python cosyVoice实现tts文本转语音、音频(未完成)
开发语言·python·音视频
计算机徐师兄3 小时前
Java基于SpringBoot的运动健康小程序【附源码、文档说明】
spring boot·小程序·运动健康·java运动健康小程序·运动健康小程序·java运动健康微信小程序·运动健康微信小程序