HarmonyNext使用request.agent.download实现断点下载

filedownlaod(API12)

📚简介

filedownload 这是一款支持大文件断点下载的开源插件,退出应用程序进程杀掉以后或无网络情况下恢复网络后,可以在上次位置继续恢复下载等

版本更新—请查看更新日志!!! 修复已知bug,demo已经更新

📚下载安装

ohpm install @ohos_lib/filedownload

1、添加权限在应用主模块entry/src/main/ets/module.json5下

"requestPermissions": [{"name" : "ohos.permission.INTERNET"},{"name" : "ohos.permission.GET_NETWORK_INFO"},]

2、在应用主模块entry入口EntryAbility onCreate生命周期里下面添加初始化数据库操作

 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');SqliteHelper.getInstance(this.context).initRDB();
}

3、在应用主模块entry入口Index.ts AboutToAppear()生命周期里添加如下代码

 try {await DownloaderUtil.persistActiveDownloads();
}catch (e) {
}

4.首先确定服务器是否支持断点下载,否则通过request.agent.create无法实现断点下载

 curl -I -H "Range: bytes=0-100" 下载路径
出现206 Partial Content 就代表着服务器支持断点续传与下载 —如下
yanruifeng@bogon video % curl -I -H "Range: bytes=0-100" https://dal-video.wenzaizhibo.com/a6dac8c6371a54477a5692f46ea9698e/6825c7da/00-x-upload/video/205971345_ae77bc38ae8b689a5a534e51b3153c8b_Kg3W8sai.mp4HTTP/1.1 206 Partial Content

filedownload相关 API

