文章

口述:鸿蒙应用架构全景图

口述:鸿蒙应用架构全景图

一句话概括:鸿蒙应用架构是一个从底层操作系统到上层应用框架的四层体系,以 ArkTS 为开发语言、Stage 模型为组件基础、Ability 为功能单元、元服务为分发形态,构建了一套面向全场景的分布式应用开发范式。

一、背景与意义

想象你在设计一栋楼。你会先画结构图——哪是承重墙、哪是管道井、哪是电路走线——然后才开始砌墙抹灰。软件架构也是同理。在开始写代码之前,先理解鸿蒙应用的整体架构,知道每个零件在哪个位置、和谁通信、被谁管理,这能省掉未来大量的”拆墙重来”。

鸿蒙应用架构不是凭空而来的。它吸收了过去二十年移动操作系统(Symbian、iOS、Android)的经验教训,针对”全场景、分布式、轻量化”这三个核心目标做了重新设计。如果你从 Android 或 iOS 过来,你会看到熟悉的影子(Ability 像 Activity,Want 像 Intent),但如果你只带着旧认知来看,你一定会踩坑。

本文以”我口述给你听”的方式,从下到上把鸿蒙应用架构全景走一遍。不抄官方文档,只说架构设计的”为什么”。

二、分层架构概览

鸿蒙应用架构从上到下分为四层:

第一层:应用框架层——就是你写代码面对的那一层。包括 ArkTS 框架、UI 组件库、声明式 UI 引擎。这一层决定了你怎么组织页面、怎么写组件、数据怎么流。

第二层:Ability 层——这是鸿蒙最核心的创新。每个能力(显示页面、后台下载、桌面卡片)都被抽象为 Ability,由系统统一管理生命周期。这一层决定了”你的应用以什么形态存在”。

第三层:进程与资源层——系统怎么管理你的应用进程,怎么分配内存,怎么调度线程。这一层决定了”你的应用跑在哪里”。

第四层:内核与驱动层——这是 OpenHarmony 内核的事,包括微内核、分布式软总线、驱动框架。应用开发者一般不直接碰,但理解它对写出高性能代码有好处。

每一层都通过标准接口(API)为上层提供服务,层与层之间职责清晰。

三、第一层:你写的代码在哪儿——应用框架层

这一层是你作为开发者每天打交道的地方。

ArkTS 不是新的语言

首先,ArkTS 不是一门从零开始的语言。它是 TypeScript 的超集——这意味着你可以在 ArkTS 里写纯 TypeScript,也可以在 TypeScript 里用 ArkTS 的特有语法(主要是装饰器)。这个决策很聪明:它让前端开发者以最低的学习成本进入鸿蒙生态。

ArkTS 的核心增量是四个东西:

第一是 @Component 和 @Entry 装饰器@Component 把一个类标记为一个可复用的 UI 组件,@Entry 标记页面的入口。这不是语法糖——在编译阶段,Ark 编译器会为这些装饰器生成额外的运行时注册代码。

第二是 状态管理装饰器体系@State@Prop@Link@Provide@Consume 这五兄弟。如果让我只用一个词来概括 ArkTS 的特征,那就是”声明式响应式”——你只需要描述状态和 UI 的映射关系,框架自动帮你做 diff 和更新。

第三是 build() 函数。每个组件必须有一个 build(),它返回你在屏幕上看到的一切。这个方法会被框架多次调用——状态变了、父组件刷新了、窗口大小变了,都会触发 build()

第四是 $$ 语法糖$variable 自动创建一个双向绑定的引用对象,这在传递 @Link 时非常有用。

组件树与渲染引擎

你写的组件在运行时会被编译为一棵组件树。渲染引擎遍历这棵树,构建出真正的视图层级。

