前面我们了解了如何构建鸿蒙应用以及开发了第一个页面,这只是简单的demo;那么如何去设计,从0到1搭建一个真正的应用呢
一、基本概念
1、Stage模型基本概念
Stage模型概念图
AbilityStage:是一个Module级别的组件容器,在HAP首次加载时创建,做一些初始化等操作
Context:提供在运行期可以调用的各种资源和能力
UIAbility:是一种包含UI的应用组件,主要用于和用户交互,
ExtensionAbility组件是一种面向特定场景的应用组件,例如卡片场景的FormExtensionAbility
WindowStage:与UIAbility实例绑定,包含一个主窗口为ArkUI提供了绘制区域
Page:表示应用/服务的一个页面
2、包类型概念
使用场景
APP:用于应用上架发布到应用市场,可以包含多个hap/hsp
HAP:entry用于实现应用入口,以及应用的主功能,feature用于特性功能
HSP:多模块共享代码、运行时按需加载、元服务分包预加载
HAR:作为二方/三方库发布到仓库供其他依赖使用
如何选择HAR/HSP包
二、现有业务分析
在搭建框架之前我们需要对即将要开发的应用有个基本的认知
1、业务复杂度
业务的复杂度影响我们需不需要组件化开发,如果需要组件话开发,我们首先需要对当前对整体架构进行划分,通常会划分成三层架构:主工程(组合各业务打包) + 业务层(包括子业务及其公用的通用业务)+ 基础能力层(三方库及其二次封装)。
当然可能很多应用都是从Android转鸿蒙来的,所以我们可以针对现有的架构进行改造,满足鸿蒙应用需求
2、是否需要多任务
- 传统设备上,应用是单任务单窗口的形式,在一些场景下,多任务多窗口的形态可以让用户获得更好的用户体验,比如文档编辑应用,可让用户同时打开编辑多个文档
- Stage模型下UIAbility组件之间不会形成栈的结构,每个UIAbility组件实例都会创建一个类似独立应用一样的任务
在进行功能设计时,需要对应用本身是否支持多任务多窗口,结合起来考虑Ability组件的设计,这影响整体工程模块化的结构
- 对于单Ability的情况下,单任务类(singleton模式)或者多任务类(multiton/specified模式)应用,如文档编辑应用,建议采用单HAP来承载UIAbility。
- 对于多Ability有两种情况:
- 对于多窗口类型的应用,如果功能不同,通过不同的UIAbility承载,如导航/打车应用,导航功能和主页属于不同的功能,要作为两个任务呈现给用户,可以将该模块作为Feature类型的HAP承载相应的UIAbility组件。
- 对于应用的一些拓展功能如卡片、分享业务,其不会作为单独的任务和窗口形态运行,并且是由系统提供的独立ExtensionAbility来承载,从更好拆分业务来考虑,也建议通过Feature类型的HAP承载单独的ExtensionAbility组件。
3、是否有按需加载模块
- 什么是按需加载:某个功能模块,使用时由用户决定安装时机,动态从应用市场下载安装使用
- 按需加载的好处:减少包体积、减少系统资源
对于按需加载的模块可以设计成Feature类型的HAP或者HSP,两者区别在于Feature类型的HAP可以包含Ability组件
结合前面的是否需要多任务以及业务是否需要按需加载,将应用划分以下两个场景:
- 单HAP工程:如果只包含一个UIAbility组件,无需使用ExtensionAbility组件,优先采用单HAP实现应用开发,按需加载使用HSP,其他使用HAR作为模块。
- 多HAP工程:多个UIAbility组件实现多任务,或者需要使用ExtensionAbility组件实现拓展功能,可以采用多HAP(Entry+多Feature),每个HAP中包含一个UIAbility组件或者一个ExtensionAbility组件
4、是否需要“一多”开发
定义:一套代码工程,一次开发上架,多端按需部署
“一多”开发是鸿蒙的一大特性,可以让用户享受全场景体验,也能为应用带来潜在用户群体
“一多”推荐在应用开发过程中使用如下的“三层工程结构”。
- common(公共能力层):用于存放公共基础能力集合(如工具库、公共配置等)。可编译成一个或多个HAR/HSP包,其只可以被products和features依赖,不可以反向依赖。
- features(基础特性层):用于存放基础特性集合(如应用中相对独立的各个功能的UI及业务逻辑实现等)。不需要单独部署的feature通常编译为HAR包或HSP包,供products或其它feature使用,但是不能反向依赖products层。需要单独部署的feature通常编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层可以横向调用及依赖common层。
- products(产品定制层):用于针对不同设备形态进行功能和特性集成。products层各个子目录各自编译为一个Entry类型的HAP包,作为应用主入口,products层不可以横向调用。
代码工程结构抽象如下:
三、单HAP架构
对于单UIAbility应用的APP工程而言,其仅包含一个Entry类型的HAP,其划分的模块则是根据是否有按需加载的需求,来考虑采用HAR模块和HSP模块。
注意:这里说的仅有一个HAP指的是一种设备类型仅有一个HAP,而不是.app文件包里面仅有一个HAP。因为.app里面可以包含其他设备的HAP包,如手表、大屏,进行多设备分发。
1、不包含按需加载模块
对于不需要按需加载的单HAP类型App来讲,可以直接全部采用HAR进行开发设计,如上图phone.hap所示
设计成HAR包有如下好处:
- 全部编译进HAP,无额外的HSP,节省HSP的安装和加载成本。
- HAR在编译进HAP时,可以利用ArkTS的语言特性和编译器功能,做类型推断和编译优化。
- 代码工程架构简单,后续演进较为灵活。
2、包含按需加载模块
在单HAP工程内,如果要实现按需加载功能,那么对应的组件需要采用HSP作为按需加载组件模块,如上图tablet.hap。这种情况下,由于hsp和业务3har都依赖相同的har(基础库2/基础库3),使得它们在应用内存在多份。另一方面,HSP是动态库相比于HAR安装和加载均会有一些性能损失,过多的HSP可能会影响安装效率和App启动性能。所以需要根据业务实际情况,在App Size与特性启动性能之间做好平衡。
性能优先:对于性能比较敏感的,则不需要再封装一个公共的HSP模块,直接依赖公共HAR包
Size优先:对于App Size比较看重的,可以考虑将公共依赖的模块封装成为一个HSP模块壳
四、多HAP架构
对于同一个设备类型,如果要实现独立的功能模块,且具有单独入口的功能特性,建议做成一个独立特性的HAP,按需下载安装。此时一个App包中,就会有多个HAP包。多HAP之间业务独立,但是可能会有业务能力共享。
前面我们了解Feature类型的HAP和HSP包是相似的,所以多HAP架构和HAP+HSP组合类似,在包含公共能力模块的情况下需要考虑在App Size与启动性能之间做平衡
五、UI设计
1、ArkUI架构模式
ArkUI采取MVVM模式,其中状态管理模块起到的就是ViewModel的作用,将数据与视图绑定在一起,更新数据的时候直接更新视图
- Model层:存储数据和相关逻辑的模型。它表示组件或其他相关业务逻辑之间传输的数据。Model是对原始数据的进一步处理。
- View层:在ArkUI中通常是@Component装饰组件渲染的UI。
- ViewModel层:在ArkUI中,ViewModel是存储在自定义组件的状态变量、LocalStorage和AppStorage中的数据。
- 自定义组件通过执行其build()方法或者@Builder装饰的方法来渲染UI,即ViewModel可以渲染View。
- View可以通过相应event handler来改变ViewModel,即事件驱动ViewModel的改变,另外ViewModel提供了@Watch回调方法用于监听状态数据的改变。
- 在ViewModel被改变时,需要同步回Model层,这样才能保证ViewModel和Model的一致性,即应用自身数据的一致性。
- ViewModel结构设计应始终为了适配自定义组件的构建和更新,这也是将Model和ViewModel分开的原因。
2、UI分层设计
视图层:包括组件/页面以及交互(touch、click等)
服务层:用于获取并处理数据,与界面进行绑定同时数据变化自动更新界面
数据层:提供原始数据,包括网络和本地数据
六、“一多”开发
OpenHarmony系统面向多终端提供了“一次开发,多端部署”(简称“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用
前面我们了解了“一多”开发推荐三层结构,推荐在common目录中存放基础公共代码,features目录中存放相对独立的功能模块代码,product目录中存放完全独立的产品代码。
前面我们介绍单/多HAP架构就已经采用这种结构
如何实现“一多”的目标
- 不同设备间的屏幕适配:自适应布局 + 响应式布局
- 不同设备系统能力差异的兼容:SysCap机制
七、最佳实践
最后我们可以参考官方为我们提供的架构设计最佳实践:HMOS世界App
另外这里对当前有的Sample资源进行了汇总