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

news2025/6/1 20:13:27

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.mp4

HTTP/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 这里写四Mock
  private 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.coloradmin.cn/o/2392929.html

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

相关文章

源的企业级网络安全检测工具Prism X(棱镜X)

Prism X(棱镜X)是由yqcs团队自主研发的开源网络安全检测解决方案,专注于企业级风险自动化识别与漏洞智能探测。该工具采用轻量化架构与跨平台设计,全面兼容Windows、Linux及macOS操作系统,集成资产发现、指纹鉴别、弱口…

基于FPGA的二叉决策树cart算法verilog实现,训练环节采用MATLAB仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) MATLAB训练结果 上述决策树判决条件&#xff1a; 分类的决策树1 if x21<17191.5 then node 2 elseif x21>17191…

权限分配不合理如何影响企业运营?

“我们明明只给了她CRM的查看权限&#xff0c;怎么客户数据被删了&#xff1f;” “新员工入职三天了&#xff0c;HR系统权限还没开通&#xff0c;流程完全卡住&#xff01;” “上个月刚给项目经理配了财务权限&#xff0c;怎么又出乱子了&#xff1f;” 这些对话是否在你的…

ES分词搜索

ES的使用 前言作者使用的版本作者需求 简介ES简略介绍ik分词器简介 使用es的直接简单使用es的查询 es在java中使用备注说明 前言 作者使用的版本 es: 7.17.27spring-boot-starter-data-elasticsearch: 7.14.2 作者需求 作者接到一个业务需求&#xff0c;我们系统有份数据被…

【数据库】并发控制

并发控制 在数据库系统&#xff0c;经常需要多个用户同时使用。同一时间并发的事务可达数百个&#xff0c;这就是并发引入的必要性。 常见的并发系统有三种&#xff1a; 串行事务执行&#xff08;X&#xff09;&#xff0c;每个时刻只有一个事务运行&#xff0c;不能充分利用…

Ansys Zemax | 手机镜头设计 - 第 2 部分:光机械封装

本文该系列文章将讨论智能手机镜头模组设计的挑战&#xff0c;涵盖了从概念、设计到制造和结构变形的分析。本文是四部分系列的第二部分&#xff0c;介绍了在 Ansys Speos 环境中编辑光学元件以及在整合机械组件后分析系统。案例研究对象是一家全球运营制造商的智能手机镜头系统…

mcp-go v0.30.0重磅发布!Server端流式HTTP传输、OAuth支持及多项功能革新全面解读!

随着云原生应用和现代分布式系统需求的不断增长&#xff0c;高效、灵活且稳定的通信协议和客户端交互框架成为开发者关注的焦点。作为开源领域备受期待的项目之一&#xff0c;mcp-go再次迎来重要版本更新——v0.30.0正式发布&#xff01;本次更新版本不仅实现了众多关键功能&am…

OpenGL Chan视频学习-10 Dealing with Errors in OpenGL

bilibili视频链接&#xff1a; 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 函数网站&#xff1a; docs.gl 说明&#xff1a; 1.之后就不再单独整理网站具体函数了&#xff0c;网站直接翻译会…

美团启动618大促,线上消费节被即时零售传导到线下了?

首先&#xff0c;从市场推广与消费者吸引的角度来看&#xff0c;美团通过联合众多品牌开展大规模促销活动&#xff0c;并发放高额优惠券包&#xff0c;旨在吸引更多消费者参与购物。这种策略有助于提高平台的活跃度和交易量&#xff0c;同时也能够增强用户粘性。对于消费者而言…

搭建 Select 三级联动架构-东方仙盟插件开发 JavaScript ——仙盟创梦IDE

三级级联开卡必要性 在 “东方仙盟” 相关插件开发中&#xff0c;使用原生 HTML 和 JavaScript 实现三级联动选择&#xff08;如村庄 - 建筑 - 单元的选择&#xff09;有以下好处和意义&#xff0c;学校管理&#xff1a; 对游戏体验的提升 增强交互性&#xff1a;玩家能够通…