这里有一个关键设计:ArkTS 的渲染引擎不是浏览器 DOM,也不是 Android 的 View 树——它是自研的声明式渲染引擎,底层使用 Skia 或者系统自带的 GPU 驱动。这意味着:

  • 没有 DOM 重排这样的概念
  • CSS 这些 Web 技术不适用(你得用链式 API 设置样式)
  • 渲染性能理论上优于 Web 方案

UI 描述:链式 API

ArkTS 的样式设置使用链式调用。和 Flutter 的嵌套 widget 模式相比,链式 API 更扁平、更容易阅读:

1
2
3
4
5
6
7
Text('你好,鸿蒙')
  .fontSize(18)
  .fontColor(Color.Blue)
  .fontWeight(FontWeight.Bold)
  .padding(12)
  .backgroundColor('#F0F0F0')
  .borderRadius(8)

每个 .xxx() 调用返回组件本身,形成链式调用。这其实是一种 Builder 模式的应用。

四、第二层:应用被拆成了什么——Ability 层

这是鸿蒙架构中最重要、也最容易引起混淆的一层。

从 FA 到 Stage

先说历史。HarmonyOS 2.x 时期,鸿蒙用的是 FA 模型(Feature Ability)。当时的设计是:一个页面就是一个 Ability。你写一个登录页,它是一个 Ability;写一个个人中心页,它也是一个 Ability。页面之间的跳转等于 Ability 切换。

这个设计有两个问题:

  1. 页面切换太慢了——每次跳转都要启动一个新的 Ability 进程
  2. 生命周期太乱了——页面级生命周期和 Ability 级生命周期重叠

所以在 HarmonyOS 4.0 之后,官方全面推 Stage 模型。在 Stage 模型下:

  • 一个 UIAbility 管理多个页面(通过路由切换)
  • 后台任务、卡片、输入法等非 UI 能力由 ExtensionAbility 承载
  • 整个应用只有一个或少数几个 UIAbility

UIAbility:应用的”窗口”

UIAbility 你可以理解为 Android 的 Activity——它是用户能看到的那个”窗口”。但区别在于:

Android Activity 是一个 Activity 一个窗口,一个应用可能有七八个 Activity;鸿蒙 UIAbility 通常一个应用只有一个,不同页面通过路由系统切换。这使页面的生命周期管理更简单:

1
2
UIAbility.onCreate → 加载首页 → 用户跳转 → 
(页面路由,不涉及 Ability 切换) → 按返回 → UIAbility.onDestroy

整个过程只有一个 UIAbility 实例,页面切换只是组件层级的替换。

ExtensionAbility:后台的”能力槽”

ExtensionAbility 是 Stage 模型里我最欣赏的设计。它明确地表达了”无 UI 的能力单元”。

你想在后台下载文件?用 ServiceExtensionAbility。 你想在桌面放个天气卡片?用 FormExtensionAbility。 你想做输入法?用 InputMethodExtensionAbility。

每种 Extension 都有标准的生命周期和运行策略——系统知道”这是一个后台服务”,所以会在内存紧张时把它的进程 kill 掉,但会保留重启所需的状态。

Want:跨越边界的消息

Ability 之间的通信靠 Want,它和 Android Intent 几乎一样。Want 的核心是对数据的描述:

1
2
3
目标: bundleName + abilityName
动作: action(打开 / 编辑 / 查看)
数据: parameters(键值对)

关键点是:Want 支持跨设备。你可以用同一个 API 启动另一个手机上的 Ability——完全相同的代码,只是 deviceId 参数不同。这就是鸿蒙分布式能力的体现。

五、第三层:代码跑在哪儿——进程与资源层

AppSpawn:应用孵化器

当用户点击桌面图标时,系统 AMS 告诉 AppSpawn:”给我 fork 一个进程跑这个应用。”

AppSpawn 预加载了 Ark 引擎和共享库——某种意义上就是 Node.js + Chromium 合并后的精简版运行时。fork 之后,子进程已经有了运行时环境,不需要再重新加载 Ark 引擎。

