前言

上篇文章中我们完成了文件下载功能,但有时候并不是通过点击链接被动响应下载任务,也有可能是点击按钮后,直接进行下载。这一篇文章中我们来看下如何主动发起一个下载任务

步骤

同样的,我们依然需要设置下载代理webview.WebDownloadDelegate,并且在其各种回调方法中处理业务逻辑。


  downloadDelegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();
  aboutToAppear() {
this.initDownloadDelegate()
}
  initDownloadDelegate(){
    this.downloadDelegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
      console.log("will start a download.");
      // 传入一个下载路径,并开始下载。
      // 如果传入一个不存在的路径,则会下载到默认/data/storage/el2/base/cache/web/目录。

     let dir =getContext().cacheDir +"/web/" + webDownloadItem.getSuggestedFileName()
      console.error("下载路径",dir)

      webDownloadItem.start(dir);
    })
    this.downloadDelegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => {
      // 下载任务的唯一标识。
      console.log("onDownloadUpdated 唯一标识 guid: " + webDownloadItem.getGuid());
      // 下载的进度。
      console.log("onDownloadUpdated 下载进度百分比: " + webDownloadItem.getPercentComplete());
      // 当前的下载速度。
      console.log("onDownloadUpdated 下载速度 : " + webDownloadItem.getCurrentSpeed())
    })
    this.downloadDelegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => {
      console.log("onDownloadFailed 唯一标识 guid: " + webDownloadItem.getGuid());
      // 下载任务失败的错误码。
      console.log("onDownloadFailed last error code: " + webDownloadItem.getLastErrorCode());
    })
    this.downloadDelegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
      console.log("onDownloadFinish guid: " + webDownloadItem.getGuid());
    })
  }

下载

这里下载的时候可能是前端通过调用native方法告知鸿蒙侧需要进行下载,或者直接是点击鸿蒙原生页面的按钮进行下载。
当触发该事件时,我们直接调用this.controller.startDownload('下载地址‘); 就可以了

恢复上次未完成的任务

想要恢复下载,我们需要在下载失败的时候保存下载的相关信息,需要调整一下之前下载代理相关代码

            this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
              console.log("will start a download.");
              // 传入一个下载路径,并开始下载。
              webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName());
            })
            this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download update percent complete: " + webDownloadItem.getPercentComplete());
              this.download = webDownloadItem;
            })
            this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download failed guid: " + webDownloadItem.getGuid());
              // 序列化失败的下载任务到一个字节数组。
              this.failedData = webDownloadItem.serialize();
            })
            this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download finish guid: " + webDownloadItem.getGuid());
            })
            this.controller.setDownloadDelegate(this.delegate);

然后我们来模拟一下

import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { downloadUtil, fileName, filePath } from './downloadUtil'; // downloadUtil.ets 见下文

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();
  download: webview.WebDownloadItem = new webview.WebDownloadItem();
  // 用于记录失败的下载任务。
  failedData: Uint8Array = new Uint8Array();

  aboutToAppear(): void {
    downloadUtil.init(this.getUIContext());
  }

      Button('record')
        .onClick(() => {
          try {
            // 保存当前下载数据到持久化文档中。
            downloadUtil.saveDownloadInfo(downloadUtil.uint8ArrayToStr(this.download.serialize()));
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        });
      Button('recovery')
        .onClick(() => {
          try {
            // 当前默认持久化文件存在,用户根据实际情况增加判断。
            let webDownloadItem = webview.WebDownloadItem.deserialize(downloadUtil.strToUint8Array(downloadUtil.readFileSync(filePath, fileName)));
            webview.WebDownloadManager.resumeDownload(webDownloadItem);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        });

}

工具类相关代码

// downloadUtil.ets
import { util } from '@kit.ArkTS';
import fileStream from '@ohos.file.fs';


const helper = new util.Base64Helper();


export const filePath = getContext().filesDir;
export const fileName = 'demoFile.txt';
export namespace  downloadUtil {


  export function uint8ArrayToStr(uint8Array: Uint8Array): string {
    return helper.encodeToStringSync(uint8Array);
  }


  export function strToUint8Array(str: string): Uint8Array {
    return helper.decodeSync(str);
  }


  export function saveDownloadInfo(downloadInfo: string): void {
    if (!fileExists(filePath)) {
      mkDirectorySync(filePath);
    }


    writeToFileSync(filePath, fileName, downloadInfo);
  }


  export function fileExists(filePath: string): boolean {
    try {
      return fileStream.accessSync(filePath);
    } catch (error) {
      return false;
    }
  }


  export function mkDirectorySync(directoryPath: string, recursion?: boolean): void {
    try {
      fileStream.mkdirSync(directoryPath, recursion ?? false);
    } catch (error) {
      console.error(`mk dir error. err message: ${error.message}, err code: ${error.code}`);
    }
  }


  export function writeToFileSync(dir: string, fileName: string, msg: string): void {
    let file = fileStream.openSync(dir + '/' + fileName, fileStream.OpenMode.WRITE_ONLY | fileStream.OpenMode.CREATE);
    fileStream.writeSync(file.fd, msg);
  }


  export function readFileSync(dir: string, fileName: string): string {
    return fileStream.readTextSync(dir + '/' + fileName);
  }


}

这样我们就完成了任务的恢复。

其实这种场景不是常见,如果需要下载大文件,一般来讲会通过鸿蒙原生相关方法来下载,而不是使用web的下载功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