在这里插入图片描述

你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌 关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀

前言

刚接触 HarmonyOS Stage 模型时,有几个名字很容易混在一起:HAP、AbilityStage、UIAbility、WindowStage,还有每天都在写的 ArkUI Page。

尤其是 EntryAbility.ets 里那句 windowStage.loadContent('pages/Index'),看起来只是加载首页,背后其实已经串起了 Stage 模型最核心的一条链路。

这一篇不展开页面路由、多窗口、ExtensionAbility,也不讨论复杂生命周期,只做一件事:把一个普通 Stage 工程从 HAP 到 ArkUI Page 的整体骨架画清楚。

截至 2026 年 9 月,HarmonyOS 7 已正式发布,对应 API 26。Stage 模型仍然是当前 HarmonyOS 应用开发的核心应用模型;官方文档明确说明,Stage 模型提供 AbilityStage、WindowStage 等对象,并将应用组件管理和窗口管理在架构层面解耦。

一、先别把 UIAbility 当成“一个页面”

理解 Stage 模型,第一个需要纠正的概念就是:

UIAbility 不是 ArkUI Page。

官方对 UIAbility 的定义是“包含 UI 的应用组件”,主要承担与用户交互相关的应用组件职责;而 ArkUI Page 才是真正组织和展示界面内容的页面。官方同时明确指出,每个 UIAbility 实例都会与一个 WindowStage 实例绑定,WindowStage 包含主窗口,主窗口为 ArkUI 提供绘制区域。

所以,更合适的理解不是:

UIAbility = 页面

而是:

UIAbility
   │
   └── WindowStage
          │
          └── Window
                 │
                 └── ArkUI Page

页面最终需要有一个窗口承载,而 UIAbility 与窗口之间的连接点,就是 WindowStage。

这也是为什么 DevEco Studio 创建的 Stage 工程里,首页不是在 UIAbility 的 build() 中直接写出来,而通常是在 onWindowStageCreate() 中调用:

windowStage.loadContent('pages/Index');

官方当前文档中的 UIAbility 示例仍然采用这种组织方式。

二、HAP 又处在什么位置

再往上一层看 HAP。

官方术语文档给出的定义很明确:HAP(Harmony Ability Package)是应用安装和运行的基本单元,由代码、资源、第三方库和配置文件等内容组成,分为 entry 和 feature 两种类型。

这里容易产生一个误区:

HAP、AbilityStage、UIAbility 是不是三个并列的运行对象?

不是。

HAP首先是包和模块层面的概念。例如工程中的 entry Ability 类型 Module 构建后形成 HAP。

AbilityStage 则是这个层级在运行期非常关键的对象。

官方 Stage 模型文档明确说明:

每个 Entry 类型或者 Feature 类型的 HAP,在运行期都有一个 AbilityStage 类实例;当 HAP 中的代码首次被加载到进程中时,系统会先创建 AbilityStage 实例。该 HAP 中定义的 UIAbility 实例化后,会与这个 AbilityStage 实例产生关联。

因此可以先得到第一层关系:

Entry / Feature HAP
        │
        └── AbilityStage
               │
               ├── UIAbility A
               └── UIAbility B

注意这里说的是一个 HAP 可以定义多个 UIAbility,并不是“一个 HAP 对应一个 UIAbility”。

AbilityStage 更接近“Module/HAP 级运行容器”。

官方 AbilityStage 开发指导同样说明:AbilityStage 是 Module 级组件容器,一个 AbilityStage 实例对应一个 Module;在 Module 的第一个 UIAbility 实例加载之前,会先创建 AbilityStage。

三、把五个核心对象放进同一张图

到这里,就可以把本文涉及的五个核心概念放到一张图里了。

应用
│
├── Entry HAP
│    │
│    ├── AbilityStage
│    │      │
│    │      ├── UIAbility 实例 A
│    │      │       │
│    │      │       └── WindowStage 实例
│    │      │               │
│    │      │               └── 主 Window
│    │      │                       │
│    │      │                       └── loadContent(...)
│    │      │                               │
│    │      │                               └── ArkUI Page
│    │      │
│    │      └── UIAbility 实例 B
│    │              │
│    │              └── WindowStage 实例
│    │                      │
│    │                      └── 主 Window
│    │
│    └── 代码 / 资源 / 配置等
│
└── Feature HAP(可选)
     │
     └── AbilityStage
            │
            └── ...

