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

一、需求背景

1、需要实现小程序下载最大500M视频
2、同时需支持图片下载
3、退到其他页面再次回到当前页面时,下载进度也需要展示

二、实现步骤

1、在app.ts文件定义一个全局变量globalDownLoadData
在这里插入图片描述
2、写一个独立的下载hooks,代码如下(hooks/useDownLoad.ts文件)

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、页面使用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值