一次开发多端部署是HarmonyOS面向多终端的核心设计理念,也是鸿蒙生态区别于传统操作系统的关键能力。随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。对开发者而言,广泛的设备类型意味着更广大的潜在用户群体。但如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。
HarmonyOS系统面向多终端提供了一多的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。其核心定义是一套代码工程、一次开发上架、多端按需部署。
为实现这一目标,需要解决三个基础问题。不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。不同设备的系统能力有差异,功能如何兼容。如何实现一套代码同时能部署到多种不同设备上,代码工程如何组织。
针对这三个问题,可以从界面级、功能级、工程级三个维度给出解决思路。本文将系统讲解这三个维度的完整技术方案。
一、一多概述与设计理念
1.1 一多的定义与目标
一次开发多端部署是HarmonyOS面向多终端的核心能力。其定义为一套代码工程,一次开发上架,多端按需部署。
一多的目标包含三个层面。支撑开发者快速高效地开发支持多种终端设备形态的应用。实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。最终帮助开发者以更低的成本覆盖更广泛的设备生态。
1.2 一多的核心价值
一多的核心价值体现在开发效率、用户体验和商业价值三个维度。
从开发效率看,一套代码覆盖多端,避免为每个设备单独开发维护。从用户体验看,应用在不同设备上获得一致且优化的使用体验。从商业价值看,一个应用可以部署到更多设备,触达更广泛的用户群体。
1.3 一多的三个关键问题
一多需要解决三个基础问题。
问题一:页面如何适配。不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何自适应变化。
问题二:功能如何兼容。不同设备的系统能力有差异,如智能穿戴设备是否具备定位能力、智慧屏是否具备摄像头等,功能如何兼容。
问题三:工程如何组织。如何实现一套代码同时能部署到多种不同设备上,代码工程如何组织。
针对这三个问题,可以从界面级、功能级、工程级三个维度给出解决思路。界面级一多解决页面适配问题,功能级一多解决系统能力兼容问题,工程级一多解决代码组织问题。
1.4 一多的两种部署模型
一多有两种部署模型。
部署模型A是不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成相同的HAP或HAP组合。部署模型B是不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成不同的HAP或HAP组合。
开发者可以从应用UX设计及应用功能两个维度,结合具体的业务场景,选择采用哪种部署模型。从屏幕尺寸、输入方式及交互距离三个维度考虑,可以将常用类型的设备分为不同泛类。手机和平板归为一类,车机和智慧屏归为一类,智能穿戴归为一类。
对于相同泛类的设备,优先选择部署模型A。对于不同泛类设备,优先选择部署模型B。如果应用在不同泛类设备上的UX设计或功能相似时,可以使用部署模型A。如果应用在同一泛类不同类型设备上UX设计或功能差异非常大时,可以使用部署模型B。
在实际开发多设备应用时,如果目标设备类型较多,往往是部署模型A和部署模型B混合使用。不管采用哪种部署模型,都应该采用一次编译。
1.5 一多的三层工程结构
一多推荐在应用开发过程中使用三层工程结构。
common层是公共能力层,用于存放公共基础能力集合,如工具库、公共配置等。common层可编译成一个或多个HAR包或HSP包。HAR中的代码和资源跟随使用方编译,如果有多个使用方,它们的编译产物中会存在多份相同拷贝。HSP中的代码和资源可以独立编译,运行时在一个进程中代码也只会存在一份。common层只可以被products和features依赖,不可以反向依赖。
features层是基础特性层,用于存放基础特性集合,如应用中相对独立的各个功能的UI及业务逻辑实现等。各个feature高内聚、低耦合、可定制,供产品灵活部署。不需要单独部署的feature通常编译为HAR包或HSP包,供products或其它feature使用,但是不能反向依赖products层。需要单独部署的feature通常编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层可以横向调用及依赖common层。
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目录下不同子目录中对不同的产品做差异化的功能和特性集成。
二、界面级一多
2.1 界面级一多的核心问题
页面级一多需要考虑不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。可以从布局能力、资源使用、交互归一几个方面去考虑。
界面级一多的目标是让同一套UI代码在不同屏幕尺寸下都能呈现出良好的视觉效果和交互体验。需要从三个方面入手。
布局能力决定了页面中的元素按照何种方式排布及显示,是页面设计及开发过程中首先需要考虑的问题。一般情况下,可以通过页面或自定义组件内的组件结构,如组件个数、组件的父子/兄弟关系、组件类型、组件的相对位置,来判断使用何种布局能力。
对于随尺寸变化组件结构相同的场景,可以在开发过程中灵活使用自适应布局能力来达到目标效果。对于随尺寸变化组件结构不同的场景,更适合使用响应式布局能力来实现不同尺寸下的不同显示效果。
资源使用指在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种处理方式。
交互归一指对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,HarmonyOS统一了各种交互方式的API,即实现了交互归一。
2.2 自适应布局与响应式布局
布局可以分为自适应布局和响应式布局两种。
自适应布局是指当外部容器大小发生变化时,元素可以根据相对关系自动变化以适应外部容器变化的布局能力。相对关系如占比、固定宽高比、显示优先级等。自适应布局能力可以实现界面显示随外部容器大小连续变化。当前自适应布局能力有七种:拉伸能力、均分能力、占比能力、缩放能力、延伸能力、隐藏能力、折行能力。
响应式布局是指当外部容器大小发生变化时,元素可以根据断点、栅格或特定的特征,如屏幕方向、窗口宽高等,自动变化以适应外部容器变化的布局能力。当前响应式布局能力有三种:断点、媒体查询、栅格布局。响应式布局可以实现界面随外部容器大小有级不连续变化,通常不同特征下的界面显示会有较大的差异。
2.3 资源使用策略
在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。
处理方式一:应用资源。借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。
处理方式二:系统资源。开发者直接使用系统预置的资源定义,即分层参数。
资源目录结构可以按设备类型、屏幕密度、语言等维度组织,实现资源的自动匹配。
三、自适应布局能力
3.1 自适应布局概述
针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力。这些布局可以独立使用,也可多种布局叠加使用。
七种自适应布局能力包括拉伸能力、均分能力、占比能力、缩放能力、延伸能力、隐藏能力、折行能力。这些能力主要通过Flex布局、Row、Column等容器组件的属性来实现。
在鸿蒙开发中,实现多端页面布局常用的技术包括Row组件、Column组件和Flex组件。这三个组件提供了拉伸控制、占比控制、折行控制等自适应布局所需要的能力。
3.2 拉伸能力
拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。
实现拉伸能力的主要方式是Flex布局的flexGrow和flexShrink属性。
flexGrow用于设置组件在父容器主轴方向上的拉伸比例。当父容器有剩余空间时,设置了flexGrow属性的子组件会按比例分配剩余空间。
flexShrink用于设置组件在父容器主轴方向上的收缩比例。当父容器空间不足时,设置了flexShrink属性的子组件会按比例收缩。
Row() {
Text('固定宽度')
.width(100)
Text('弹性拉伸')
.flexGrow(1)
.backgroundColor(Color.Gray)
}
3.3 均分能力
均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。
实现均分能力的主要方式是Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly或FlexAlign.SpaceBetween。
SpaceEvenly表示Flex主轴方向均匀分配弹性元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。SpaceBetween表示Flex主轴方向均匀分配弹性元素,相邻元素之间距离相同,第一个元素与行首对齐,最后一个元素与行尾对齐。
Row() {
Column() {
Image($r('app.media.icon1'))
Text('选项一')
}
Column() {
Image($r('app.media.icon2'))
Text('选项二')
}
Column() {
Image($r('app.media.icon3'))
Text('选项三')
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
3.4 占比能力
占比能力是指子组件的宽或高按照预设的比例,随容器组件发生变化。
实现占比能力有两种方式。第一种是将子组件的宽高设置为父组件宽高的百分比。第二种是使用layoutWeight属性。
layoutWeight属性用于设置兄弟组件在父容器主轴方向的布局权重。父容器尺寸确定时,设置了layoutWeight属性的子元素与兄弟元素占主轴尺寸按照权重进行分配,忽略元素本身尺寸设置,表示自适应占满剩余空间。
Column() {
Text('标题区域')
.height(50)
.backgroundColor(Color.Red)
Blank()
.layoutWeight(1)
Button('底部按钮')
.height(60)
.backgroundColor(Color.Blue)
}
.width('100%')
.height('100%')
3.5 缩放能力
缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。
实现缩放能力的主要方式是布局约束的aspectRatio属性。
aspectRatio用于设置组件的宽高比。当组件宽度变化时,高度会按比例自动调整。
Image($r('app.media.image'))
.width('100%')
.aspectRatio(1.5) // 宽高比为1.5:1
3.6 延伸能力
延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。
实现延伸能力有两种方式。通过List组件实现,或通过Scroll组件配合Row组件或Column组件实现。
Scroll() {
Row() {
ForEach(this.items, (item: string) => {
Text(item)
.padding(10)
})
}
}
.scrollable(ScrollDirection.Horizontal)
3.7 隐藏能力
隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏。相同显示优先级的子组件同时显示或隐藏。
实现隐藏能力的主要方式是布局约束的displayPriority属性。
Row() {
Text('高优先级')
.displayPriority(1)
Text('中优先级')
.displayPriority(2)
Text('低优先级')
.displayPriority(3)
}
3.8 折行能力
折行能力是指容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,自动换行。
实现折行能力的主要方式是Flex组件的wrap属性设置为FlexWrap.Wrap。
Flex({
direction: FlexDirection.Row,
wrap: FlexWrap.Wrap
}) {
ForEach(this.items, (item: string) => {
Text(item)
.padding(10)
.margin(5)
.backgroundColor(Color.Gray)
})
}
四、响应式布局能力
4.1 响应式布局概述
响应式布局是指页面内的元素可以根据特定的特征,如窗口宽度、屏幕方向等,自动变化以适应外部容器变化的布局能力。
HarmonyOS为此提供了一系列的响应式布局能力和工具,用来实现多端布局。响应式布局是基于响应式设计方法论进行布局的方法,核心思想是页面根据不同屏幕尺寸自动调整布局,提供更舒适的界面和更好的用户体验。
响应式布局的能力包括断点、媒体查询、栅格布局,以及一些支持响应式布局的组件,如Tabs、Swiper、Grid、List、GridRow,通过断点设置可以实现不同的展示效果。
4.2 断点
响应式布局中最常使用的特征是窗口宽度及窗口高宽比,可以将窗口宽度及窗口高宽比划分为不同的范围,称之为断点。当窗口宽度及窗口高宽比从一个断点变化到另一个断点时,改变页面布局以获得更好的显示效果。
横向断点以应用窗口宽度为判断条件,建议划分为如下区间。
| 断点名称 | 窗口宽度(vp) |
|---|---|
| xs | (0, 320] |
| sm | [320, 600) |
| md | [600, 840) |
| lg | [840, 1440) |
| xl | [1440, +∞) |
纵向断点根据应用窗口的高宽比进行判断,建议划分为如下区间。
| 断点名称 | 高宽比 |
|---|---|
| sm | (0, 0.8) |
| md | [0.8, 1.2) |
| lg | [1.2, +∞) |
断点面向窗口而非设备类型,相同断点区间的窗口展示相同的页面布局。同一设备上的不同窗口形态,例如全屏显示、分屏显示、自由窗口等,可能落入不同的断点区间,展示不同布局。
从API version 22起,开发者可利用响应式系统环境变量装饰器@Env读取断点信息。当组件所在窗口尺寸发生变化时,@Env装饰的断点环境变量将更新,并触发与该断点环境变量关联的组件刷新,从而实现界面内容的同步更新。
4.3 媒体查询
媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。
let mediaQuery = matchMedia('(max-width: 600px)');
mediaQuery.on('change', (result: MediaQueryResult) => {
if (result.matches) {
// 小屏设备
} else {
// 大屏设备
}
});
4.4 栅格布局
栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。
栅格布局的核心组件包括:
GridRow是栅格容器,定义布局的列数、间距和断点规则。GridCol是栅格子组件,控制子元素占据的列数、偏移和排序。断点系统根据设备屏幕宽度划分不同断点,动态切换布局规则。
GridRow({
columns: 12,
gutter: { x: 20, y: 10 },
breakpoints: {
value: ['320vp', '520vp', '840vp']
}
}) {
GridCol({
span: { xs: 12, sm: 6, md: 4 },
offset: { md: 1 }
}) {
Text('内容块')
}
}
五、功能级一多
5.1 系统能力概述
应用开发至少包含两部分工作:UI页面开发和底层功能开发。功能级一多主要解决应用如何应对设备系统能力差异的兼容问题。
系统能力是HarmonyOS的核心概念。SysCap指操作系统中每一个相对独立的特性,如蓝牙、Wi-Fi、NFC、摄像头等,都是系统能力之一。每个系统能力对应多个API,随着目标设备是否支持该系统能力共同存在或消失。
与系统能力相关的有三个核心概念:
支持能力集是设备具备的系统能力集合,在设备配置文件中配置。要求能力集是应用需要的系统能力集合,在应用配置文件中配置。联想能力集是开发应用时IDE可联想的API所在的系统能力集合,在应用配置文件中配置。
只有当应用要求能力集是设备支持能力集的子集的时候,应用才可以在该设备上分发、安装和运行。
5.2 动态逻辑判断
如果某个系统能力没有写入应用的要求能力集中,那么在使用前需要判断设备是否支持该系统能力。
方法一:HarmonyOS定义了API canIUse帮助开发者来判断该设备是否支持某个特定的系统能力。
if (canIUse('SystemCapability.Communication.NFC.Core')) {
console.log('该设备支持NFC能力');
} else {
console.log('该设备不支持NFC能力');
}
方法二:开发者可通过import的方式将模块导入,若当前设备不支持该模块,import的结果为undefined,在使用其API时需判断是否存在。
import controller from '@kit.ConnectivityKit';
if (controller) {
controller.enableNfc();
}
如果某系统能力是应用运行必须的,则要将其写入到应用的要求能力集中,以确保应用不会分发和安装到不符合要求的设备上。如果某系统能力不是应用运行必须的,则可以在运行时做动态判断,这样可以最大程度扩大应用的适用范围。
5.3 配置syscap.json
IDE会根据创建的工程所支持的设备自动配置联想能力集和要求能力集,同时也支持开发者修改。
在项目的src/main目录下创建syscap.json文件:
{
"devices": {
"general": [
"default",
"tablet"
],
"custom": [
{
"某自定义设备": [
"SystemCapability.Communication.SoftBus.Core"
]
}
]
},
"development": {
"addedSysCaps": [
"SystemCapability.Communication.NFC.Core"
]
},
"production": {
"addedSysCaps": [],
"removedSysCaps": []
}
}
对于要求能力集,开发者修改时要十分慎重,修改不当会导致应用无法分发和安装到目标设备上。对于联想能力集,通过增加系统能力可以扩大IDE可联想的API范围,但要注意这些API可能在某些设备上不支持,使用前需要判断。
六、工程级一多
6.1 应用程序包结构
HarmonyOS的应用以APP Pack形式发布,其包含一个或多个HAP包。HAP是HarmonyOS应用安装的基本单位,HAP可以分为Entry和Feature两种类型。
Entry类型的HAP是应用的主模块。在同一个应用中,同一设备类型只支持一个Entry类型的HAP,通常用于实现应用的入口界面、入口图标、主特性功能等。
Feature类型的HAP是应用的动态特性模块。Feature类型的HAP通常用于实现应用的特性功能,一个应用程序包可以包含一个或多个Feature类型的HAP,也可以不包含。
Module是HarmonyOS应用/服务的基本功能单元,包含了源代码、资源文件、第三方库及应用/服务配置文件,每一个Module都可以独立进行编译和运行。Module分为Ability和Library两种类型。Ability类型的Module编译后生成HAP包,Library类型的Module编译后生成HAR包或HSP包。
6.2 三层工程结构详解
一多推荐在应用开发过程中使用三层工程结构。这种分层架构通过HAP、HAR、HSP等模块化包类型在工程上实现。开发者可以根据功能是否需独立部署、是否动态加载等需求,灵活组合这些模块,最终编译出适应不同设备形态的应用包,实现一套代码,多端生成。
common层是公共能力层,存放公共基础能力集合,如工具库、公共配置等。该层追求稳定性和复用性,是应用开发的标准件仓库。common层可编译成一个或多个HAR包或HSP包,只可以被products和features依赖,不可以反向依赖。
features层是基础特性层,存放基础特性集合,如应用中相对独立的各个功能的UI及业务逻辑实现等。每个模块都应具备高内聚、低耦合的特性。它们依赖common层,并向上为products层提供清晰的业务接口。这一层的设计直接决定了多端部署的灵活性。features层可以横向调用及依赖common层。
products层是产品定制层,直面用户和设备差异。负责根据不同设备形态、交互方式和使用场景,对基础特性进行个性化的UI设计、资源适配和交互逻辑编排。products层各个子目录各自编译为一个Entry类型的HAP包,作为应用主入口。products层不可以横向调用。
6.3 不同部署模型的工程组织
部署模型A和部署模型B的主要差异点集中在products层。
部署模型A在products目录下同一子目录中做功能和特性集成。适用于相同泛类设备,UX设计或功能相似的情况。
部署模型B在products目录下不同子目录中对不同的产品做差异化的功能和特性集成。适用于不同泛类设备,UX设计或功能差异较大的情况。
七、一多实战案例分析
7.1 设置页面的自适应布局
以设置页面的cell视图为例,文字和图标在左侧,箭头图标在右侧。在不同尺寸的设备上运行时,始终保持左侧文字、右侧图标的效果。
布局结构分析显示,左侧为文字内容,右侧为图标,中间区域可以随着屏幕大小自动延伸。这里用到了延伸能力,需要使用Blank组件。
Blank组件是空白填充组件,在容器主轴方向上具有自动填充容器空余部分的能力,仅当父组件为Row、Column或Flex时生效。
Row() {
Text('个人信息')
Blank()
Image($r('app.media.arrow'))
.width(20)
.height(20)
}
.width('90%')
.padding(10)
也可以使用Row组件的对齐方式来实现两端对齐效果,通过FlexAlign.SpaceBetween实现左右元素两端对齐。
7.2 多列内容的栅格布局
多列内容展示场景,如商品列表、图文混排等,适合使用栅格布局实现。
GridRow({
columns: 12,
gutter: { x: 20, y: 10 },
breakpoints: {
value: ['320vp', '600vp', '840vp']
}
}) {
ForEach(this.items, (item: Product) => {
GridCol({
span: { xs: 12, sm: 6, md: 4, lg: 3 }
}) {
ProductCard({ data: item })
}
})
}
7.3 不同泛类设备的差异化适配
对于手机和平板等不同泛类设备,可以采用products层的差异化工程组织方式。在products目录下分别创建phone和tablet子目录,各自编译为独立的Entry类型HAP包,根据设备类型选择不同的HAP组合部署。
八、一多开发最佳实践
8.1 布局设计原则
提升全场景体验,需考虑多设备连续性。应用页面布局设计时推荐遵循两个原则。
原则一:两个宽度相近的窗口,页面布局相同,断点归一。原则二:高度相对宽度较小的窗口,呈现横向窗口或类方形窗口时,页面布局进行差异化设计,增加断点。
系统设计了横向和纵向断点分别代表窗口的不同特征,作为判断页面布局和交互体验的条件。建议在实际开发中,根据应用实际使用场景决定适配哪些断点。
8.2 开发工具与调试
DevEco Studio作为官方IDE,多设备实时预览功能是一多开发的利器,可以同时查看同一界面在不同设备上的渲染效果。Codelinter支持对代码风格、安全、性能、一多适配等规则进行检查。
建议在开发过程中充分利用DevEco Studio提供的MultiPreview功能,配置多设备模拟器集群进行同步调试。
8.3 性能优化建议
一多开发需要考虑不同设备的性能差异。对于低性能设备,应适当降低UI复杂度,减少动画效果,优化图片资源。
使用组件复用机制,减少滑动过程中组件创建和布局开销,提升帧率。合理使用布局边界,限制布局影响范围,减少重新布局的计算量。
8.4 测试策略
一多应用需要在多种设备上进行全面测试。可以使用自动化测试框架支持多设备并行测试。建议覆盖不同屏幕尺寸、不同系统能力组合、不同交互方式的测试场景。
UXLint可以检查多端适配规范,帮助发现布局适配、资源使用等方面的问题。
总结
本文系统讲解了一次开发多端部署的完整技术方案。从一多的设计理念出发,深入解析了界面级一多的自适应布局和响应式布局能力,功能级一多的系统能力兼容机制,以及工程级一多的三层工程结构和部署模型。
通过本文的学习,希望你能够理解一多的核心定义和目标,掌握七种自适应布局能力和三种响应式布局能力的使用方法,理解系统能力的概念和动态判断方法,掌握三层工程结构的组织方式,了解不同部署模型的选择策略。
一多是HarmonyOS面向多终端的核心设计理念,掌握一多开发是开发鸿蒙跨设备应用的关键。第五篇将深入讲解数据管理与持久化,包括应用数据存储概述、文件与用户数据、分布式数据管理等核心内容。
2万+

被折叠的 条评论
为什么被折叠?