这里有一个对比点:Android 的 Zygote 预加载 Java 框架类,AppSpawn 预加载 JS/TS 运行时。两者目的一致,但启动路径不同——鸿蒙的 JS 运行时启动比 Android 的 Java 虚拟机更轻量。

进程隔离

每个应用(包括元服务)运行在独立的沙箱进程中。应用 A 不能直接访问应用 B 的内存,应用 B 也不能读写应用 A 的文件。这种隔离在鸿蒙上执行得比 Android 更严格——应用连自己 data 目录以外的路径都访问不了。

如果两个应用需要通信,走 IPC(进程间通信)。鸿蒙 IPC 是基于序列化的消息传递模式,和 Android Binder 本质相同,但接口更简化。

线程模型

一个应用进程内部,线程模型是:

  • 1 个主线程:UI 渲染 + 事件处理(绝对不能阻塞)
  • N 个 TaskPool 线程:自动管理的线程池,执行计算任务
  • M 个 Worker 线程:按需创建的独立 JS 运行时,长任务专用
  • 若干系统线程:IPC、GC、渲染管线

记住一条铁律:任何时候都不要阻塞主线程。ArkTS 中 setTimeout 默认在 TaskPool 中执行,但如果你在 aboutToAppear 里执行 1 亿次循环,UI 会卡死。

六、第四层:地基——内核与分布式能力

第四层是应用开发者一般碰不到的,但它决定了鸿蒙的上限。

微内核架构

鸿蒙不是 Linux 内核。它的内核是面向 IoT 设计的微内核——只包含最基本的调度和 IPC,驱动和文件系统都运行在用户空间。

这对应用开发者意味着:系统更安全(驱动崩溃不会导致内核崩溃),但也更复杂(用户态驱动有额外的上下文切换开销)。好在这些复杂对应用的层透明——你写代码时不会察觉。

分布式软总线

如果说鸿蒙有什么功能是 iOS 和 Android 都没有的,那就是分布式软总线。它让鸿蒙设备发现彼此、建立安全连接、共享能力:

  • 你的手机在播放视频 → 在平板靠近时,系统询问是否”流转”到平板上播放
  • 你的蓝牙耳机连接了手机 → 在用平板看电影时,音频自动从手机切换到平板

这些能力在应用层只是一个 API 调用 —— this.context.startAbility(want) 加上 deviceId 参数。

元服务引擎

元服务引擎是运行”免安装应用”的轻量运行时。它的设计思路是:只在需要时才下载代码片段,用完即释放。

从架构角度看,元服务和完整应用共享同一套 Ability 模型——它们只是包的体积更小(≤10MB)、生命周期更短、分发渠道更多。底层的 Ability 生命周期、IPC 通信、渲染引擎都是一套。

七、典型应用架构设计

理解了这四层架构后,一个典型的鸿蒙应用应该怎么组织?

小应用(单一功能)

1
2
3
4
5
6
7
AbilityStage → UIAbility(单个)
                → 页面1(首页,路由 "/")
                → 页面2(详情页,路由 "/detail")
                
状态管理:@State + @Link(组件内通信)
数据获取:直接调用 HTTP API(TaskPool 自动)
存储:Preferences(轻量 KV)

中应用(多页面 + 后台任务)

1
2
3
4
5
6
7
8
9
10
11
12
AbilityStage → UIAbility(主窗口)
                → 页面A(首页)
                → 页面B(列表页)
                → 页面C(详情页/编辑页)
             ServiceExtensionAbility(后台同步)
             FormExtensionAbility(桌面卡片)
             
状态管理:@Provide/@Consume(跨层级)
          AppStorage(跨页面)
数据获取:ViewModel 模式 + Repository
存储:RDB(关系型数据库)
通信:Want(跨 Ability)、IPC(自定义服务)

大应用(多模块 + 分布式)

1
2
3
4
5
6
7
8
9
10
11
AbilityStage → UIAbility(主模块)
                → N 个页面
             UIAbility(辅助窗口,如播放器)
             N 个 ExtensionAbility
             
