HarmonyOS NEXT 关于鸿蒙的一多开发(一次开发,多端部署) 1+8+N_鸿蒙 一多开发
官方定义
定义:一套代码工程,一次开发上架,多端按需部署。
目标:支撑开发者快速高效的开发支持多种终端设备形态的应用,实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。
什么是1+8+N:1个系统HarmonyOS+8个常用终端(手机、平板、折叠屏、2in1、车机、手表等)+N个不同的物联网设备(智能家居等等)
为什么要做一多开发
随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。HarmonyOS系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。
一多的主要问题
一多开发虽然听上去那么便利,但也一定会带来一些技术问题,主要是三个问题:
为了解决这三个问题,分别从不同的方式进行解决
- 页面适配问题:界面级一多
- 功能兼容问题:功能级一多
- 工程如何组织:工程级一多
界面级一多
界面级一多主要解决的问题是:
-
不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。
可以通过两中方式解决:
- 自适应布局
- 响应式布局
自适应布局是通过一些组件的自适应能力,来解决在小幅度的屏幕大小改变。如果屏幕变化跨度特别大,还是需要使用响应式布局。
自适应布局共有七种
针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。
基于通用属性的两种实现方式:
- 将子组件的宽高设置为父组件宽高的百分比
- layoutWeight属性
基于容器组件的两种实现方式:
- 通过List组件实现
- 通过Scroll组件配合Row组件或Column组件实现
响应式布局
自适应布局可以保证窗口尺寸在【一定范围内变化】时,页面的显示是正常的。但是将窗口尺寸【变化较大】时(如窗口宽度从400vp变化为1000vp),仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题,此时就需要借助响应式布局能力调整页面结构。
响应式布局是指页面内的元素可以根据特定的特征(如窗口宽度、屏幕方向等)自动变化以适应外部容器变化的布局能力。
响应式布局中最常使用的特征是窗口宽度,可以将窗口宽度划分为不同的范围(下文中称为断点)。当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。
三种响应式布局能力:
响应式布局能力
简介
断点
将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。
媒体查询
媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。
栅格布局
栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。
断点
不同的断点取值范围
断点名称
取值范围(vp)
设备
xs
[0, 320)
手表等超小屏
sm
[320, 600)
手机竖屏
md
[600, 840)
手机横屏,折叠屏
lg
[840, +∞)
平板,2in1 设备
系统提供了多种方法,判断应用当前处于何种断点,进而可以调整应用的布局。常见的监听断点变化的方法如下所示:
- 获取窗口对象并监听窗口尺寸变化(了解)
- 通过媒体查询监听应用窗口尺寸变化(掌握)
- 借助栅格组件能力监听不同断点的变化(掌握)
- 通过窗口对象,监听窗口尺寸变化(了解)
媒体查询
这里官网对通过媒体查询监听断点的功能做简单的封装,点击跳转。
这里做了更简化的版本
import { mediaquery } from \'@kit.ArkUI\'interface Breakpoint { name: string size: number mediaQueryListener?: mediaquery.MediaQueryListener}export const BreakpointKey: string = \'currentBreakpoint\'export class BreakpointSystem { private currentBreakpoint: string = \'md\' private breakpoints: Breakpoint[] = [ { name: \'xs\', size: 0 }, { name: \'sm\', size: 320 }, { name: \'md\', size: 600 }, { name: \'lg\', size: 840 } ] public register() { this.breakpoints.forEach((breakpoint: Breakpoint, index) => { let condition: string if (index === this.breakpoints.length - 1) { condition = \'(\' + breakpoint.size + \'vp<=width\' + \')\' } else { condition = \'(\' + breakpoint.size + \'vp<=width { if (mediaQueryResult.matches) { this.updateCurrentBreakpoint(breakpoint.name) } }) }) } public unregister() { this.breakpoints.forEach((breakpoint: Breakpoint) => { if (breakpoint.mediaQueryListener) { breakpoint.mediaQueryListener.off(\'change\') } }) } private updateCurrentBreakpoint(breakpoint: string) { if (this.currentBreakpoint !== breakpoint) { this.currentBreakpoint = breakpoint AppStorage.set(BreakpointKey, this.currentBreakpoint) console.log(\'on current breakpoint: \' + this.currentBreakpoint) } }}/* 定义一个接口类型 键: 断点值 值: 泛型*/declare interface BreakPointTypeOption { xs?: T sm?: T md?: T lg?: T xl?: T xxl?: T}/* 对外导出一个类 在实例化的时候接收一个泛型*/export class BreakPointType { // 选项对象 options: BreakPointTypeOption constructor(option: BreakPointTypeOption) { this.options = option } getValue(currentBreakPoint: string) { if (currentBreakPoint === \'xs\') { return this.options.xs } else if (currentBreakPoint === \'sm\') { return this.options.sm } else if (currentBreakPoint === \'md\') { return this.options.md } else if (currentBreakPoint === \'lg\') { return this.options.lg } else if (currentBreakPoint === \'xl\') { return this.options.xl } else if (currentBreakPoint === \'xxl\') { return this.options.xxl } else { return undefined } }}
栅格布局
栅格是多设备场景下通用的辅助定位工具,通过将空间分割为有规律的栅格。栅格可以显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。
- GridRow breakpoints属性 和 的 onBreakpointChange 事件
- GridRow 的 gutter属性、GridCol 的 offset 属性
- GridRow的 columns 属性、GridCol 的 span 属性
功能级一多
主要是应用如何解决设备系统能力差异的兼容问题。暂时用的比较少。
基本利用canIUse去查询设备是否具有某个能力如:拍照,定位,蓝牙等。
工程级一多
这部分对程序员来说非常重要,一个一多项目,要想更高效,更利于团队配合,就要好好思考,如果做项目结构分层。
一多模式下,官方推荐在开发过程中采用\"三层工程架构\",其实就是把项目拆分成不同类型的模块,再通过模块之间的引用组合,最终实现应用功能,拆分规范如下:
- commons(公共能力层):用于存放公共基础能力合集,比如工具库,公共配置等
- features(基础特性层):用于存放应用中相对独立的各个功能的UI以及业务逻辑实现
- products(产品定制层):用于针对不同设备形态进行功能和特性集成,作为应用入口
根据一个更具体的 手机-折叠屏-平板 三终端项目的话,应该如下设计
products:只是一个入口,应该不负责具体的业务,可以写业务
features:写具体业务,把每个业务拆分成具体的模块 N个,方便维护
commons: 提供基础组件-基础工具-基础类型- 架构组-技术平台组
那么不同的工程架构要用到什么包呢?
首先先了解都有哪几种包
包的分类
- hap- 可以有ability,可以有页面,可以有组件,可以有资源,不同平台的主包(手机包、平板包、手表包)
- hsp-动态共享包。运行时复用- 可以实现按需打包,最常用分包(用户模块包、购物车模块包、收获地址包,各种页面包)
- har- 静态共享包。编译态复用,常见于三方仓库包(请求库包、各种工具包)
还有一些注意点,har包是在引用的时候重复拷贝,如果项目中不是发布到三方库或二方库的话,可以使用hsp包,他在引用的时候赋值地址,不会重复拷贝。