服务器如何配置防火墙管理端口访问?

配置服务器防火墙来管理端口访问&#xff0c;是保障云服务器安全的核心步骤。下面我将根据你使用的不同操作系统&#xff08;Linux: Ubuntu/Debian/CentOS&#xff1b;Windows Server&#xff09;介绍常用防火墙配置方法。 ✅ 一、Linux 防火墙配置&#xff08;UFW / firewalld…

Spring Boot+Activiti7入坑指南初阶版

介绍  Activiti 是一个轻量级工作流程和业务流程管理 (BPM) 平台,面向业务人员、开发人员和系统管理员。其核心是一个超快且坚如磐石的 Java BPMN 2 流程引擎。它是开源的,并根据 Apache 许可证分发。Activiti 可以在任何 Java 应用程序、服务器、集群或云中运行。它与 Spri…

如何在 Odoo 18 中创建 PDF 报告

如何在 Odoo 18 中创建 PDF 报告 Qweb 是 Odoo 强大的模板引擎&#xff0c;旨在轻松将 XML 数据转换为 HTML 文档。其功能特性包括基于属性的自定义、条件逻辑、动态内容插入及多样化的报告模板选项。这种多功能性使 Qweb 成为制作个性化、视觉吸引力强的报告、电子邮件和文档…

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用 文章目录 前言正文配置环境下载源码配置环境变量测试运行修改点说明实际运行情况 参考 前言 本文用来记录 xCoreSDK-Python的调用使用1。 正文 配置环境 配置开发环境&#xff0c;这里使用conda做python环境管理&…

VLC-QT 网页播放RTSP

先看效果图,代码在文章末尾,包含源码,vlc-qt完整的库 环境说明:VS 2017 QTQt5.13.0 MSVC2017 32位 将vlc_install 目录下的bin,include,lib里所有的东西分别放在qt目录下 bin -> C:\Qt\Qt5.13.0\5.13.0\msvc2017\bin include->C:\Qt\Qt5.13.0\5.13.0\msvc201…

【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix

【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix 文章目录 【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix一、资料准备1.去畸变影像2.相机文件3.外方位元素二、创建工程1.新建工程2.导入照片3.编辑相机文件4.编辑外方位元素文件,导入外方位元…

创建型设计模式之Prototype(原型)

创建型设计模式之Prototype&#xff08;原型&#xff09; 摘要&#xff1a; Prototype&#xff08;原型&#xff09;设计模式通过复制现有对象来创建新对象&#xff0c;避免重复初始化操作。该模式包含Prototype接口声明克隆方法、ConcretePrototype实现具体克隆逻辑&#xff…

JNI开发流程

一. 引言 最近在做一个自己的项目&#xff0c;就是基于FastDDS封装一套JAVA库&#xff0c;让android和java应用可以使用dds的功能。 由于FastDDS是使用C编写的开源库&#xff0c;因此java的类库想要调用FastDDS的接口&#xff0c;需要额外编写一个JNI层的动态库对FastDDS的接口…

STM32G4 电机外设篇(二) VOFA + ADC + OPAMP

目录 一、STM32G4 电机外设篇&#xff08;二&#xff09; VOFA ADC OPAMP1 VOFA1.1 VOFA上位机显示波形 2 ADC2.1 用ADC规则组对板载电压和电位器进行采样 3 OPAMP&#xff08;运放&#xff09;3.1 结合STM32内部运放和ADC来完成对三相电流的采样3.2 运放电路分析 附学习参考…

微服务难题?Nacos服务发现来救场

文章目录 前言1.什么是服务发现2.Nacos 闪亮登场2.1 服务注册2.2 服务发现 3.Nacos 的优势3.1 简单易用3.2 高可用3.3 动态配置 4.实战演练4.1安装 Nacos4.2 服务注册与发现示例代码&#xff08;以 Spring Boot 为例&#xff09; 总结 前言 大家好&#xff0c;我是沛哥儿。今天…