如果只记一张图,建议记这一张。

其中有三组关系尤其重要。

HAP → AbilityStage: AbilityStage 对应 Module/HAP 这一层的运行期组件容器。

UIAbility → WindowStage: 每个 UIAbility 类实例都会绑定一个 WindowStage 类实例。

WindowStage → ArkUI Page: WindowStage 管理窗口,通过 loadContent() 把 ArkUI 页面内容加载到关联窗口中。官方关于 UIContext 的说明进一步指出,一个 Ability 可以存在多个 Window,而每个 Window 通过 loadContent 加载页面后,会生成相应的 UIContent,也就是一个 ArkUI 实例。

所以真正完整的链路实际上比“Ability 打开 Page”多了一层窗口体系:

HAP
 ↓
AbilityStage
 ↓
UIAbility
 ↓
WindowStage
 ↓
Window
 ↓
UIContent / ArkUI Page

四、它们到底谁先创建

如果只讨论一个普通 Stage 单 HAP 应用的首次启动,可以把主干过程理解成:

HAP代码首次加载
      ↓
创建 AbilityStage
      ↓
AbilityStage.onCreate()
      ↓
创建 UIAbility 实例
      ↓
UIAbility.onCreate()
      ↓
创建主窗口对应的 WindowStage
      ↓
UIAbility.onWindowStageCreate(windowStage)
      ↓
windowStage.loadContent('pages/Index')
      ↓
创建并渲染 ArkUI 页面
      ↓
UIAbility 进入前台阶段

这里最关键的一条官方约束是:Module 第一个 UIAbility 实例加载之前,AbilityStage 已经被创建。 AbilityStage 的 onCreate() 正是用于 Module 初始化的生命周期回调。

UIAbility 与显示相关的职责又被拆给了 WindowStage。官方 Stage 模型概述特别指出,UIAbility 生命周期主要包含创建、销毁、前台、后台等状态,而显示相关状态通过 WindowStage 暴露。

这正是 Stage 模型名称里“Stage”的含义之一:应用组件和窗口各有自己的“舞台”,而不是把业务生命周期、窗口生命周期和页面生命周期全部揉进一个对象。

五、搭一个最小工程,把关系直接写进代码

下面不做业务功能,只建立一个最小观察场景:

  1. 给 entry HAP 显式配置 AbilityStage;
  2. AbilityStage 创建时打印日志;
  3. UIAbility 创建时打印日志;
  4. WindowStage 创建后加载 pages/Index;
  5. Index 页面显示一个简单文本。

这样做的价值不是实现功能,而是把上面的架构关系落实到工程文件中。

1. 创建 AbilityStage

DevEco Studio 的默认工程不一定自动生成自定义 AbilityStage 文件。官方指导要求:如果需要使用 AbilityStage,可以创建继承自 AbilityStage 的类,再通过 Module 配置中的 srcEntry 指定入口。

// entry/src/main/ets/myabilitystage/MyAbilityStage.ets

import { AbilityStage } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    console.info('StageDemo: AbilityStage onCreate');
  }
}

这段代码解决的问题非常单纯:观察 HAP/Module 级运行对象何时进入初始化阶段。

这里使用当前 Kit 化导入方式:

import { AbilityStage } from '@kit.AbilityKit';

AbilityStage 属于 Ability Kit。

2. 在 module.json5 中关联 AbilityStage 和 UIAbility

下面只保留与本文关系直接相关的字段,不代表完整工程的全部配置:

{
  "module": {
    "name": "entry",
    "type": "entry",

    "srcEntry": "./ets/myabilitystage/MyAbilityStage.ets",

    "mainElement": "EntryAbility",
    "pages": "$profile:main_pages",

    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets"
      }
    ]
  }
}

这里最值得看的是两个 srcEntry。

Module 层的:

module.srcEntry

指向 AbilityStage。

而:

module.abilities[].srcEntry

指向具体 UIAbility。

