harmony 鸿蒙Downloading Files

  • 2025-06-12
  • 浏览 (9)

Downloading Files

NOTE

Use WebDownloadItem.start to specify the path for storing downloaded files. Note that WebDownloadItem.start does not start the download. The download process starts when the user clicks the page link. WebDownloadItem.start is used to move the content that has been downloaded to the temporary directory (/data/storage/el2/base/cache/web/Temp/) to the specified path, and directly save the remaining content to the specified path. Use WebDownloadItem.cancel to cancel the current download. In this case, the temporary file is deleted.

If you do not want to download the file to the temporary directory before WebDownloadItem.start, you can also use WebDownloadItem.cancel to interrupt the download. In addition, the interrupted download can be resumed by using WebDownloadManager.resumeDownload.

Listening for Downloads Initiated from Pages

Call setDownloadDelegate() to register a DownloadDelegate object with the Web component to listen for downloads initiated from pages. While the Web component downloads resources as requested, it notifies the application of the download progress through the DownloadDelegate object.

In the following example, the index.html and download.html files are added to the rawfile folder of the application. After the application is started, a Web component is created and the index.html file is loaded. After setDownloadDelegate is clicked, a DownloadDelegate object is registered with the Web component. This DownloadDelegate object listens for any downloads initiated by clicking the download button on the page.

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();

  build() {
    Column() {
      Button('setDownloadDelegate')
        .onClick(() => {
          try {
            this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
              console.log("will start a download.");
              // Pass in a download path and start the download.
              // If the path is invalid, the file will be downloaded to the default directory at /data/storage/el2/base/cache/web/.
              webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName());
            })
            this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => {
              // Unique ID of a download task.
              console.log("download update guid: " + webDownloadItem.getGuid());
              // Download progress.
              console.log("download update percent complelte: " + webDownloadItem.getPercentComplete());
              // Current download speed.
              console.log("download update speed: " + webDownloadItem.getCurrentSpeed())
            })
            this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download failed guid: " + webDownloadItem.getGuid());
              // Error code of a download task failure.
              console.log("download failed last error code: " + webDownloadItem.getLastErrorCode());
            })
            this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download finish guid: " + webDownloadItem.getGuid());
            })
            this.controller.setDownloadDelegate(this.delegate);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Web({ src: $rawfile('index.html'), controller: this.controller })
    }
  }
}

HTML file to be loaded:

<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
// Click the download button in the lower right corner of the video to trigger a download task.
<video controls="controls" width="800px" height="580px"
       src="http://vjs.zencdn.net/v/oceans.mp4"
       type="video/mp4">
</video>
<a href='data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E' download='download.html'>Download the download.html</a>
</body>
</html>

HTML file to be downloaded:

<!-- download.html -->
<!DOCTYPE html>
<html>
<body>
<h1>download test</h1>
</body>
</html>

Initiating a Download Task

Call startDownload() to initiate a download task. For a download initiated by it, the Web component works out the referrer based on the currently displayed URL and its own default referrer policy.