模块化:HAR/HSP 分包
状态管理:Store(全局状态管理)
数据获取:DataSync + 离线缓存
存储:RDB + Preferences + 文件
通信:分布式 Want + Call 通信
性能:LazyForEach + TaskPool + WASM(如果需要)

最佳实践推荐

根据我到目前的观察,大多数鸿蒙应用只需要 1 个 UIAbility + 1-2 个 ServiceExtensionAbility。不要过早拆分多个 UIAbility——只有在需要”独立窗口”或”不同进程”时才去拆分。

八、高频面试题解析

Q1:鸿蒙应用架构和 Android 应用架构最大的区别是什么?

答: 这个问题没有标准答案,但从架构角度看,我认为区别在于组件模型的粒度。Android 把 Activity、Service、ContentProvider、BroadcastReceiver 四个组件放在同一层级——它们都是”一等公民”。鸿蒙把这四种能力合并成了两个:UIAbility(≈ Activity)和 ExtensionAbility(≈ Service + 后台任务 + 卡片)。而且鸿蒙的能力更专注——UIAbility 只管 UI,ExtensionAbility 只管能力。这种”分而治之”的设计让生命周期管理更清晰。

Q2:从 iOS 跨到鸿蒙,最容易误解的是什么?

答: 我从跨平台开发者那里听到最多的是对”多窗口”的误解。iOS 应用通常是”一个屏幕一个 ViewController”;鸿蒙的 UIAbility 可以同时管理多个页面实例。这种”窗口管理”而非”页面管理”的思维,是从 UIKit 过来的开发者最需要适应的地方。

Q3:元服务和完整 App 在架构上有什么本质区别?

答: 本质上是”包的完整度”差异,而不是架构差异。元服务使用完整 App 相同的 Stage 模型、Ability 生命周期、UI 框架。唯一区别是:元服务 HAP 包 ≤10MB,只能包含核心功能。这意味着你需要对模块做更严格的”按需加载”——不能把所有代码一股脑塞进去。

Q4:鸿蒙架构层面如何支持跨设备开发?

答: 核心是分布式软总线统一 Want 协议。分布式软总线负责设备发现和安全连接,Want 协议负责目标定位。你在代码里写 startAbility(want),给 deviceId 参数赋值,系统自动完成跨设备调用。同样的 Ability,只需配置 continuable 属性就支持”跨端迁移”。

九、总结与扩展

鸿蒙应用架构的四层结构,每一层解决一个核心问题:

  1. 应用框架层——你用什么语言和范式写 UI?(ArkTS + 声明式)
  2. Ability 层——你的应用由哪些能力单元组成?(UIAbility + ExtensionAbility)
  3. 进程与资源层——代码在哪个进程、哪个线程运行?(AppSpawn + TaskPool)
  4. 内核与分布式能力——不同设备如何协作?(软总线 + 分布式 Want)

从开发者的视角,这四层可以简化为一条路径:

你想写一个功能 → 创建一个 Ability → 写声明式 UI(ArkTS) → 系统自动分配进程和线程 → 如果需要跨设备,加一个 deviceId 参数

这就是鸿蒙应用架构的精髓。理解了这个全景,再去看具体的 API 文档和代码示例,一切都会显得顺理成章。


推荐阅读清单(按顺序)

  1. 先读《鸿蒙 Stage 模型开发指南》——理解组件基础
  2. 然后看《ArkTS 声明式开发范式》——了解 UI 怎么写
  3. 再翻《Ability 开发指导》——知道怎么组织功能
  4. 最后扫一遍《分布式开发指南》——扩展跨设备能力

这四份材料读完,基本就能在脑海中画出鸿蒙应用架构的全景了。

本文由作者按照 CC BY 4.0 进行授权

© 独行的风. 保留部分权利。

本站采用 Jekyll 主题 Chirpy

本站总访问量 本站访客数 本文阅读量