likes
comments
collection
share

react-native-blob-util下载文件展示进度,随时取消(原创仅供参考)这段代码通过封装一个下载文件的功能

作者站长头像
站长
· 阅读数 134

这段代码通过封装一个下载文件的功能,利用 React 状态管理和异步处理,能够在 React Native 应用中轻松实现文件下载、进度跟踪和取消下载的功能。每个步骤都以清晰的方式处理下载任务,使得代码易于理解和维护。

下载功能实现

1. 引入必要库和 hooks

  • useRef:React Hook,用于创建一个引用对象,能够在组件之间保留状态。
  • CommonBridge 和 ReactNativeBlobUtil:这两个库用于处理文件下载和本地文件操作。

2. 定义状态和引用

const downloadTaskRef = useRef({})
  • downloadTaskRef 被用作引用以存储下载任务的实例,这样可以在多个函数中共享这个状态。

3. 定义下载文件的函数

const downloadFile = async (url: string) => {
  • downloadFile 是一个异步函数,接收一个 URL 作为参数,用于下载文件。

4. 构建文件路径

const fileName = 'xxx.pdf'
const filePath = `${...}`
  • fileName 定义了下载文件的名称。

  • filePath 动态确定文件存储路径:

    • 如果是在 Android 设备上,使用 /storage/emulated/0/Download 目录。
    • 如果是在 iOS 设备上,使用 ReactNativeBlobUtil.fs.dirs.CacheDir

5. 配置下载任务

const { config } = ReactNativeBlobUtil
downloadTaskRef.current = config({
  path: filePath,
  fileCache: true
})
.fetch('GET', url, {})
  • 使用 ReactNativeBlobUtil 的 config 方法配置下载任务,指定文件存储路径以及启用文件缓存。
  • 接着用 fetch 方法开始下载,HTTP 请求使用 'GET' 方法。

6. 下载进度更新

.progress((percent, total) => {
  setProgress(percent / total)
})
  • 监听下载进度,percent 和 total 是当前下载的字节数和文件总字节数,通过 setProgress 更新进度状态。

7. 处理下载完成和错误

try {
  const response = await downloadTaskRef.current
  setProgress(0)
  ...
} catch (error: any) {
  setProgress(-1)
  ...
}
  • 使用 try...catch 结构捕获异步过程中的错误。如果下载成功,重置进度状态并根据操作系统执行相应操作:

    • 对于 Android,使用 ReactNativeBlobUtil.android.addCompleteDownload 提示用户下载完成,并显示通知。
    • 对于 iOS,使用 ReactNativeBlobUtil.ios.previewDocument 预览下载的文档。

8. 取消下载的方法

const cancelDownload = useCallback(() => {
  if (downloadTaskRef.current) {
    downloadTaskRef.current.cancel((error: any) => {
      setProgress(-1)
    })
    downloadTaskRef.current = null
  }
}, [])
  • cancelDownload 是一个回调函数,用于取消下载任务:

    • 首先检查是否有下载任务在进行,如果有,则调用 cancel 方法取消下载,并设置进度状态为 -1 表示下载被取消。
    • 最后,重置 downloadTaskRef.current 为 null

进度条

这段代码实现了一个简单的进度条,其中进度是动态变化的,用于表示某种任务的完成情况。你可以通过修改 progress 变量的值,来实现进度条的动态更新。

<Progress.Bar
  progress={progress}
/>
  1. import * as Progress from 'react-native-progress' :

    • 这部分表示开始使用 Progress.Bar 组件
  2. progress={progress} :

    • 这里的 progress 是一个变量,代表进度条的进度值,通常在 0 到 1 之间。例如,0 表示没有进度,1 表示进度完成。在实际使用中,你可能会用一个状态值来动态更新这个变量。

关键代码


  const [progress, setProgress] = useState(-1)
  const downloadTaskRef = useRef({})

  const downloadFile = async (url: string) => {
    const fileName = 'xxxx.pdf'
    const filePath = `${
      CommonBridge.isAndroid()
        ? '/storage/emulated/0/Download'
        : ReactNativeBlobUtil.fs.dirs.CacheDir
    }/${fileName}`
    const { config } = ReactNativeBlobUtil

    downloadTaskRef.current = config({
      path: filePath,
      fileCache: true
    })
      .fetch('GET', url, {})
      .progress((percent, total) => {
        setProgress(percent / total)
      })

    try {
      const response = await downloadTaskRef.current
      setProgress(0)

      if (CommonBridge.isAndroid()) {
        ReactNativeBlobUtil.android
          .addCompleteDownload({
            title: fileName,
            description: '下载完成',
            mime: 'application/pdf',
            path: response.path(),
            showNotification: true
          })
          .then(() => {
            setProgress(1)
            showToast('下载完成,请前往 /Download 查看')
          })
      } else {
        setProgress(1)
        ReactNativeBlobUtil.ios.previewDocument(response.path())
      }
    } catch (error: any) {
      setProgress(-1)
      console.error(
        'Error',
        error.message.includes('cancelled')
          ? 'Download was canceled'
          : `Download failed: ${error.message}`
      )
    }
  }

  const cancelDownload = useCallback(() => {
    if (downloadTaskRef.current) {
      downloadTaskRef.current.cancel((error: any) => {
        setProgress(-1)
      })

      downloadTaskRef.current = null
    }
  }, [])

  const handleDownload = useCallback(() => {
    if (path) {
      downloadFile(encodeURI(decodeURIComponent(path)))
    }
  }, [path])

  return progress != 1 && progress != -1 ? (
    <View style={styles.progressContainer}>
      <Text style={styles.progressText}>{parseInt((progress * 100).toString())}%</Text>
      <Progress.Bar
        color="rgba(255,255,255,0.9)"
        borderWidth={0}
        progress={progress}
        style={{ height: 4 }}
        width={pageWidth - 133}
        unfilledColor="rgba(255,255,255,0.1)"
      />
      <TouchableOpacity onPress={cancelDownload} style={styles.cancelButton}>
        取消
      </TouchableOpacity>
    </View>
  ) : (
      <TouchableOpacity onPress={handleDownload} style={styles.itemBox}>
        下载
      </TouchableOpacity>
  )

转载自:https://juejin.cn/post/7418133431677894675
评论
请登录