鸿蒙应用开发:下载功能

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

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

}
}

下载过程

相关文章
|
2月前
|
人工智能 JavaScript API
【HarmonyOS NEXT+AI】问答03:找不到DevEco Studio Cangjie Plugin下载链接?
本文针对学员在“HarmonyOS NEXT+AI大模型打造智能助手APP(仓颉版)”课程中提出的问题进行解答:为何无法在华为开发者社区官网找到DevEco Studio Cangjie Plugin下载链接。文中详细介绍了Cangjie Plugin的功能及获取方式,包括STS和Canary版本的申请流程,并提供了学习仓颉编程语言的资源与建议。对于普通开发者,STS版本是当前首选;同时,通过课程与官方教程,可快速掌握仓颉语言核心语法及API,助力开发HarmonyOS NEXT AI智能助手应用。
101 3
【HarmonyOS NEXT+AI】问答03:找不到DevEco Studio Cangjie Plugin下载链接?
|
17天前
|
IDE API 开发工具
鸿蒙开发:DevEcoStudio中那些实用的小功能
本篇文章就暂时给大家盘点四个,在后续的文章中,关于DevEco Studio中能够提升我们开发效率的功能,也会不间断的进行总结。
65 12
鸿蒙开发:DevEcoStudio中那些实用的小功能
|
21天前
HarmonyOS实战:Tab顶部滑动悬停功能实现
在鸿蒙开发中,实现Scroll嵌套List列表滑动时顶部悬停的效果是一个常见需求。本文详细介绍了如何通过布局和事件处理来实现这一功能。首先,使用Scroll嵌套List和Tab布局来构建基础页面。然后,通过设置nestedScroll属性为NestedScrollMode.PARENT_FIRST,确保外层Scroll优先滑动。接着,通过监听List和Scroll的滑动事件,处理滑动冲突,确保在特定条件下Scroll停止滑动,将滑动事件交给List处理。最终,实现了在上下滑动时优先让Scroll滑动的效果,并提供了扩展思路,如优先让List滑动等。
93 10
HarmonyOS实战:Tab顶部滑动悬停功能实现
|
7天前
|
API 开发者
鸿蒙NEXT上传图片功能PhotoViewPicker核心功能解析
`PhotoViewPicker` 是鸿蒙系统中用于媒体资源选择的核心组件,通过它可以便捷地实现图片、视频等媒体文件的选择功能。下面从基本用法、参数配置到高级应用进行全面解析:
35 1
|
20天前
|
定位技术 API
HarmonyOS实战:高德地图定位功能完整流程详解
本文详细介绍了在鸿蒙系统中使用高德地图实现完整定位功能的流程。首先分析需求,包括权限申请、检查GPS状态、单次或多次定位选择以及定位失败处理。接着通过代码实现具体步骤:添加定位权限、申请用户权限、检查GPS开关状态、启动定位服务,并处理定位成功或失败的情况。若定位失败,可尝试获取历史定位信息或使用默认位置。最后总结指出,虽然定位功能基础简单,但完整的流程与细节处理才是关键。建议读者动手实践,掌握高德地图定位功能的使用。
130 15
|
11天前
|
前端开发 容器
32.[HarmonyOS NEXT Row案例一(上)] 使用Row组件创建水平排列的功能按钮组
HarmonyOS NEXT提供了丰富的布局组件,其中Row组件是一种常用的水平布局容器,可以将子组件按照水平方向排列。本教程将详细讲解如何使用Row组件创建一个水平排列的功能按钮组,重点介绍基础间距与对齐的设置方法。
27 4
|
23天前
|
存储 安全 数据安全/隐私保护
HarmonyOS5云服务技术分享--匿名登录功能指南
本文为开发者详解如何实现应用的“游客模式”登录功能,让用户无需注册即可快速体验APP。通过5步集成指南(环境准备、初始化认证模块、智能登录检测、一键游客登录及账号升级策略),手把手教你完成开发流程。同时分享安全守则与高阶技巧,如敏感操作防护和事件监听等,帮助优化用户体验并提升留存率。文末更有小互动,期待你的观点交流!
|
22天前
|
JSON 数据格式
HarmonyOS实战: 城市选择功能的快速实现
本文详细介绍了在开发城市选择功能时,如何处理城市列表中的多音字、按字母顺序排列城市以及将首字母相同的城市分组的技术实现。首先,通过使用pinyin4js库处理多音字,确保每个城市名称的首字母正确。接着,利用Intl.Collator对城市数据进行字母排序。最后,通过遍历和条件判断,将首字母相同的城市分组,并使用ListItemGroup和sticky功能在UI中展示分组结果。文章强调了分组处理的复杂性,并鼓励读者动手实践以加深理解。
122 6
|
22天前
|
JavaScript 前端开发 Java
HarmonyOS NEXT~鸿蒙系统下的Cordova框架应用开发指南
《HarmonyOS NEXT:鸿蒙系统下的Cordova框架应用开发指南》详细介绍如何将Cordova应用适配到鸿蒙系统。文章涵盖兼容性分析、环境配置、特性适配、性能优化及发布调试等内容。尽管Cordova官方暂无直接支持,但通过Cordova-Android平台与定制插件可实现功能扩展。开发者需注意性能差异,并借助插件机制融入鸿蒙特色功能,如服务卡片和分布式能力。未来,随着鸿蒙生态完善,Cordova在该平台的应用将更加广泛且高效。
111 1
|
2月前
|
人工智能 物联网 编译器
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡
79 11
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