
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??
簡介
在OpenHarmony應用開發中,我們常用兩種方式來實現文件的下載:
- 使用系統能力SystemCapability.Communication.NetStack(@ohos.http)
- 使用系統能力SystemCapability.MiscServices.Download(@ohos.request)
區別
- 前者下載過程信息不可見,后者會在手機狀態欄顯示下載會話,并且可被應用監聽
- 前者請求下載后不會對文件作進一步處理,后者會直接保存到指定目錄
使用場景
文檔傳送門
??HarmonyOS?OpenHarmony
下面,我們基于ArkUI-ts來實現一個下載進度條的顯示,以API 8、FA模型為例。
(API 9接口稍有改動,若使用API 9、Stage模型,請參考官方文檔??OpenHarmony??,但基本的代碼思路是不變的。
變動:
- 相比于API 8的FA模型,加入了Context的傳參。
- 增加了uploadFile()、downloadFile()方法,保留upload()、donwload()方法
實現流程
首先配置網絡權限(config.json–>module下添加)。
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
支持http(config.json下添加)。
"deviceConfig": {
"default": {
"network": {
"cleartextTraffic": true
}
}
},
1、下載配置
導入系統接口。
import request from '@ohos.request'
DownloadConfig
常用的字段配置:
字段 | 解釋 | 必填 |
url | 資源目標地址 | 是 |
header | 請求頭配置 | 否 |
filePath | 資源保存路徑 | 否 |
其它的字段配置:
字段 | 解釋 | 必填 |
title | 設置下載會話標題(狀態欄) | 否 |
description | 設置下載會話的描述(狀態欄) | 否 |
networkType | 允許下載的網絡類型: 0x00000001——流量數據 0x00010000——wifi | 否 |
enableRoaming | 是否允許在漫游網絡中下載 | 否 |
enableMetered | 允許在按流量計費的連接下下載 | 否 |
示例1
例如:通過圖片url下載保存到本地的 internal://cache的myDownload/test.png 路徑,文件名為test.png
let downloadConfig: request.DownloadConfig = {
url: downloadUrl,
filePath: 'myDownload/test.png',
description: 'Download Test',
}
internal://cache是應用沙箱路徑,獲取方法:
import featureAbility from "@ohos.ability.featureAbility"
let cacheSandPath = featureAbility.getConext().getCacheDoir()
目前js api只支持在filePath配置在internal://cache下(默認)
我們有兩種方式可以訪問到下載的文件:一是內部儲存目錄storage路徑file目錄;二是只允許本應用訪問的沙箱路徑cache目錄
這個知識點在后面的Image顯示會用到。
2、創建下載任務
let downloadTask
request.download(downloadConfig, (err, data) => {
if (err) {
console.info('xxx--- Failed to request the download. Cause: ' + JSON.stringify(err))
return
}
downloadTask = data
})
3、監聽下載事件
request.DownloadTask
方法 | 解釋 |
on/ off(“progress”) | 開啟/關閉 進度 監聽,返回當前下載大小receivedSize和總大小totalSize |
on / off(‘complete’|‘pause’|‘remove’) | 開啟/關閉 完成|暫停|取消 監聽 |
on / off(‘fail’) | 開啟/關閉 失敗 監聽,返回錯誤碼 |
remove() | 移除下載任務,返回boolean值 |
pause() | 暫停下載任務 |
query() | 查詢下載實時情況,返回Promise<DownloadInfo> |
queryMimeType() | 查詢下載的任務的 MimeType(媒體類型),返回Promise<string> |
request.DownloadInfo
屬性 | 解釋 |
downloadTotalBytes | 下載的文件的總大小(int bytes) |
downloadedBytes | 實時下載大小(int bytes) |
downloadId | 下載的文件ID |
fileName | 下載的文件名 |
filePath | 存儲文件的URI |
status | 下載狀態代碼 |
targetURI | 下載文件的URI |
downloadTitle | 下載的文件的標題 |
description | 待下載文件的描述信息 |
failedReason | 下載失敗原因(非必有) |
想要實現下載進度的監聽,從上面的方法我們可以找到對應的方法 on(“progress”)。
示例3-1
downloadTask.on('progress', (receiveSize: number, totalSize: number) => {
this.curProgressValue = (receiveSize / totalSize) * 100
this.curTaskDownloadedSize = receiveSize
this.curTaskTotalSize = totalSize
})
經過測試發現,直接使用 on(‘progress’)不一定能監聽到實時下載大小和總大小,返回值receivedSize和totalSize可能為0。
因此當on(“progress”)的返回值為0時,我們可以用另外一個方法 query() 來查詢實時下載中的進度信息,或是在query() 中使用on(‘progress’)。
示例3-2
進度的監聽
let downloadInfoFilePath:string = ''
downloadTask.query().then((downloadInfo:request.DownloadInfo) => {
downloadInfoFilePath = downloadInfo.filePath // 此處返回的路徑不同于應用沙箱路徑
this.downloadTask = data
this.downloadTask.on('progress', (receiveSize: number, totalSize: number) => {
this.curProgressValue = (receiveSize / totalSize) * 100 // 進度條Progress屬性值
this.curTaskDownloadedSize = receiveSize // 實時下載大小
this.curTaskTotalSize = totalSize // 總大小
})
/* 或使用query返回的downloadInfo獲取下載進度信息
this.curTaskDownloadedSize = downloadInfo.downloadedBytes
this.curTaskTotalSize = downloadInfo.downloadTotalBytes
this.curProgressValue = (this.curTaskDownloadedSize / this.curTaskTotalSize) * 100
*/
console.info('xxx--- downloadTask queried info:' + JSON.stringify(downloadInfo))
}).catch((err) => {
console.info('xxx--- Failed to query the downloadTask:' + JSON.stringify(err))
})
示例3-3
complete、fail、pause事件的監聽。
downloadTask.query().then((downloadInfo:request.DownloadInfo) => {
......
var self = this
var clearListeners = function () {
self.downloadTask.off('progress')
self.downloadTask.off('fail')
self.downloadTask.off('remove')
self.downloadTask.off('complete')
}
this.downloadTask.on('fail', (err) => {
clearListeners()
this.curProgressValue = 0
})
this.downloadTask.on('remove', () => {
clearListeners()
this.curProgressValue = 0
})
this.downloadTask.on('complete', () => {
clearListeners()
this.curProgressValue = 100
// downloadInfoList:string[] 保存下載歷史的路徑
this.downloadInfoList.push(downloadInfoFilePath)
})
})
4、下載結果反饋
定義一個Progress組件來顯示當前下載任務的進度(數字和進度條),當下載任務結束后,顯示相關信息:任務成功or失敗、保存的位置。
Progress({ value: this.curProgressValue })
.width('90%')
.color(Color.Blue)
.margin(10)
Text顯示相關下載信息。
Text('實時下載大小: ' + this.curTaskDownloadedSize + ' B').width('90%').fontSize(25).margin(10)
Text('當前任務大小: ' + this.curTaskTotalSize + ' B').width('90%').fontSize(25).margin(10)
Text('下載儲存路徑:').width('90%').fontSize(25).margin({ left: 10, right: 10, top: 10, bottom: 5 })
定義Image組件,獲取保存路徑顯示下載的媒體(僅當圖片)。
這里訪問路徑使用的是downloadInfo中的filePath屬性,即內部儲存路徑。
// downloadInfoList:string[] 保存下載歷史的路徑
ForEach(this.downloadInfoList, item => {
Flex({ justifyContent: FlexAlign.Center }) {
Image(item)
.backgroundColor('#ccc')
.margin(5)
.width('25%')
.aspectRatio(1)
.alignSelf(ItemAlign.Start)
.objectFit(ImageFit.ScaleDown)
Text(item).fontSize(15).padding(10).width('70%')
}.width('95%')
}, item => item)
同時,可以完美地運用上我在這篇文章 #創作者激勵#【FFH】自制ArkUI組件-文件管理器(二)懸浮小球 封裝好的 文件管理器組件-FilerBall 來檢驗我們文件下載保存的位置,以及查看更詳細的文件信息。
演示圖
下載大文件(視頻)時

這里設置images、video、file都保存在沙箱訪問路徑internal://cache的myDownload/下。
Image回顯

代碼
downloadDemo(downloadUrl: string, saveUrl?: string) {
var self = this
var clearListeners = function () {
self.downloadTask.off('progress')
self.downloadTask.off('fail')
self.downloadTask.off('remove')
self.downloadTask.off('complete')
}
let downloadConfig: request.DownloadConfig = {
url: downloadUrl,
filePath: 'myDownload/' + saveUrl,
enableMetered: true,
enableRoaming: true,
description: 'Download Test',
}
request.download(downloadConfig, (err, data) => {
if (err) {
console.info('xxx--- Failed to request the download. Cause: ' + JSON.stringify(err))
return
}
let downloadInfoFilePath
this.curProgressValue = 0
this.mes = '開始'
this.downloadTask = data
this.downloadTask.query().then((downloadInfo: request.DownloadInfo) => {
downloadInfoFilePath = downloadInfo.filePath
this.downloadTask.on('progress', (receiveSize: number, totalSize: number) => {
this.curProgressValue = (receiveSize / totalSize) * 100
this.curTaskDownloadedSize = receiveSize
this.curTaskTotalSize = totalSize
})
console.info('xxx--- Download task queried. Data:' + JSON.stringify(downloadInfo))
}).catch((err) => {
console.info('xxx--- Failed to query the download task. Cause:' + JSON.stringify(err))
})
this.downloadTask.on('fail', (err) => {
clearListeners()
this.curProgressValue = 0
this.mes = '失敗'
})
this.downloadTask.on('remove', () => {
clearListeners()
this.curProgressValue = 0
this.mes = '取消'
})
this.downloadTask.on('complete', () => {
clearListeners()
this.curProgressValue = 100
this.mes = '完成'
// downloadInfoList保存下載歷史的路徑
this.downloadInfoList.push(downloadInfoFilePath)
})
})
}
ets使用示例。
Button('下載視頻(小)', { type: ButtonType.Capsule })
.width('90%')
.height(50)
.margin(10)
.onClick(() => {
this.curProgressValue = this.curTaskDownloadedSize = this.curTaskTotalSize = 0
this.downloadDemo('https://media.w3.org/2010/05/sintel/trailer.mp4', 'video/')
})
頁面代碼放在附件資源。
https://ost.51cto.com/resource/2679。
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??