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

相关推荐
00后程序员张2 小时前
Fiddler使用教程,全面掌握Fiddler抓包工具的配置方法、代理设置与调试技巧(HTTPHTTPS全解析)
前端·测试工具·ios·小程序·fiddler·uni-app·webview
2501_916008892 小时前
HTTPS 下的 DDoS 防护与抓包分析实战,从检测到快速缓解的工程化打法
网络协议·ios·小程序·https·uni-app·iphone·ddos
2501_915918412 小时前
App 使用 HTTPS 的工程化实战,从接入到真机排查的一线指南
android·ios·小程序·https·uni-app·iphone·webview
EasyNVR3 小时前
EasyNVR 录像自由时段启停与快照定时更新
音视频
ontheway-xx4 小时前
ffmpeg4.4.2 gcc 15.2.0 编译错误
ffmpeg·音视频
FFZero14 小时前
【C++/Lua联合开发】 (一) Lua基础知识
c++·音视频·lua
EasyCVR5 小时前
视频汇聚平台EasyCVR在智慧工地无网线无电线监控现场视频解决方案
音视频
EasyGBS6 小时前
EasyGBS如何在平安乡村搭建无线视频联网监控系统?
音视频
说私域6 小时前
开源AI大模型AI智能名片S2B2C商城小程序在护肤品文案痛点表达中的应用与效果研究
人工智能·小程序
weixin_177297220696 小时前
盲盒一番赏小程序系统开发:重构潮玩消费的沉浸式革命
小程序·重构·盲盒