简易代码实践:https://github.com/gongshijier/harmonyLab
飞书:https://bzreny5z71.feishu.cn/docx/OJ74dfqe4oHXNNxpT5Mc1Bujnjg
1. 历史前景
自主可控:鸿蒙代表了自研操作系统的崛起
分布式生态:基于鸿蒙自下而上的应用生态,多终端构造的体验和消费场景的迁移
鸿蒙(HarmonyOS,开发代号 Ark):
正式名称为华为终端鸿蒙智能设备操作系统软件是华为自 2012 年以来开发的一款分布式操作系统。
该系统利用“分布式”技术,将手机、电脑、平板、电视、汽车和智能穿戴等多款设备融合成一个“超级终端”,使用户便于操作和共享各种设备的资源。
发布时间线:
2019 年 8 月正式发布了 HarmonyOS。
2020 年 12 月 16 日,华为发布 HarmonyOS 2 手机开发者版本,次年 6 月 2 日,华为举行发布会正式发布鸿蒙操作系统 2.0,及公布搭载该系统的多款新产品,包括华为智能手机、平板电脑和智能手表,同时向现有用户分阶段推送系统更新。
2022 年 7 月 27 日,华为 HarmonyOS 3 正式发布。
2023 年 8 月 4 日,华为 HarmonyOS 4 正式发布。同时公开了 HarmonyOS NEXT 的开发者预览版。
鸿蒙分层架构:
[图片上传失败...(image-a2cee2-1701587571079)]
分布式生态:手机、手表、平板、汽车
[图片上传失败...(image-a820fc-1701587571079)]
2. 语法特性
鸿蒙开发最早支持 Java 开发,后续鸿蒙 3.0 版本之后中逐渐废弃 Java,而是主推两种范式:
类 WebUi 的开发范式
响应式声明式的开发范式:ArkTs 两种范式性能上有些差异,后者 ArkTs 声明式的 Ui 范式性能优于 webUi 的开发范式 ArkTs 是 TypeScript 的超集,语法特性在两者的基础上进行了系列拓展,可以高效的支持响应式的布局开发
[图片上传失败...(image-21fe1b-1701587571079)]
2.1 页面组件
声明式的写法,只需要关注页面的构成,无需关注 Measure layout draw,其实现在系统 native 源码中
下面是以 ArtTs 的范式来书写一个 列表页布局的代码片段,类 Jetpack 中 compose 组件声明式的 UI 范式:
@Component
export struct FeedList {
private data: FeedDataSource = new FeedDataSource()
private flavor: Flavor
build() {
Scroll() {
List() {
LazyForEach(this.data, (item: Cell, index: number) => {
ListItem() {
this.buildCard(item)
}
.width('95%')
.margin({ top: 16, left: 10, bottom: 10 })
})
}
.cachedCount(3)
.lanes(this.flavor.lanes)
.width('100%')
.height('100%')
.divider({ strokeWidth: 0.2, color: '#d6d6d6' })
}.backgroundColor(Color.White)
}
组件的布局方式中 component 的 build 方法中组织,build 方法决定了渲染组件的构成,还有一大特点是响应式的布局思想:
@Entry
@Component
struct MyComponent {
@State isVisible: boolean = true;
build() {
Column() {
Button("显隐切换")
.onClick(() => {
this.isVisible = !this.isVisible
})
if (this.isVisible) {
Row()
.width(300).height(300).backgroundColor(Color.Pink)
}
}.width('100%')
}
}
[图片上传失败...(image-d91793-1701587571079)]
这里点击切换可见性的按钮后,会修改 @State 注解修饰的变量,值得注意的是,组件 buid() 方法中,是根据这个变量来选择性渲染 Row 组件的,布局代码这样的写法就可以实现点击按钮控制可见性了
类 databinding 的思想,这种响应式的特性中 ArkTs 中支持较好:
定义了大量的 关键字 来维护页面的状态,其中有父子组件,单向绑定的,有双向绑定的;
@State:@State 装饰的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。
@Prop:@Prop 装饰的变量可以和父组件建立单向同步关系,@Prop 装饰的变量是可变的,但修改不会同步回父组件。
@Link:@Link 装饰的变量和父组件构建双向同步关系的状态变量,父组件会接受来自@Link 装饰的变量的修改的同步,父组件的更新也会同步给@Link 装饰的变量。
@Provide/@Consume:@Provide/@Consume 装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数命名机制传递,通过 alias(别名)或者属性名绑定。
@Observed:@Observed 装饰 class,需要观察多层嵌套场景的 class 需要被@Observed 装饰。单独使用@Observed 没有任何作用,需要和@ObjectLink、@Prop 连用。
@ObjectLink:@ObjectLink 装饰的变量接收@Observed 装饰的 class 的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。
[图片上传失败...(image-348b97-1701587571079)]
至于 ArkTs 语言:
[图片上传失败...(image-35bf33-1701587571079)]
2.2 语法相关
下面是几个 TypeScript 代码片段,方便更好感受语法特点:
联合类型
类
接口
联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值:
var val:string|number
val = 12
console.log("数字为 "val)
val = "Runoob"
console.log("字符串为 "val)
类:
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("函数中显示发动机型号 : "+this.engine)
}
}
// 创建一个对象
var obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+obj.engine)
// 访问方法
obj.disp()
接口:
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
2.3 UI 组件
UI 组件: Text、Image、Button、List、Radio、Toggle、Tabs、Progress、Video ...
布局:Row、Column、Stack、Flex:
[图片上传失败...(image-8d6fc0-1701587571079)]
3. 业务实践
基于浏览器基本 UI 特征,熟悉 ArkTs 语法,方便快速上手鸿蒙开发
简易代码实践:https://github.com/gongshijier/harmonyLab
基本组件:
频道--Tabs
底 Tab--Tabs
列表页--List
Row Column Text Image TextInput
[图片上传失败...(image-9037-1701587571079)]
[图片上传失败...(image-e242e8-1701587571079)]
4. 架构简析
鸿蒙系统源码简析,理解整体系统架构和相关概念
后续内容基于: OpenHarmony-v4.0-Release 版本源码中截取较多 markdown 文档中的内容辅助理解:
完整的系统源码目录:
[图片上传失败...(image-ca24b-1701587571079)]
其中核心模块比如: arkui graphic window 等模块中 foundation 目录下:
[图片上传失败...(image-8a14b4-1701587571079)]
整体架构:
[图片上传失败...(image-40f4b3-1701587571079)]
4.1 ArkCompiler 和 ArkRuntime
文档: https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/ARK-Runtime-Subsystem-zh.md
ArkCompiler:
[图片上传失败...(image-8fd343-1701587571079)]
ArkRuntime:
[图片上传失败...(image-785f3a-1701587571079)]
[图片上传失败...(image-788c41-1701587571079)]
4.2 启动流程
init:
[图片上传失败...(image-677e58-1701587571078)]
应用启动流程:
[图片上传失败...(image-8b0238-1701587571078)]
4.3 ArkUI
ArkTs 中只涉及:UI 树的构建,不涉及 measure layout draw 以及 invalidate requestlayout 相关
核心 UI 绘制 pipeline:在 ArkUI engine 中实现,架构导致缺乏 UI 开发的拓展能力,上限比较低
[图片上传失败...(image-a20e53-1701587571078)]
4.4 graphic
ArkTs -- JsBridge -- UINode -- MeasureLayoutRender -- Surface -- WMS
[图片上传失败...(image-67bcbb-1701587571078)]
[图片上传失败...(image-96925-1701587571078)]
4.5 window
Surface 合成和消费
[图片上传失败...(image-ce1835-1701587571078)]
window:
[图片上传失败...(image-5a367d-1701587571078)]
window manager:
[图片上传失败...(image-629b84-1701587571078)]
5. 工程架构
鸿蒙项目的目录架构解析
工程架构目录:
[图片上传失败...(image-ae49d7-1701587571078)]
AppScope > app.json5:应用的全局配置信息。
-
entry:HarmonyOS 工程模块,编译构建生成一个 HAP 包。
src > main > ets:用于存放 ArkTS 源码。
src > main > ets > entryability:应用/服务的入口。
src > main > ets > pages:应用/服务包含的页面。
src > main > resources:用于存放应用/服务所用到的资源文件,如图形、多媒体、字符串、布局文件等。
src > main > module.json5:Stage 模型模块配置文件。主要包含 HAP 包的配置信息、应用/服务在具体设备上的配置信息以及应用/服务的全局配置信息。
build-profile.json5:当前的模块信息、编译信息配置项,包括 buildOption、targets 配置等。其中 targets 中可配置当前运行环境,默认为 HarmonyOS。
hvigorfile.ts:模块级编译构建任务脚本,开发者可以自定义相关任务和代码实现。
oh_modules:用于存放三方库依赖信息。
build-profile.json5:应用级配置信息,包括签名、产品配置等。
hvigorfile.ts:应用级编译构建任务脚本。
6. 问题和思考
- ArkTs 组件源码都在 Native 层 arkui 中,measure layout draw,invalidate requestLayout 等都是 arkui 封装,开发中需要对 Natvie 层实现进行学习,断点也没法定位相关源码,有比较大的维护成本 ?
[图片上传失败...(image-86cd6e-1701587571078)]
- 同上,由于 ui 和 graphic 相关的代码均封装在 native 系统源码中,增加一个 js 组件步骤极为麻烦,且应用开发无法实现,需要修改系统源码?
官方增加一个 JS 组件的 codeReview : https://gitee.com/theretherehuh/ace_ace_engine/pulls/1/files
7. 引用
- 开发者文档:
- 开源仓库:
- 页面状态关键字:
https://www.seaxiang.com/blog/8c467ecc0f4846b69bb47db0dba94d2a
- 系统源码:
https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v4.0-release.md
- 源码下载地址:
- UI 渲染过程: