1# Downloading Files 2 3> **NOTE** 4> 5>To use the download function of the **Web** component, the application needs to invoke **WebDownloadItem.start** to specify the path for saving the downloaded file. 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. To cancel the current download, you can invoke **WebDownloadItem.cancel**. In this case, the temporary file is deleted. 6> 7>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](../reference/apis-arkweb/js-apis-webview.md#resumedownload11). 8 9## Listening for Downloads Initiated from Pages 10 11Call [setDownloadDelegate()](../reference/apis-arkweb/js-apis-webview.md#setdownloaddelegate11) 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. 12 13In 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. 14 15```ts 16// xxx.ets 17import { webview } from '@kit.ArkWeb'; 18import { BusinessError } from '@kit.BasicServicesKit'; 19 20@Entry 21@Component 22struct WebComponent { 23 controller: webview.WebviewController = new webview.WebviewController(); 24 delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate(); 25 26 build() { 27 Column() { 28 Button('setDownloadDelegate') 29 .onClick(() => { 30 try { 31 this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => { 32 console.log("will start a download."); 33 // Pass in a download path and start the download. 34 // If the path is invalid, the file will be downloaded to the default directory at /data/storage/el2/base/cache/web/. 35 webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName()); 36 }) 37 this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => { 38 // Unique ID of a download task. 39 console.log("download update guid: " + webDownloadItem.getGuid()); 40 // Download progress. 41 console.log("download update guid: " + webDownloadItem.getPercentComplete()); 42 // Current download speed. 43 console.log("download update speed: " + webDownloadItem.getCurrentSpeed()) 44 }) 45 this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => { 46 console.log("download failed guid: " + webDownloadItem.getGuid()); 47 // Error code of a download task failure. 48 console.log("download failed guid: " + webDownloadItem.getLastErrorCode()); 49 }) 50 this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => { 51 console.log("download finish guid: " + webDownloadItem.getGuid()); 52 }) 53 this.controller.setDownloadDelegate(this.delegate); 54 } catch (error) { 55 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 56 } 57 }) 58 Web({ src: $rawfile('index.html'), controller: this.controller }) 59 } 60 } 61} 62``` 63 64HTML file to be loaded: 65```html 66<!-- index.html --> 67<!DOCTYPE html> 68<html> 69<body> 70// Click the download button in the lower right corner of the video to trigger a download task. 71<video controls="controls" width="800px" height="580px" 72 src="http://vjs.zencdn.net/v/oceans.mp4" 73 type="video/mp4"> 74</video> 75<a href='data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E' download='download.html'>Download the download.html</a> 76</body> 77</html> 78``` 79 80HTML file to be downloaded: 81```html 82<!-- download.html --> 83<!DOCTYPE html> 84<html> 85<body> 86<h1>download test</h1> 87</body> 88</html> 89``` 90 91## Initiating a Download Task 92 93Call [startDownload()](../reference/apis-arkweb/js-apis-webview.md#startdownload11) to initiate a download task. 94For a download initiated by it, the **Web** component works out the referrer based on the currently displayed URL and its own default referrer policy. 95 96 In the following example, clicking **setDownloadDelegate** registers a listener class with the **Web** component, and clicking **startDownload** initiates a download task. 97 The application is notified of the download task progress through the configured **DownloadDelegate** object. 98 99```ts 100// xxx.ets 101import { webview } from '@kit.ArkWeb'; 102import { BusinessError } from '@kit.BasicServicesKit'; 103 104@Entry 105@Component 106struct WebComponent { 107 controller: webview.WebviewController = new webview.WebviewController(); 108 delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate(); 109 110 build() { 111 Column() { 112 Button('setDownloadDelegate') 113 .onClick(() => { 114 try { 115 this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => { 116 console.log("will start a download."); 117 // Pass in a download path and start the download. 118 webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName()); 119 }) 120 this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => { 121 console.log("download update guid: " + webDownloadItem.getGuid()); 122 }) 123 this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => { 124 console.log("download failed guid: " + webDownloadItem.getGuid()); 125 }) 126 this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => { 127 console.log("download finish guid: " + webDownloadItem.getGuid()); 128 }) 129 this.controller.setDownloadDelegate(this.delegate); 130 } catch (error) { 131 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 132 } 133 }) 134 Button('startDownload') 135 .onClick(() => { 136 try { 137 // The specified download address here is https://www.example.com/. 138 // Replace it with the URL from which you want to download files. 139 this.controller.startDownload('https://www.example.com/'); 140 } catch (error) { 141 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 142 } 143 }) 144 Web({ src: 'www.example.com', controller: this.controller }) 145 } 146 } 147} 148``` 149 150 151## Resuming Unfinished Download Tasks Due to Process Exit 152When the **Web** component is started, you can resume the unfinished download task through the [resumeDownload()](../reference/apis-arkweb/js-apis-webview.md#resumedownload11) API. 153 154In 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. 155```ts 156// xxx.ets 157import { webview } from '@kit.ArkWeb'; 158import { BusinessError } from '@kit.BasicServicesKit'; 159import { downloadUtil, fileName, filePath } from './downloadUtil'; // downloadUtil.ets is described below. 160 161@Entry 162@Component 163struct WebComponent { 164 controller: webview.WebviewController = new webview.WebviewController(); 165 delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate(); 166 download: webview.WebDownloadItem = new webview.WebDownloadItem(); 167 // Used to record failed download tasks. 168 failedData: Uint8Array = new Uint8Array(); 169 170 build() { 171 Column() { 172 Button('setDownloadDelegate') 173 .onClick(() => { 174 try { 175 this.delegate.onBeforeDownload((webDownloadItem: webview.WebDownloadItem) => { 176 console.log("will start a download."); 177 // Pass in a download path and start the download. 178 webDownloadItem.start("/data/storage/el2/base/cache/web/" + webDownloadItem.getSuggestedFileName()); 179 }) 180 this.delegate.onDownloadUpdated((webDownloadItem: webview.WebDownloadItem) => { 181 console.log("download update percent complete: " + webDownloadItem.getPercentComplete()); 182 this.download = webDownloadItem; 183 }) 184 this.delegate.onDownloadFailed((webDownloadItem: webview.WebDownloadItem) => { 185 console.log("download failed guid: " + webDownloadItem.getGuid()); 186 // Serialize the failed download task to a byte array. 187 this.failedData = webDownloadItem.serialize(); 188 }) 189 this.delegate.onDownloadFinish((webDownloadItem: webview.WebDownloadItem) => { 190 console.log("download finish guid: " + webDownloadItem.getGuid()); 191 }) 192 this.controller.setDownloadDelegate(this.delegate); 193 webview.WebDownloadManager.setDownloadDelegate(this.delegate); 194 } catch (error) { 195 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 196 } 197 }) 198 Button('startDownload') 199 .onClick(() => { 200 try { 201 // The specified download address here is https://www.example.com/. 202 // Replace it with the URL from which you want to download files. 203 this.controller.startDownload('https://www.example.com/'); 204 } catch (error) { 205 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 206 } 207 }) 208 // Serialize and save the current download task information for subsequent download task resumption. 209 // This example shows the one-task download scenario. For multiple download tasks, extend the code as required. 210 Button('record') 211 .onClick(() => { 212 try { 213 // Save the downloaded data to a persistent file. 214 downloadUtil.saveDownloadInfo(downloadUtil.uint8ArrayToStr(this.download.serialize())); 215 } catch (error) { 216 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 217 } 218 }) 219 // Resume the download task from the serialized download task information. 220 // Ensure that the WebDownloadManager.setDownloadDelegate setting is complete when the button is triggered. 221 Button('recovery') 222 .onClick(() => { 223 try { 224 // The persistence file is available by default. You can set it as required. 225 let webDownloadItem = 226 webview.WebDownloadItem.deserialize(downloadUtil.strToUint8Array(downloadUtil.readFileSync(filePath, fileName))); 227 webview.WebDownloadManager.resumeDownload(webDownloadItem); 228 } catch (error) { 229 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 230 } 231 }) 232 233 Web({ src: 'www.example.com', controller: this.controller }) 234 } 235 } 236} 237``` 238 239Download the task information persistence utility file. 240```ts 241// downloadUtil.ets 242import { util } from '@kit.ArkTS'; 243import fileStream from '@ohos.file.fs'; 244 245const helper = new util.Base64Helper(); 246 247export const filePath = getContext().filesDir; 248export const fileName = 'demoFile.txt'; 249export namespace downloadUtil { 250 251 export function uint8ArrayToStr(uint8Array: Uint8Array): string { 252 return helper.encodeToStringSync(uint8Array); 253 } 254 255 export function strToUint8Array(str: string): Uint8Array { 256 return helper.decodeSync(str); 257 } 258 259 export function saveDownloadInfo(downloadInfo: string): void { 260 if (!fileExists(filePath)) { 261 mkDirectorySync(filePath); 262 } 263 264 writeToFileSync(filePath, fileName, downloadInfo); 265 } 266 267 export function fileExists(filePath: string): boolean { 268 try { 269 return fileStream.accessSync(filePath); 270 } catch (error) { 271 return false; 272 } 273 } 274 275 export function mkDirectorySync(directoryPath: string, recursion?: boolean): void { 276 try { 277 fileStream.mkdirSync(directoryPath, recursion ?? false); 278 } catch (error) { 279 console.error(`mk dir error. err message: ${error.message}, err code: ${error.code}`); 280 } 281 } 282 283 export function writeToFileSync(dir: string, fileName: string, msg: string): void { 284 let file = fileStream.openSync(dir + '/' + fileName, fileStream.OpenMode.WRITE_ONLY | fileStream.OpenMode.CREATE); 285 fileStream.writeSync(file.fd, msg); 286 } 287 288 export function readFileSync(dir: string, fileName: string): string { 289 return fileStream.readTextSync(dir + '/' + fileName); 290 } 291 292} 293``` 294