方法介绍
persistActiveDownloads()断点下载的主要方法「内置更改数据库状态,把断点前后字节数统一合并成一个文件」
static async pause(taskId: string):Promise下载暂停方法「内置更改数据库状态」
static async resume(downloadInfo: IFileDownloader):Promise下载恢复方法 「内置更改数据库状态」
static async delete(userId: string, downloadId: string):Promise删除「取消下载」方法「删除数据库表记录,删除文件系统下载文件、」
static async downloadFile(data: T, isBatchInsertQueue?: boolean)通用下载方法
GTNetworkUtil网络相关工具类 「监听有网、无网状态」
FileUtil文件操作相关工具类 「沙盒文件存储、删除等操作」
SqliteHelper数据库操作类、「增删改查」
static addListener(eventName:string,callback:(download:IFileDownloader)=>void)下载统一监听回调类「进度监听、失败、恢复、成功、暂停」
基本用法
import { IFileDownloader } from '@ohos_lib/filedownload/src/main/ets/interface/IFileDownloader';
import {DownloaderUtil,DownloadManager, NetworkCallback, SqliteHelper,GTNetworkUtil} from '@ohos_lib/filedownload'
import { DownloadStatus } from '@ohos_lib/filedownload/src/main/ets/constants/DownloadStatus';
import { relationalStore } from '@kit.ArkData';
import { promptAction, router } from '@kit.ArkUI';
import { IResponseData } from '../interfaces/IResponseData';@Entry
@ComponentV2
struct SingleFileDownload {@Local userId:string ='722134343434343434';//登录用户信息id 这里写四Mockprivate networkCallback:NetworkCallback={netAvailableCallback: (netHandle: ESObject) => {promptAction.showToast({message:'网络可用~'})},netLostCallback: (_: ESObject) => {promptAction.showToast({message:'网络连接已断开,请检查~'})//无网络情况下,恢复网络后继续保持在上次位置下载 --只需要调用如下一行代码即可// 本质逻辑内部还是发送了一个监听,统一在DownloadManager.addListener监听处理DownloaderUtil.persistActiveDownloads()}}@Local data: IResponseData[] = [];async aboutToAppear() {this.loadData();getContext().eventHub.on('reQuery',()=>{this.loadData();})DownloadManager.addListener(DownloadManager.eventName,(downloadInfo:IFileDownloader)=>{console.log('更新回调',downloadInfo.downloadSize)//进度监听更新回调let newData =  this.data?.map((item)=>{if(item.downloadId===downloadInfo.downloadId){item.taskId = downloadInfo.taskId;item.filePath = downloadInfo.filePath;item.fileName =downloadInfo.fileName;item.downloadSize = downloadInfo.downloadSize;item.fileSize = downloadInfo.fileSize;item.isBackgroundPause =downloadInfo.isBackgroundPause;item.exitFrequency = downloadInfo.exitFrequency;item.status = downloadInfo.status;item.begins = downloadInfo.begins;return item;}return item;})this.data =newData;})//完善在无网络情况下,下载任务暂停,并且恢复网络后继续下载GTNetworkUtil.register(this.networkCallback)}//TODO tips: 下载失败,首先检查url是否可以正常访问,或者浏览器是否可以正常在线下载async loadData(){// TODO 假设从网络获取数据数据结构为: response=[{classNumber:'76432121445578293',className:'第一章 第一讲:At the Airport在机场'}]//转换数据结构response时接口类型必须要继承 extends IFileDownloader IFileDownloader接口类型初始化至少包含三个字段userId ,downloadId,url userId登录用户的userId//因此extends IFileDownloader过的IResponseData接口类型 对应转换后的数据如下所示let result:IResponseData[] =[{classNumber:'76432121445578293',downloadId:'76432121445578293',className:'第一章 第一讲:At the Airport在机场',"url": "http://dal-video.wenzaizhibo.com/13c7d34a1181dddad67cfbe387977842/6836c525/00-x-upload/video/209245033_3aaf16a38aff214594fffec92839d37e_n8kGbGC8.mp4",       userId:this.userId}]//从数据库读取获取上次的下载进度let predicates =new relationalStore.RdbPredicates(SqliteHelper.tableName);predicates.equalTo('userId',this.userId);let queryList = await SqliteHelper.getInstance(getContext()).queryData(predicates);if(queryList.length>0){let newData = result.map((item:IResponseData)=>{let obj =queryList.find(el=>el.downloadId===item.downloadId);if(obj) {item.taskId = obj.taskId;item.filePath = obj.filePath;item.fileName =obj.fileName;item.downloadSize = obj.downloadSize;item.fileSize = obj.fileSize;item.isBackgroundPause =obj.isBackgroundPause;item.exitFrequency = obj.exitFrequency;item.status = obj.status;item.begins = obj.begins;return item;}return item;})this.data= newData;}else{this.data = result;}}aboutToDisappear(): void {GTNetworkUtil.unregister();DownloadManager.removeListener(DownloadManager.eventName)getContext().eventHub.off('reQuery');}getStatus(status:number|undefined){switch (status){case DownloadStatus.COMPLETED:return '下载完成'case DownloadStatus.PAUSE:return '暂停'case DownloadStatus.FAILED:return '下载失败'case DownloadStatus.RUNNING:return '下载中'default :return '下载'}}@Builder imageAnimator(item:IResponseData){ImageAnimator().images([{src: $r('app.media.ic_downloading_1')},{src: $r('app.media.ic_downloading_2')},{src: $r('app.media.ic_downloading_3')},{src: $r('app.media.ic_downloading_4')},{src: $r('app.media.ic_downloading_5')}]).duration(1000).state(item.status===DownloadStatus.RUNNING?AnimationStatus.Running:AnimationStatus.Initial).reverse(false).fillMode(FillMode.None).iterations(-1).width(24).height(24).onStart(() => {console.info('Start')}).onPause(() => {console.info('Pause')}).onRepeat(() => {console.info('Repeat')}).onCancel(() => {console.info('Cancel')}).onFinish(() => {console.info('Finish')})}build() {Column() {Stack({alignContent:Alignment.TopStart}){ForEach(this.data,(item:IResponseData)=>{Flex({direction:FlexDirection.Row,alignItems:ItemAlign.Center,justifyContent:FlexAlign.SpaceBetween}) {Row(){Text(item?.className).fontSize(16).fontWeight(FontWeight.Bold)}.layoutWeight(1)if(item.status===DownloadStatus.COMPLETED){Image($r('app.media.ic_download_completed')).width(24).height(24)}else if(item.status===DownloadStatus.RUNNING) {this.imageAnimator(item);}else if(item.status===DownloadStatus.FAILED){Image($r('app.media.ic_download_fail')).width(24).height(24)}else if(item.status===DownloadStatus.PAUSE){Image($r('app.media.ic_download_start')).width(24).height(24)}}.width('100%').height(44).onClick(async ()=>{if (item?.status === DownloadStatus.RUNNING) { //下载中---->点击触发取消下载【删除下载】let number =  await DownloaderUtil.delete(item.userId,item.downloadId);if(number>0){this.loadData();}} else if (item?.status === DownloadStatus.FAILED) { //下载失败----> 重新下载DownloaderUtil.downloadFile(item);} else if (item?.status === DownloadStatus.PAUSE) { //下载暂停----->代表要恢复下载await DownloaderUtil.resume(item);} else if(item.status===DownloadStatus.COMPLETED) { //下载完成 ---->去播放router.pushUrl({url: 'pages/VideoPlayerPage',params:{url:'file:///'+item.filePath+'/'+item.fileName,}})}else{ //未下载 -->去下载promptAction.showToast({message:'开始下载',})DownloaderUtil.downloadFile(item);}}).padding({left: 16,right: 16}).margin({top: 32})})}.layoutWeight(1)Button('查看下载').type(ButtonType.Capsule).onClick(()=>{router.pushUrl({url:'pages/DownloadManagerPage',params:{data:this.data,userId:this.userId}})}).backgroundColor(Color.Red)}.height('100%').width('100%')}
}
运行Demo演示效果
  • demo 运行 git clone https://github.com/yrjwcharm/ohos_library.git
  • 切换分支 git checkout feature/ohos/fileDownload
