鸿蒙系统不断发展,有与安卓、iOS 形成三足鼎立之势,且其在智能手机、智能穿戴、车载、家居等行业领域的应用越来越广泛。作为开发者,如何抓住鸿蒙生态崛起的机遇,解决开发挑战,创造更好的应用体验?欢迎您和我们一起探讨~
鸿蒙提供了多种API用于下载,今天我就拿request包来讲解下如何实现下载。
版本:
DevEco Studio 4.1 Release
SDK10
API
request API中介绍了两种下载方式:request.downloadFile和request.agent.create。如果仅限于下载,两者区别不大,仅仅是下载路径区别。前者的config可指定所有沙箱路径,后者的config只能指定缓存目录。但是若考虑到一些细节问题,如断点续传等,推荐第二种。
主代码
下载功能主代码要求输入下载地址(url)和下载文件名(name),并且首先基于文件名检查文件是否存在,然后创建下载任务,并且在下载过程中订阅了下载进度,即时将下载信息传递给页面进行渲染。
import fs from '@ohos.file.fs';
import request from '@ohos.request';
import Prompt from '@system.prompt';
import EventBus from './EventBus';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
let downloadTask: request.agent.Task;
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
export class DownLoader {
/**
- 下载文件
- @param url 文件地址
@param name 文件名
*/
static async downloadthisFile(url,name) {
let filePath = context.cacheDir+'/'+name;
try {// 检查文件是否存在
const fileExists = await checkFileExists(filePath);
if (fileExists) {
console.log("File already exists, deleting the existing file...");
await fs.unlink(filePath); // 删除已存在的文件
console.log("File deleted successfully.");
}// 创建下载任务
let config: request.agent.Config = {
action: request.agent.Action.DOWNLOAD,
url: url,
saveas: './'+name,
overwrite: true,
mode: request.agent.Mode.FOREGROUND,
index: 0,
begins: 0,
ends: -1,
};try {
downloadTask = await request.agent.create(getContext(), config);
console.info(Succeeded in creating a download task. result: ${downloadTask.tid}
);
downloadTask.start();
Prompt.showToast({ message: "Download task started.", duration: 1000 });// 订阅下载进度
if (downloadTask.tid) {let lastReceivedSize = 0; let lastTime = Date.now(); // 监听下载进度 let call = async (progress: request.agent.Progress) => { const Speed = calculateSpeed(progress.processed, lastTime, lastReceivedSize); const percent = (progress.processed / progress.sizes[0]) * 100; const size = (progress.sizes[0] / 1024 / 1024).toFixed(2); // MB console.log("进度 速度 大小", percent, Speed, size); // 直接更新状态 EventBus.emit('downloadProgress', percent); EventBus.emit('downloadSpeed', Speed); EventBus.emit('downloadSize', size); console.log("Download task returned:", downloadTask.tid) }; // 订阅下载进度 downloadTask.on('progress', call); console.log("Download task returned:", downloadTask.tid);
}
} catch (err) {
console.error(Failed to create a download task, Code: ${err.code}, message: ${err.message}
);
}if (!downloadTask.tid)
throw new Error("Download task failed, no task returned.");} catch (err) {
console.error(Failed to download file. Error: ${err.message}
);
}}
/**
暂停下载
*/
static async pausedownload() {
downloadTask.pause().then(() => {
console.info(Succeeded in pausing a download task.
);
}).catch((err: BusinessError) => {
console.error(Failed to pause the upload task, Code: ${err.code}, message: ${err.message}
);
});
}/**
- 恢复下载
*/
static async resumedownload() {
downloadTask.resume().then(() => {
console.info(Succeeded in resuming a download task.
);
}).catch((err: BusinessError) => {
console.error(Failed to resume the download task, Code: ${err.code}, message: ${err.message}
);
});
}
}
/**
- 计算下载速度
- @param receivedSize 已接收的字节数
- @param lastTime 上次计算速度的时间戳
- @param lastReceivedSize 上次计算速度时已接收的字节数
@returns 速度,单位KB/s
*/
function calculateSpeed(receivedSize,lastTime,lastReceivedSize) {
const currentTime = Date.now();
const timeElapsed = (currentTime - lastTime) / 1000; // 转换为秒
const bytesReceived = receivedSize - lastReceivedSize; // 新接收到的字节数// 计算速度
const speed = timeElapsed > 0 ? (bytesReceived / timeElapsed) : 0; // 字节/秒// 更新历史数据
lastTime = currentTime;
lastReceivedSize = receivedSize;return Number((speed / 1024).toFixed(2)); // 转换为KB/s
};
/**
- 检查文件是否存在
- @param filePath 文件路径
- @returns Promise 文件是否存在
*/
async function checkFileExists(filePath) {
try {
console.log("Checking file existence for:", filePath);
await fs.stat(filePath);
return true; // 文件存在
} catch (err) {
if (err.code === 'ENOENT') {
return false; // 文件不存在
} else {
console.error(Error checking file existence: ${err.message}
);
return false; // 处理其他错误
}
}
}
页面
页面主体是两个输入框,输入下载地址(url)和下载文件名(name),执行下载的按钮、暂停(继续)按钮以及一个圆形进度条。
import { DownLoader } from '../common/Download';
import EventBus from '../common/EventBus';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State download: boolean = true;
@State url: string = '';
@State fileName: string = '';
@State percent: number = 0;
aboutToAppear(): void {
// 订阅下载进度更新
EventBus.on('downloadProgress', async (percent) => {
this.percent = percent;
console.log("Updated download progress:", this.percent);
});
}
build() {
Column() {
TextInput({ text: this.url, placeholder: 'input your download url' }).margin({ top: 20 })
.onSubmit((EnterKeyType) => {
console.info(EnterKeyType + '输入法回车键的类型值')
})
TextInput({ text: this.fileName, placeholder: 'input your download file name' }).margin({ top: 20 })
.onSubmit((EnterKeyType) => {
console.info(EnterKeyType + '输入法回车键的类型值')
})
Button('Download')
.width(150)
.margin({ top: 20 })
.onClick(async ()=>{
await DownLoader.downloadthisFile(this.url,this.fileName);
})
Button(this.download ? 'Pause' : 'Resume')
.width(150)
.margin({ top: 20 })
.onClick(async ()=>{
this.download = !this.download;
this.download ? DownLoader.resumedownload() : DownLoader.pausedownload();
})
Progress({ value: this.percent, total: 100, type: ProgressType.ScaleRing }).width(100).height(100)
.margin({top: 50})
.visibility(this.percent >= 0 && this.percent <= 100 ? Visibility.Visible : Visibility.Hidden)
.backgroundColor(Color.Black)
.style({ strokeWidth: 15, scaleCount: 20, scaleWidth: 5 }) // 设置环形有刻度进度条宽度15,总刻度数为20,刻度宽度为5vp
}
.padding(20)
.width('100%')
}
}
下载过程