[TOC]
关于鸿蒙开发中的HAP、HSP、HAR包的区别和思考
背景声明
- 博主9年安卓开发,Web前端、Java栈的后台和node栈后台开发亦有涉猎,目前已加入鸿蒙领航者计划,正在学习鸿蒙OS NEXT开发。
- 仅讨论Stage模型下的开发
概念讲解
HAP
全称是Harmony Ability Package,这里且简单翻译为鸿蒙能力包,理解为模块化分包。
如果类比安卓开发,可以理解为android多模块项目中的module。(这里说一下差异,在项目的源代码上都是类似的结构,一个文件夹是一个module,但在打包编译上,安卓是全部合并,鸿蒙则是每个HAP是独立的,最终打包成一个应用)
HAP有两种类型,一种是entry,是应用的主模块,作为应用的入口,提供了应用的基础功能 (注意这里,也就是说,应用的主入口和一些基本功能都应该放到这个模块中来编写代码,这里应该是关系到应用启动以及自由流转功能是否快速且流畅)
另外一种是feature,特性,或者可以理解为功能模块。
总的来说HAP是将安装包的不同功能进行模块化分包的操作。
值得注意的是,HAP并不支持导出接口和ArkUI组件给其他模块使用,也就意味着模块之间是相互隔离的,这里和安卓开发完全不同,安卓的多个模块之间依然可以有层级关系(虽然这样并不是一个好的做法)
HSP
全称是Harmony Shared Package,官方称为动态共享包
HSP要求要和宿主应用具有相同的包名,如果需要给公司内部的其他应用使用,需要了解集成态HSP(建议需要用到再研究)
使用HSP的优势:
- 多个HAP/HSP共用的代码和资源放在同一个HSP中,可以提高代码、资源的可重用性和可维护性,同时编译打包时也只保留一份HSP代码和资源,能够有效控制应用包大小。
- HSP在运行时按需加载,有助于提升应用性能。
- 同一个组织内部的多个应用之间,可以使用集成态HSP实现代码和资源的共享。
根据官方文档中的工具-DevEco Service-ohpm-repo私仓搭建工具-快速开始文中有段话:
三方库包含静态共享包 HAR 包和动态共享包 HSP 包,可以通过 ohpm 命令行工具和使用 Web 页面两种方式发布。
可以得知:HSP可以发布(只能发布到私仓,在发布HAR的文档部分有提及:链接)
需要注意的是:HSP可以依赖其他HAR或HSP,不支持循环依赖,也不支持依赖传递
HAR
全称是Harmony Archive,官方称为静态共享包。
官方的设定的职责是:通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。
使用场景主要是:作为二方库,发布到OHPM私仓,供公司内部其他应用使用;或作为三方库,发布到OHPM中心仓,供其他应用使用。
同样的,需要注意的是:HAR可以依赖其他HAR,不支持循环依赖,也不支持依赖传递(HAR可以依赖HSP,但依赖HSP之后HAR仅支持应用内共享。出处。这种用法应该并不常见)
三者区别
规格 | HAP | HAR | HSP |
---|---|---|---|
支持在配置文件中声明UIAbility组件与ExtensionAbility组件 | √ | × | × |
支持在配置文件中声明pages页面 | √ | × | √ |
支持包含资源文件与.so文件 | √ | √ | √ |
支持依赖其他HAR文件 | √ | √ | √ |
支持依赖其他HSP文件 | √ | √ | √ |
支持在设备上独立安装运行 | √ | × | × |
思考和讨论
Q1:为什么会有HAP、HSP、HAR这样的设计区分?
我认为这种设计,是源于分布式系统的理念,具体体现为一次开发多端部署和自由流转两部分能力上的设计需要。
这种粒度的分包,我认为有以下优势:
- 能够提升应用的启动速度,应用启动时,可以进行部分加载、按需加载。
- 实现一次开发多端部署,能够按不同粒度的包,对应不同端,进行不同的包的替换、增加或减少,实现不同端的公共功能和不同特性的针对性整合。
- 自由流转的功能上,应该是在目标设备并没有安装这个应用的情况下,这种分包设计能够体现出最大优势,通过网络把必须的包进行传递,将运行内存同步之后理论上就可以正常接续工作了(这里是分析猜测,具体的实现应该有更精妙的策略)
那么顺便总结一下各种包的实际用处:
- HAP主要用于按模块封包不同的功能,方便按需加载。
- HSP主要用于多模块的资源、代码段等共用,但是只局限于应用内部或者公司内部的不同应用。HSP在应用打包时仅保留一份,并且不同模块加载时会按需加载HSP。
- HAR主要用于二方库或三方库的封装,能够被HAP和HSP依赖和使用,但HAR会被重复打包进HSP和HAP中。
实际使用中应该是这样的:
- 项目分为多个模块(HAP),每个模块管理自己的依赖(HSP、HAR)
- 多模块共用的资源、代码段等,在项目建立library或者新建项目,打包为HSP
- 项目内部或者公司内部共用的工具包一类,建立项目,打包发布为HSP
- 开源共用的二方库或三方库,打包发布为HAR(不开源的官方还是推荐以HSP的形式使用)
Q2:为什么编译HAP和HSP时,会把他们所依赖的HAR直接编译到HAP和HSP中?
我认为是为了自由流转的按需加载的时候,保持一定大小的颗粒度,减少包的数量,一方面在传输上每个包都会是一个新的传输,不如减少包的数量,从而增加单位时间内平均的传输速度,也就是数据量。(参考我们ohpm install的时候的操作对比就可以了解了)。
还有就是装载包,比如确保我装载入口HAP以及必要的HSP之后,程序就可以开始运行了
在开发上,因为依赖不传递,每个模块可以声明自己需要的依赖可以避免模块依赖不需要的sdk(勉强算是一个好处)
另外因为HSP和HAR都是依赖不传递的,HAR编译打包到HSP中,这样HAP依赖HSP的时候就不用单独添加HSP依赖的HAR了(但是这个并不是主要原因,并且HAP需要使用HAR时,还需要显式的添加依赖,并且HAR会再次打包进HAP)
翻译过来就是项目中的模块,添加HSP依赖的时候,不用把HSP的依赖也添加一遍了(HSP完整)
Q3:能不能有更理想的方案?
我还是觉得依赖不传递,HAR重复打包的这种设定,不是一个最理想的方案,因为这些工作不应该也没必要推给开发者,同时这三个概念对开发者形成了一定的学习成本,在开发上,依赖的管理也成了一个负担。
问题1,依赖不能传递
依赖不能传递是不是一种不得已的设定?这是明确不利于封装和共用的,如果项目足够复杂,每个模块的依赖清单可能就要难以管理了。
更理想的想法来说,能不能实现依赖传递,比如在添加依赖时,开发者自己能够决定依赖是否传递,但IDE能够在编译阶段,自动判断,自动依赖,而打包模式实际不变,这样重复的手动配置依赖的操作就减少了。
问题2,HAR重复打包
同样的HAR重复打包,我理解为是一种为了分布式系统的一种设计,有优势,也有妥协。整体来说,已经是先进的了,遥遥领先 : P。
对于重复打包的这种情况,能不能有更理想的方案,比如说支持依赖传递,然后在不同的HAP进行重复打包。或者可以进行独立的包管理,每个依赖都是一个包,其中的依赖关系,加载关系,在打包时进行预置(接问题3)。
问题3,包的流转优化
假设依赖支持传递并且打包进行独立的包管理的前提下:自由流转时的依赖包流转,是不是可以在目标设备建立包管理库,按包名、版本、hash等进行比对,对包进行计数和复用管理。自由流转到目标设备时,已存在的直接复用,可以减少包传输,减少流转耗时,以及减少设备机身存储占用。
以上关于依赖传递和打包方案的思考和讨论,各位读者是否有更好的思路,欢迎评论区讨论 : P。