鸿蒙应用开发:下载功能

简介: 鸿蒙应用开发:下载功能

鸿蒙系统不断发展,有与安卓、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%')

}
}

下载过程

相关文章
|
7月前
|
存储 移动开发 Android开发
HarmonyOS应用开发者高级认证(88分答案)
HarmonyOS应用开发者高级认证(88分答案)
2666 0
|
7月前
|
JavaScript IDE 前端开发
【HarmonyOS 4.0 应用开发实战】TypeScript 快速入门之环境配置
【HarmonyOS 4.0 应用开发实战】TypeScript 快速入门之环境配置
210 0
|
7月前
|
开发框架 JavaScript 数据管理
请介绍一下鸿蒙操作系统的应用开发框架和工具。
请介绍一下鸿蒙操作系统的应用开发框架和工具。
232 0
|
7月前
|
存储 IDE 开发工具
HarmonyOS应用开发尝鲜篇:HarmonyOS快速入门
HarmonyOS应用开发尝鲜篇:HarmonyOS快速入门
|
7月前
|
JavaScript 前端开发 开发者
深入理解ArkTS:Harmony OS 应用开发语言 TypeScript 的基础语法和关键特性
深入理解ArkTS:Harmony OS 应用开发语言 TypeScript 的基础语法和关键特性
635 0
|
2月前
|
存储 开发工具 开发者
紧跟科技潮流,揭秘鸿蒙应用开发新世界:打造全场景智慧生活,你准备好迎接这场技术革命了吗?
【10月更文挑战第20天】随着华为鸿蒙系统的发布,一个全新的操作系统生态正在形成。本文将探讨基于鸿蒙系统的应用软件开发,介绍其跨设备特性、开发工具链及框架,并通过示例代码展示开发流程,帮助开发者更好地理解和利用这一平台。
40 4
|
5月前
|
存储 开发框架 安全
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段一
HarmonyOS NEXT星河版的应用开发标志着华为分布式操作系统的全新篇章,它聚焦于打造原生精致、易用、流畅、安全、智能和互联的极致体验。开发者可以利用其先进的API和工具集,如DevEco Studio,构建高性能、跨设备无缝协同的应用程序,从而充分利用HarmonyOS的分布式能力,为用户带来一致且丰富的多场景数字生活体验。随着“学习强国”、岚图汽车、中国电信等知名企业和应用的加入,鸿蒙生态正迅速扩展,引领着原生应用开发的新趋势。
204 3
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段一
|
5月前
鸿蒙打电话功能
鸿蒙打电话功能
138 0
|
7月前
|
存储 JSON JavaScript
HarmonyOS应用开发者基础认证 模拟考试 题库
HarmonyOS应用开发者基础认证 模拟考试 题库
516 0
|
7月前
|
安全 IDE 开发工具
HarmonyOS的功能及场景应用
一、基本介绍 鸿蒙HarmonyOS主要应用的设备包括智慧屏、平板、手表、智能音箱、IoT设备等。具体来说,鸿蒙系统是一款面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,通过同一套系统能力、适配多种终端形态。 二、应用HarmonyOS的设备 1、智能手机: HarmonyOS用于华为的智能手机,旨在提供更流畅的用户体验和更好的多设备协同功能。 2、平板电脑: 华为的平板电脑也可以运行HarmonyOS,使用户可以在不同设备之间共享应用和数据。 3、智能电视: HarmonyOS用于智能电视,提供智能家
222 0