两个字段长得很像,层级却完全不同。这是理解 Stage 工程结构时非常容易忽略的地方。官方 AbilityStage 指导明确使用 Module 的 srcEntry 指定 AbilityStage 源文件;UIAbility 则声明在 abilities 配置中。

六、UIAbility 真正负责的是哪一段

接下来创建最小的 EntryAbility:

// entry/src/main/ets/entryability/EntryAbility.ets

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.info('StageDemo: UIAbility onCreate');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    console.info('StageDemo: UIAbility onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        console.error(`StageDemo: loadContent failed, code=${err.code}`);
        return;
      }

      console.info('StageDemo: pages/Index loaded');
    });
  }

  onForeground(): void {
    console.info('StageDemo: UIAbility onForeground');
  }

  onBackground(): void {
    console.info('StageDemo: UIAbility onBackground');
  }

  onWindowStageDestroy(): void {
    console.info('StageDemo: UIAbility onWindowStageDestroy');
  }

  onDestroy(): void {
    console.info('StageDemo: UIAbility onDestroy');
  }
}

这段代码真正需要关注的不是日志,而是:

onWindowStageCreate(windowStage: window.WindowStage)

系统把已经创建的 WindowStage 交给 UIAbility,然后我们调用:

windowStage.loadContent('pages/Index')

把页面内容加载进去。

官方当前 API 示例仍使用 UIAbility、window.WindowStage 和 loadContent() 这一组合,推荐的 Kit 导入分别来自 @kit.AbilityKit 与 @kit.ArkUI。

这个最小骨架不涉及相机、定位、文件读取等受控能力,因此本文场景不需要额外申请运行时权限。

七、ArkUI Page 是链路最末端的 UI

页面可以保持得非常简单:

// entry/src/main/ets/pages/Index.ets