In the following example, clicking setDownloadDelegate registers a listener class with the Web component, and clicking startDownload initiates a download task. The application is notified of the download task progress through the configured DownloadDelegate object.

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();

  build() {
    Column() {
      Button('setDownloadDelegate')
        .onClick(() => {
          try {
            this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
              console.log("will start a download.");
              // Pass in a download path and start the download.
              webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName());
            })
            this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download update guid: " + webDownloadItem.getGuid());
            })
            this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download failed guid: " + webDownloadItem.getGuid());
            })
            this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download finish guid: " + webDownloadItem.getGuid());
            })
            this.controller.setDownloadDelegate(this.delegate);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Button('startDownload')
        .onClick(() => {
          try {
            // The specified download address here is https://www.example.com/. 
            // Replace it with the URL from which you want to download files.
            this.controller.startDownload('https://www.example.com/');
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

Use DocumentViewPicker() to obtain the default download directory and set it as the download directory.

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { picker, fileUri } from  '@kit.CoreFileKit';
@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();

  build() {
    Column() {
      Button('setDownloadDelegate')
        .onClick(() => {
          try {
            this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
              console.log("will start a download.");
              // Use DocumentViewPicker() to obtain the default download directory and set it as the download directory.
              getDownloadPathFromPicker().then((downloadPath) => {
                webDownloadItem.start(downloadPath + '/' + webDownloadItem.getSuggestedFileName());
              });

            })
            this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => {
              // Unique ID of a download task.
              console.log("download update guid: " + webDownloadItem.getGuid());
              // Download progress.
              console.log("download update percent complelte: " + webDownloadItem.getPercentComplete());
              // Current download speed.
              console.log("download update speed: " + webDownloadItem.getCurrentSpeed())
            })
            this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download failed guid: " + webDownloadItem.getGuid());
              // Error code of a download task failure.
              console.log("download failed last error code: " + webDownloadItem.getLastErrorCode());
            })
            this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download finish guid: " + webDownloadItem.getGuid());
            })
            this.controller.setDownloadDelegate(this.delegate);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Web({ src: $rawfile('index.html'), controller: this.controller })
    }
  }

}
function getDownloadPathFromPicker(): Promise<string> {
  return new Promise<string>(resolve => {
    try {
      const documentSaveOptions = new picker.DocumentSaveOptions();
      documentSaveOptions.pickerMode = picker.DocumentPickerMode.DOWNLOAD
      const documentPicker = new picker.DocumentViewPicker();
      documentPicker.save(documentSaveOptions).then(async (documentSaveResult: Array<string>) => {
        if (documentSaveResult.length <= 0) {
          resolve('');
          return;
        }
        const uriString = documentSaveResult[0];
        if (!uriString) {
          resolve('');
          return;
        }
        const uri = new fileUri.FileUri(uriString);
        resolve(uri.path);
      }).catch((err: BusinessError) => {
        console.error(`ErrorCode: ${err.code},  Message: ${err.message}`);
        resolve('');
      });
    } catch (error) {
      resolve('');
    }
  })
}

Resuming Unfinished Download Tasks Due to Process Exit

When the Web component is started, you can resume the unfinished download task through the resumeDownload() API.

In the following example, the record button is used to save the current download task to a persistent file. After the application is restarted, the recovery button can be used to resume the persistent download task. If multiple download tasks need to be saved, the application can adjust the persistence time and mode as required.

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { downloadUtil, fileName, filePath } from './downloadUtil'; // downloadUtil.ets is described below.

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();
  download: webview.WebDownloadItem = new webview.WebDownloadItem();
  // Used to record failed download tasks.
  failedData: Uint8Array = new Uint8Array();

  build() {
    Column() {
      Button('setDownloadDelegate')
        .onClick(() => {
          try {
            this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => {
              console.log("will start a download.");
              // Pass in a download path and start the 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());
              // Serialize the failed download task to a byte array.
              this.failedData = webDownloadItem.serialize();
            })
            this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => {
              console.log("download finish guid: " + webDownloadItem.getGuid());
            })
            this.controller.setDownloadDelegate(this.delegate);
            webview.WebDownloadManager.setDownloadDelegate(this.delegate);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Button('startDownload')
        .onClick(() => {
          try {
            // The specified download address here is https://www.example.com/. 
            // Replace it with the URL from which you want to download files.
            this.controller.startDownload('https://www.example.com/');
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      // Serialize and save the current download task information for subsequent download task resumption.
      // This example shows the one-task download scenario. For multiple download tasks, extend the code as required.
      Button('record')
        .onClick(() => {
          try {
            // Save the downloaded data to a persistent file.
            downloadUtil.saveDownloadInfo(downloadUtil.uint8ArrayToStr(this.download.serialize()));
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      // Resume the download task from the serialized download task information.
      // Ensure that the WebDownloadManager.setDownloadDelegate setting is complete when the button is triggered.
      Button('recovery')
        .onClick(() => {
          try {
            // The persistence file is available by default. You can set it as required.
            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}`);
          }
        })

      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

Download the task information persistence utility file.

// 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);
  }

}

你可能感兴趣的鸿蒙文章

harmony 鸿蒙ArkWeb

harmony 鸿蒙Taking Over the Media Playback on Web Pages

harmony 鸿蒙Mutual Invoking Between the Application and the Frontend Page (C/C++)

harmony 鸿蒙Establishing a Data Channel Between the Application and the Frontend Page (C/C++)

harmony 鸿蒙Enabling Ads Blocking

harmony 鸿蒙Establishing a Data Channel Between the Application and the Frontend Page

harmony 鸿蒙Migrating Web Components Between Different Windows

harmony 鸿蒙Introduction to ArkWeb

harmony 鸿蒙Implementing Content Scrolling

harmony 鸿蒙Managing Cookies and Data Storage

0  赞