HarmonyOS:一次开发,多端部署(4)
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ )
➤GitHub地址:https://github.com/strengthen
➤原文地址:https://www.cnblogs.com/strengthen/p/18513894
➤如果链接不是为敢技术的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
概述
随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。HarmonyOS 系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。
定义和目标
定义:一套代码工程,一次开发上架,多端按需部署。
目标:支撑开发者快速高效的开发支持多种终端设备形态的应用,实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。
关键问题
为了实现“一多”的目标,需要解决如下三个基础问题:
问题1:页面如何适配
不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。
问题2:功能如何兼容
不同设备的系统能力有差异,如智能穿戴设备是否具备定位能力、智慧屏是否具备摄像头等,功能如何兼容。
问题3:工程如何组织
如何实现一套代码同时能部署到多种不同设备上,代码工程如何组织。
关键问题的解决思路
针对“一多”提出的三个基础问题,可以从界面级、功能级、工程级三个维度给出相关问题的解决思路:
界面级一多
页面级一多需要考虑不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。可以从布局能力、资源使用、交互归一几个方面去考虑。
布局能力
布局决定了页面中的元素按照何种方式排布及显示,是页面设计及开发过程中首先需要考虑的问题。一般情况下,可以通过页面(或自定义组件)内的组件结构(组件个数、组件的父子/兄弟关系、组件类型、组件的相对位置)来判断使用何种布局能力。
- 对于随尺寸变化组件结构相同的场景,可以在开发过程中灵活使用自适应布局能力来达到目标效果。
- 对于随尺寸变化组件结构不同的场景,更适合使用响应式布局能力来实现不同尺寸下的不同显示的效果。
布局可以分为自适应布局和响应式布局,二者的介绍如下表所示:
名称 |
简介 |
---|---|
自适应布局 |
当外部容器大小发生变化时,元素可以根据相对关系自动变化以适应外部容器变化的布局能力。相对关系如占比、固定宽高比、显示优先级等。当前自适应布局能力有7种:拉伸能力、均分能力、占比能力、缩放能力、延伸能力、隐藏能力、折行能力。自适应布局能力可以实现界面显示随外部容器大小连续变化。 |
响应式布局 |
当外部容器大小发生变化时,元素可以根据断点、栅格或特定的特征(如屏幕方向、窗口宽高等)自动变化以适应外部容器变化的布局能力。当前响应式布局能力有3种:断点、媒体查询、栅格布局。响应式布局可以实现界面随外部容器大小有级不连续变化,通常不同特征下的界面显示会有较大的差异。 |
自适应布局
针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。
自适应布局能力 |
使用场景 |
实现方式 |
---|---|---|
拉伸能力 |
容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。 |
Flex布局的flexGrow和flexShrink属性 |
均分能力 |
容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。 |
Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly |
占比能力 |
子组件的宽或高按照预设的比例,随容器组件发生变化。 |
基于通用属性的两种实现方式: - 将子组件的宽高设置为父组件宽高的百分比 - layoutWeight属性 |
缩放能力 |
子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。 |
布局约束的aspectRatio属性 |
延伸能力 |
容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。 |
基于容器组件的两种实现方式: - 通过List组件实现 - 通过Scroll组件配合Row组件或Column组件实现 |
隐藏能力 |
容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏。相同显示优先级的子组件同时显示或隐藏。 |
布局约束的displayPriority属性 |
折行能力 |
容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,自动换行。 |
Flex组件的wrap属性设置为FlexWrap.Wrap |
响应式布局
响应式布局是指页面内的元素可以根据特定的特征(如窗口宽度、屏幕方向等)自动变化以适应外部容器变化的布局能力。响应式布局中最常使用的特征是窗口宽度,可以将窗口宽度划分为不同的范围(下文中称为断点)。当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。
响应式布局能力 |
简介 |
---|---|
断点 |
将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。 |
媒体查询 |
媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。 |
栅格布局 |
栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。 |
资源使用
在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种方式处理:
- 应用资源:借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。
- 系统资源:开发者直接使用系统预置的资源定义(即分层参数)。
交互归一
对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,我们统一了各种交互方式的API,即实现了交互归一。
常见的基础输入方式及其在各输入设备上的表现如下图所示。
功能级一多
应用开发至少包含两部分工作: UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。前面章节介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。
系统能力
系统能力(即SystemCapability,缩写为SysCap)指操作系统中每一个相对独立的特性,如蓝牙,WIFI,NFC,摄像头等,都是系统能力之一。每个系统能力对应多个API,随着目标设备是否支持该系统能力共同存在或消失。
与系统能力相关的,有支持能力集、联想能力集和要求能力集三个核心概念。
- 支持能力集:设备具备的系统能力集合,在设备配置文件中配置。
- 要求能力集:应用需要的系统能力集合,在应用配置文件中配置。
- 联想能力集:开发应用时IDE可联想的API所在的系统能力集合,在应用配置文件中配置。
- 只有当应用要求能力集是设备支持能力集的子集的时候,应用才可以在该设备上分发、安装和运行。
- 可以访问系统能力列表了解全量的系统能力。
动态逻辑判断
如果某个系统能力没有写入应用的要求能力集中,那么在使用前需要判断设备是否支持该系统能力。
- 方法1:HarmonyOS定义了API canIUse帮助开发者来判断该设备是否支持某个特定的syscap。
if (canIUse("SystemCapability.Communication.NFC.Core")) { console.log("该设备支持SystemCapability.Communication.NFC.Core"); } else { console.log("该设备不支持SystemCapability.Communication.NFC.Core"); }
- 方法2:开发者可通过import的方式将模块导入,若当前设备不支持该模块,import的结果为undefined,开发者在使用其API时,需要判断其是否存在。
import controller from '@kit.ConnectivityKit'; try { controller.enableNfc(); console.log("controller enableNfc success"); } catch (busiError) { console.log("controller enableNfc busiError: " + busiError); }
- 如果某系统能力是应用运行必须的,则要将其写入到应用的要求能力集中,以确保应用不会分发和安装到不符合要求的设备上。
- 如果某系统能力不是应用运行必须的,则可以在运行时做动态判断,这样可以最大程度扩大应用的适用范围。
配置联想能力集和要求能力集
- IDE会根据创建的工程所支持的设备自动配置联想能力集和要求能力集,同时也支持开发者修改。
// syscap.json { "devices": { "general": [ // 每一个典型设备对应一个syscap支持能力集,可配置多个典型设备 "default", "tablet" ], "custom": [ // 厂家自定义设备 { "某自定义设备": [ "SystemCapability.Communication.SoftBus.Core" ] } ] }, "development": { // addedSysCaps内的sycap集合与devices中配置的各设备支持的syscap集合的并集共同构成联想能力集 "addedSysCaps": [ "SystemCapability.Communication.NFC.Core" ] }, "production": { // 用于生成rpcid,慎重添加,可能导致应用无法分发到目标设备上 "addedSysCaps": [], // devices中配置的各设备支持的syscap集合的交集,添加addedSysCaps集合再除去removedSysCaps集合,共同构成要求能力集 "removedSysCaps": [] // 当该要求能力集为某设备的子集时,应用才可被分发到该设备上 } }
- 对于要求能力集,开发者修改时要十分慎重,修改不当会导致应用无法分发和安装到目标设备上。
- 对于联想能力集,通过增加系统能力可以扩大IDE可联想的API范围。但要注意这些API可能在某些设备上不支持,使用前需要判断。
工程级一多
工程级一多需要考虑如何实现一套代码同时能部署到多种不同设备上,代码工程如何组织。
应用程序包结构
在进行应用开发时,一个应用通常包含一个或多个Module。Module是HarmonyOS应用/服务的基本功能单元,包含了源代码、资源文件、第三方库及应用/服务配置文件,每一个Module都可以独立进行编译和运行。
Module分为“Ability”和“Library”两种类型:
- “Ability”类型的Module编译后生成HAP包。
- “Library”类型的Module编译后生成HAR包。
HarmonyOS的应用以APP Pack形式发布,其包含一个或多个HAP包。HAP是HarmonyOS应用安装的基本单位,HAP可以分为Entry和Feature两种类型:
- Entry类型的HAP:应用的主模块。在同一个应用中,同一设备类型只支持一个Entry类型的HAP,通常用于实现应用的入口界面、入口图标、主特性功能等。
- Feature类型的HAP:应用的动态特性模块。Feature类型的HAP通常用于实现应用的特性功能,一个应用程序包可以包含一个或多个Feature类型的HAP,也可以不包含。
部署模型
“一多”有两种部署模型:
- 部署模型A:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成相同的HAP(或HAP组合)。
- 部署模型B:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成不同的HAP(或HAP组合)。
开发者可以从应用UX设计及应用功能两个维度,结合具体的业务场景,考虑选择哪种部署模型。当然,也可以借助设备类型分类,快速做出判断。
从屏幕尺寸、输入方式及交互距离三个维度考虑,可以将常用类型的设备分为不同泛类:
- 默认设备、平板
- 车机、智慧屏
- 智能穿戴
- ……
对于相同泛类的设备,优先选择部署模型A,对于不同泛类设备,优先选择部署模型B。
- 应用在不同泛类设备上的UX设计或功能相似时,可以使用部署模型A。
- 应用在同一泛类不同类型设备上UX设计或功能差异非常大时,可以使用部署模型B,但同时也应审视应用的UX设计及功能规划是否合理。
- 本小节引入部署模型A和部署模型B的概念是为了方便开发者理解。实际上在开发多设备应用时,如果目标设备类型较多,往往是部署模型A和部署模型B混合使用。
- 不管采用哪种部署模型,都应该采用一次编译。
工程结构
“一多”推荐在应用开发过程中使用如下的“三层工程结构”。
- common(公共能力层):用于存放公共基础能力集合(如工具库、公共配置等)。
common层不可分割,需编译成一个HAR包,其只可以被products和features依赖,不可以反向依赖。
- features(基础特性层):用于存放基础特性集合(如应用中相对独立的各个功能的UI及业务逻辑实现等)。
各个feature高内聚、低耦合、可定制,供产品灵活部署。不需要单独部署的feature通常编译为HAR包,供products或其它feature使用。需要单独部署的feature通常编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层可以横向调用及依赖common层,同时可以被products层不同设备形态的HAP所依赖,但是不能反向依赖products层。
- products(产品定制层):用于针对不同设备形态进行功能和特性集成。
products层各个子目录各自编译为一个Entry类型的HAP包,作为应用主入口。products层不可以横向调用。
代码工程结构抽象后一般如下所示:
/application ├── common # 可选。公共能力层, 编译为HAR包或HSP包 ├── features # 可选。基础特性层 │ ├── feature1 # 子功能1, 编译为HAR包或HSP包或Feature类型的HAP包 │ ├── feature2 # 子功能2, 编译为HAR包或HSP包或Feature类型的HAP包 │ └── ... └── products # 必选。产品定制层 ├── wearable # 智能穿戴泛类目录, 编译为Entry类型的HAP包 ├── default # 默认设备泛类目录, 编译为Entry类型的HAP包 └── ...
- 部署模型不同,相应的代码工程结构也有差异。部署模型A和部署模型B的主要差异点集中在products层:部署模型A在products目录下同一子目录中做功能和特性集成;部署模型B在products目录下不同子目录中对不同的产品做差异化的功能和特性集成。
- 开发阶段应考虑不同类型设备间最大程度的复用代码,以减少开发及后续维护的工作量。
- 整个代码工程最终构建出一个APP包,应用以APP包的形式发布到应用市场中。
参考链接
“一次开发,多端部署”的参考指南中详细讲解了一多的相关知识、UX设计、架构规范等,可供开发者参考。