@Entry
@Component
struct Index {
  build() {
    Column() {
      Text('Stage Model')
        .fontSize(28)

      Text('AbilityStage → UIAbility → WindowStage → ArkUI Page')
        .fontSize(16)
        .margin({ top: 16 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

对应的页面配置可以放在:

entry/src/main/resources/base/profile/main_pages.json

例如:

{
  "src": [
    "pages/Index"
  ]
}

官方当前工程配置资料仍采用 pages: "$profile:main_pages" 与 main_pages.json 中 src 页面列表的方式组织页面。

这里还要再区分一次:

@Entry
@Component
struct Index

这里的 @Entry 表示当前 ArkUI Page 的入口组件,它不是 entry HAP,也不是 EntryAbility。

官方 ArkUI 页面生命周期文档将 Page 定义为应用的 UI 页面,并指出使用 @Entry 修饰的自定义组件作为该页面的默认入口组件。

也就是说,HarmonyOS 工程里至少存在三个容易混淆的“入口”概念:

entry HAP
EntryAbility
@Entry ArkUI Component

名字接近,但不是一个层级。

八、几个特别容易理解错的地方

1. AbilityStage 不是 Application 的另一种写法

AbilityStage 是 Module 级组件容器。

如果应用只有一个 entry HAP,看起来它似乎就是整个应用唯一的顶层对象;但到了多 HAP 工程,这种理解马上会出问题。

官方规定,每个 Entry 或 Feature HAP 在运行期都有对应的 AbilityStage。

所以应该记:

一个应用
  ≠ 一个 AbilityStage

一个 Entry/Feature HAP
  → 对应 AbilityStage

2. UIAbility 不是页面容器的同义词

UIAbility 是应用组件。

WindowStage 才负责连接 UIAbility 与窗口体系,而 ArkUI 页面最终被加载到窗口对应的 UI 实例中。

如果把 UIAbility 直接等价为 Page,后面遇到多窗口、UIContext、多 UI 实例时会越来越难理解。官方关于 UIContext 的说明已经明确存在:

Ability → Window → UIContent

这样的多实例关系。

3. WindowStage 也不是 ArkUI Page

WindowStage 是窗口管理层对象。

Page 是 UI 内容。

loadContent() 恰好把二者连接起来。

因此:

windowStage.loadContent('pages/Index')

不只是“跳到首页”,更准确地说,它是在为这个 WindowStage 关联的窗口加载 ArkUI 页面内容。

4. Page 生命周期不能替代 UIAbility 生命周期

ArkUI Page 有自己的生命周期,例如 onPageShow()、onPageHide();自定义组件又有 aboutToAppear()、aboutToDisappear() 等组件生命周期。

它们和:

UIAbility.onCreate
UIAbility.onForeground
UIAbility.onBackground
UIAbility.onDestroy

不是同一个层级。

页面显示,不等于 UIAbility 被重新创建。

九、HarmonyOS 7 下应该怎么看版本

HarmonyOS 7 已于 2026 年正式发布,对应 API 26。官方开发者月刊和开发者官网均已将 HarmonyOS 7(API 26)作为当前正式版本提供配套资料。

但本文讲的 Stage 骨架不是 API 26 才出现的新能力。

当前 Ability Kit 文档显示,UIAbilityContext、AbilityStageContext 等 Stage 模型基础接口从 API version 9 开始提供,并明确标注只能在 Stage 模型下使用;HarmonyOS 7 / API 26 继续支持这些基础模型。

因此本文更合适的版本表述是:

项目本文结论
当前开发背景HarmonyOS 7
当前正式 APIAPI 26
应用模型Stage
UIAbility / AbilityStageAbility Kit
WindowStage / WindowArkUI 窗口能力
示例语言ArkTS
额外权限本文最小场景不需要
特定设备限制本文只讨论通用应用骨架,不使用设备专属能力

不要因为正在使用 API 26,就把所有基础对象写成“API 26 新增”。

十、实际项目里怎么排查 Stage 层级问题

碰到“页面没有显示”“生命周期和预想不一致”一类问题时,可以按照层级从外往内检查,而不是一开始就改 ArkUI 布局。

可以按这个顺序:

  1. 看 Module/HAP:当前代码到底属于哪个 entry 或 feature Module。
  2. 看 AbilityStage 配置:如果自定义了 AbilityStage,确认 module.srcEntry 是否指向正确文件。
  3. 看 UIAbility 配置:确认 abilities 中的 name、srcEntry 与实际 UIAbility 对应。
  4. 看 WindowStage:确认页面加载逻辑是否发生在正确的 onWindowStageCreate() 中。
  5. 看 loadContent():检查页面路径是否正确,并处理加载错误。
  6. 最后看 ArkUI Page:确认页面是否已经配置、是否存在 @Entry 页面入口组件以及组件树本身是否正确。

这种排查方式的核心就是顺着:

HAP
→ AbilityStage
→ UIAbility
→ WindowStage
→ Page

一层一层往下找。

如果连 WindowStage 都还没有进入预期阶段,只盯着 Index.ets 改布局通常解决不了问题。

开发经验总结

Stage 模型的对象不少,但整体骨架其实可以压缩成四句话。

第一,HAP 是包和 Module 层面的基本单元,AbilityStage 是这一层对应的重要运行期组件容器。

第二,一个 HAP 可以定义 UIAbility;UIAbility 是包含 UI 的应用组件,不等于某一个 ArkUI 页面。

第三,每个 UIAbility 实例会绑定 WindowStage,WindowStage 包含主窗口,为 ArkUI 提供绘制区域。

第四,windowStage.loadContent('pages/Index') 把窗口体系和 ArkUI 页面真正连接起来。

所以,以后再看到默认工程中的:

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index');
  }
}

可以在脑子里直接展开成:

Entry HAP
   ↓
AbilityStage
   ↓
EntryAbility
   ↓
WindowStage
   ↓
Main Window
   ↓
loadContent
   ↓
pages/Index
   ↓
ArkUI Component Tree

把这条主线弄清楚之后,再去理解 UIAbility 生命周期、多窗口、UIContext、Navigation,甚至多 HAP 工程,很多原本零散的概念都会找到自己的位置。

下一次打开一个陌生 HarmonyOS 工程,可以先不看业务代码,沿着 module.json5 → AbilityStage → UIAbility → onWindowStageCreate → loadContent → Page 走一遍。通常几分钟就能把这个工程最基本的运行骨架摸清楚。

❤️ 如果本文帮到了你…

  • 请点个赞,让我知道你还在坚持阅读技术长文!
  • 请收藏本文,因为你以后一定还会用上!
  • 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