下载观看Demo演示效果–退出应用程序杀掉进程后恢复下载

点击下载视频

下载观看Demo演示效果–无网络情况下恢复网络后继续保持下载

点击下载视频

鸿蒙技术交流QQ群:783867484
开源不易,希望您可以动一动小手点点小⭐⭐
👴希望大家如有好的需求踊跃提交,如有问题请前往github提交issue,空闲时间会扩充与修复优化

🌏开源协议

本项目基于 Apache License 2.0 ,在拷贝和借鉴代码时,请大家务必注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/907560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx: [emerg] bind() to 0.0.0.0:80 failed (10013: 80端口被占用

Nginx启动报错:nginx: [emerg] bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a socket in a way forbidden by its access permissions) 这个报错代表80端口被占用 先查看占用80的端口 netstat -aon | findstr :80 把它杀掉,强…

embbeding 视频截图

Embedding是什么?有什么作用?是怎么得到的?_哔哩哔哩_bilibili

服务器tty2终端如何关机

在服务器的 tty2 或其他虚拟终端上,要安全地进行关机操作,可以使用以下命令之一: 1.1 使用 shutdown 命令: shutdown 命令可以计划系统关机。默认需要超级用户权限。 sudo shutdown -h now-h 选项表示关机(halt&…

时序数据库IoTDB启动方式及集群迁移指南

IoTDB启动方式 IoTDB在配置启动时有两种推荐方式: ‌主机名启动‌: ‌推荐理由‌:主机名启动方式更为灵活,便于在不同网络环境中部署相同的IoTDB实例。‌工作原理‌:IoTDB启动后会维护一张节点编号与网络地址的映射表…

如何在Qt中绘制一个带有动画的弧形进度条?

如何在Qt中绘制一个弧形的进度条 在图形用户界面开发中,进度指示控件(Progress Widget)是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件,用于绘制圆弧形进度条。当然,笔者看了眼公开…

在 Mac 下 VSCode 中的终端使用 option + b 或 f 的快捷键变成输入特殊字符的解决方案

前言 在终端里,我们可以使用 option b 和 option f 来在我们输入的命令中进行快速的前后调整光标,但是,在未设置的情况下,在 MacOS 中,会变成输入特殊字符。 普通键盘上是 alt b 和 alt f ,只是叫法不…

Android bindservice绑定服务,并同步返回service对象的两个方法

先上一段代码: private IDeviceService deviceService null; private ServiceConnection connnull; private synchronized void bindyourservice() { Intent intent new Intent();intent.setPackage("servicepackagename");intent.setAction("…

Go语言之空接口与类型断言

Go 语言中,接口是一种强大的抽象机制。其中,空接口(interface{})和类型断言为我们提供了处理任意类型与类型检查的能力。 一、空接口(interface{}) 空接口是 Go 中最特殊的接口:不包含任何方法…

三、OrcaSlicer预设显示

一、界面类 主框架使用的是wxWidgets库;3D模型的渲染区的控件,使用的是imgui库。 1、Plater 此类在OrcaSlicer\src\slic3r\GUI\Plater.hpp文件中定义 1.1 Plater::priv 此结构体是Plater的数据类,各种数据的对象和指针保存在此结构体中。如…

00 QEMU源码中文注释与架构讲解

QEMU源码中文注释与架构讲解 先占坑:等后续完善后再更新此文章 注释作者将狼才鲸创建日期2025-05-30更新日期NULL CSDN阅读地址:00 QEMU源码中文注释与架构讲解Gitee源码仓库地址:才鲸嵌入式/qemu 一、前言 参考网址 QEMU 源码目录简介qe…

一、Sqoop历史发展及原理

作者:IvanCodes 日期:2025年5月30日 专栏:Sqoop教程 在大数据时代,数据往往分散存储在各种不同类型的系统中。其中,传统的关系型数据库 (RDBMS) 如 MySQL, Oracle, PostgreSQL 等,仍然承载着大量的关键业务…

【Halcon】图像分割中的 regiongrowing 与dyn_threshold 动态阈值 算法详解对比

图像分割中的 regiongrowing 与动态阈值算法详解对比 在使用 HALCON 进行图像处理时,图像分割是最常见也最关键的操作之一。本文将深入讲解 regiongrowing 算子的原理与使用方法,并与另一常见方法——动态阈值 (dyn_threshold) 进行详细对比&#xff0c…

Docker部署项目无法访问,登录超时完整排查攻略

项目背景:迁移前后端应用,prod环境要求保留443端口,开发环境37800端口,后端容器端口为8000,前端为80,fastAPI对外端口为41000 生产环境部署在VM01,开发环境部署在VM03,在VM01配置nginx转发 [r…

充电便捷,新能源汽车移动充电服务如何预约充电

随着新能源汽车的普及,充电便捷性成为影响用户体验的关键因素之一。传统的固定充电桩受限于地理位置和数量,难以完全满足用户需求,而移动充电服务的出现,为车主提供了更加灵活的补能方式。通过手机APP、小程序或在线平台&#xff…

探索C++标准模板库(STL):从容器到底层奥秘-全面解析String类高效技巧(上篇)

前引:在现代软件开发中,字符串处理是几乎所有程序的核心需求之一。无论是文本解析、网络通信,还是用户交互,高效且安全的字符串操作能力直接决定了代码的质量与可维护性。而C标准模板库(Standard Template Library, ST…

Python爬虫实战:抓取百度15天天气预报数据

🌐 编程基础第一期《9-30》–使用python中的第三方模块requests,和三个内置模块(re、json、pprint),实现百度地图的近15天天气信息抓取 记得安装 pip install requests📑 项目介绍 网络爬虫是Python最受欢迎的应用场景之一&…

HTML常见事件详解:从入门到实战应用

前言 在Web开发中,事件是用户与网页交互的核心机制。HTML事件让我们能够响应用户的各种操作,如点击、鼠标移动、键盘输入等。掌握HTML事件是前端开发的基础技能之一,本文将深入探讨HTML中的常见事件类型及其实际应用。 HTML事件概览总结 H…

模具制造业数字化转型:精密模塑,以数字之力铸就制造基石

模具被誉为 “工业之母”,是制造业的重要基石,其精度直接决定了工业产品的质量与性能。在工业制造向高精度、智能化发展的当下,《模具制造业数字化转型:精密模塑,以数字之力铸就制造基石》这一主题,精准点明…

深度解读漏洞扫描:原理、类型与应用实践

在网络安全领域,漏洞就像隐藏在系统中的定时炸弹,随时可能被攻击者利用,导致数据泄露、服务瘫痪等严重后果。而漏洞扫描作为发现这些潜在威胁的 “侦察兵”,是保障网络安全的重要防线。本文将全面介绍漏洞扫描的相关知识&#xff…

[HNCTF 2022 Week1]silly_zip

下载附件 解压发现需要密码 用010打开看看,发现是伪加密 改成00点击保存 解压后得到图片 感觉图片看着怪怪的,修改一下高度看看有没有其他线索 把47改成78 最后得到flag