downloadFile.ts 2.6 KB
Newer Older
Q
qiang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
import { TEMP_PATH } from '../constants'
import { hasOwn } from '@vue/shared'
import {
  defineTaskApi,
  API_DOWNLOAD_FILE,
  API_TYPE_DOWNLOAD_FILE,
  DownloadFileProtocol,
  DownloadFileOptions,
} from '@dcloudio/uni-api'

type Downloader = ReturnType<typeof plus.downloader.createDownload>

class DownloadTask implements UniApp.DownloadTask {
  private _downloader: Downloader
  private _callbacks: Function[] = []
  constructor(downloader: Downloader) {
    this._downloader = downloader
    downloader.addEventListener('statechanged', (download, status) => {
      if (download.downloadedSize && download.totalSize) {
        this._callbacks.forEach((callback) => {
          callback({
            progress: Math.round(
              (download.downloadedSize! / download.totalSize!) * 100
            ),
            totalBytesWritten: download.downloadedSize,
            totalBytesExpectedToWrite: download.totalSize,
          })
        })
      }
    })
  }
  abort() {
    this._downloader.abort()
  }
  onProgressUpdate(callback: (result: any) => void) {
    if (typeof callback !== 'function') {
      return
    }
    this._callbacks.push(callback)
  }
  offProgressUpdate(callback: (result: any) => void) {
    const index = this._callbacks.indexOf(callback)
    if (index >= 0) {
      this._callbacks.splice(index, 1)
    }
  }
  onHeadersReceived(callback: (result: any) => void): void {
    throw new Error('Method not implemented.')
  }
  offHeadersReceived(callback: (result: any) => void): void {
    throw new Error('Method not implemented.')
  }
}

export const downloadFile = defineTaskApi<API_TYPE_DOWNLOAD_FILE>(
  API_DOWNLOAD_FILE,
  ({ url, header, timeout }, { resolve, reject }) => {
    timeout =
      (timeout ||
        (__uniConfig.networkTimeout && __uniConfig.networkTimeout.request) ||
        60 * 1000) / 1000
    const downloader = plus.downloader.createDownload(
      url,
      {
        timeout,
        filename: TEMP_PATH + '/download/',
        // 需要与其它平台上的表现保持一致,不走重试的逻辑。
        retry: 0,
        retryInterval: 0,
      },
      (download, statusCode) => {
        if (statusCode) {
          resolve({
            tempFilePath: download.filename!,
            statusCode,
          })
        } else {
          reject(`statusCode: ${statusCode}`)
        }
      }
    )
    const downloadTask = new DownloadTask(downloader)
    for (const name in header) {
      if (hasOwn(header, name)) {
        downloader.setRequestHeader(name, header[name])
      }
    }
    downloader.start()
    return downloadTask
  },
  DownloadFileProtocol,
  DownloadFileOptions
)