理解 Stage 模型 —— HarmonyOS 应用架构新标准

引言:为什么必须掌握 Stage 模型?

HarmonyOS 3.1 起,华为正式引入 Stage 模型 ,并宣布 FA(Feature Ability)模型逐步废弃 。到 HarmonyOS 6.0.0(API 6.0.2) 时代,Stage 模型已成为唯一推荐的应用架构标准

如果你仍在使用 FA 模型,你的应用将:

  • ❌ 无法上架新版华为应用市场;
  • ❌ 无法使用最新 UI 能力(如 Canvas 高性能绘制、分布式窗口);
  • ❌ 失去对多设备协同、后台任务管理等高级特性的支持。

本文将带你从零彻底搞懂 Stage 模型,涵盖:

  • ✅ Stage vs FA 模型核心差异;
  • UIAbilityWindowStageContext 三大核心概念;
  • ✅ 项目结构文件(main_pages.json, module.json5)详解;
  • ✅ 如何获取屏幕尺寸、窗口、能力上下文;
  • ✅ 完整可运行代码示例(适配 API 6.0.2)。

所有内容均基于 DevEco Studio 4.1 + HarmonyOS 6.0.0 模拟器 实测验证。


一、Stage 模型 vs FA 模型:架构演进之路

1. FA 模型(已废弃)

FA(Feature Ability)模型是 HarmonyOS 早期采用的架构,灵感来自 Android 的 Activity/Service 模式。

scala 复制代码
// FA 模型示例(已不推荐)
export default class MainAbility extends Ability {
  onCreate() {
    // 初始化逻辑
  }
}

AI写代码ts
123456

FA 模型缺陷

  • 能力(Ability)与 UI 强耦合;
  • 多窗口、多实例管理复杂;
  • 缺乏统一的生命周期管理;
  • 难以支持跨设备协同。

2. Stage 模型(现代标准)

Stage 模型采用 "能力(Ability) + 窗口(Window) + 页面(Page)"三层解耦架构,更符合现代操作系统设计理念。

维度 FA 模型 Stage 模型
入口 MainAbility UIAbility
UI 管理 Ability 直接控制 UI WindowStage 管理窗口,Page 描述 UI
生命周期 分散在 Ability 中 统一由 UIAbilityWindowStage 协同管理
多实例支持 困难 原生支持(如分屏、悬浮窗)
跨设备协同 需手动实现 内置 Continuation 能力

💡 核心思想
UI 与业务逻辑分离,窗口与页面解耦,能力可复用


二、Stage 模型三大核心概念

1. UIAbility:应用的能力入口

UIAbility 是 Stage 模型中承载 UI 的能力单元 ,相当于 FA 模型中的 MainAbility,但职责更清晰。

javascript 复制代码
// src/main/ets/UIAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    console.log('UIAbility created');
  }

  onWindowStageCreate(windowStage) {
    // 关键:在此加载主页面
    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        console.error('Failed to load content: ' + JSON.stringify(err));
        return;
      }
      console.log('Content loaded successfully');
    });
  }

  onDestroy() {
    console.log('UIAbility destroyed');
  }
}

AI写代码ts
1234567891011121314151617181920212223

代码逐行解析

  • onCreate():Ability 创建时调用(适合初始化全局状态);
  • onWindowStageCreate(windowStage)窗口创建完成,此时可加载页面;
  • windowStage.loadContent('pages/Index'):指定主页面路径(相对于 src/main/ets);
  • onDestroy():Ability 销毁前清理资源。
    📌 关键点
    UI 不再在 Ability 中定义,而是在独立的 Page 文件中描述 (如 Index.ets)。

2. WindowStage:窗口管理中枢

WindowStage 代表一个应用窗口实例,负责:

  • 加载页面内容;
  • 管理窗口属性(大小、透明度、焦点);
  • 处理窗口生命周期事件。
javascript 复制代码
// 在 UIAbility 中获取 WindowStage
onWindowStageCreate(windowStage: window.WindowStage) {
  // 获取窗口对象
  const window = windowStage.getMainWindowSync();
  
  // 设置窗口背景色
  window.setWindowBackgroundColor('#FFFFFF');
  
  // 加载页面
  windowStage.loadContent('pages/Index', callback);
}

AI写代码ts
1234567891011

典型应用场景

  • 全屏游戏:window.setFullScreen(true)
  • 悬浮窗:通过 windowManager 创建新 WindowStage
  • 多窗口协同:一个 Ability 可管理多个 WindowStage

3. Context:上下文获取桥梁

Context 是访问系统服务、资源、能力的统一入口 。在 ArkTS 中,通过 getContext(this) 获取。

less 复制代码
// 在 Page 组件中获取 Context
@Entry
@Component
struct MyPage {
  build() {
    Column() {
      Button("获取屏幕信息")
        .onClick(() => {
          const context = getContext(this);
          const config = context.config; // 屏幕配置
          const ability = context.getUIAbility(); // 获取 UIAbility 实例
          
          console.log(`Screen: ${config?.screenWidth} x ${config?.screenHeight}`);
        })
    }
  }
}

AI写代码ts
1234567891011121314151617

关键 API

  • getContext(this):在 @Component 中获取上下文;
  • context.config:获取设备配置(屏幕宽高、DPI、语言等);
  • context.getUIAbility():获取当前 UIAbility 实例;
  • context.resourceManager:访问字符串、图片等资源。
    ⚠️ 注意
    getContext(this) 中的 this 必须是 @Component 装饰的 struct 实例,否则会报错。

三、项目结构文件详解(Stage 模型专属)

Stage 模型引入了新的配置文件体系,取代 FA 模型的 config.json

1. main_pages.json:页面路由清单

路径src/main/resources/base/profile/main_pages.json

css 复制代码
{
  "src": [
    "pages/Index",
    "pages/Detail"
  ]
}

AI写代码json
123456

作用

  • 声明所有可被 loadContent() 加载的页面路径;

  • 路径相对于 src/main/ets

  • 必须显式注册 ,否则 loadContent 会失败。
    💡 最佳实践

  • 主页面放第一个;

  • 按功能模块组织路径(如 pages/game/Level1)。


2. module.json5:模块级配置(核心!)

路径src/main/module.json5

kotlin 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility", // 对应 UIAbility 类名
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages", // 引用 main_pages.json
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/UIAbility.ts", // Ability 入口文件
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ]
  }
}

AI写代码json5
123456789101112131415161718192021222324252627282930313233

关键字段解析

字段 说明
mainElement 主 Ability 名称,必须与 abilities.name 一致
srcEntry Ability 的 TypeScript 入口文件路径
pages 引用 main_pages.json,声明页面集合
skills 声明 Ability 的启动意图(如桌面图标点击)

📌 重要变化

FA 模型的 config.json 已被 module.json5 + main_pages.json 取代,配置更模块化、可读性更强


3. build-profile.json5:构建配置

路径 :项目根目录 /build-profile.json5

json 复制代码
{
  "app": {
    "signingConfigs": [],
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "compatibleSdkVersion": "6.0.2(22)", // 关键:指定 API 版本
        "runtimeOnly": false
      }
    ]
  }
}

AI写代码json5
12345678910111213

作用

  • 指定兼容的 SDK 版本(compatibleSdkVersion);
  • 配置签名、产品变体;
  • 控制是否仅运行时(runtimeOnly)。
    适配提示

你的虚拟机为 API 6.0.2(22) ,此处必须匹配,否则安装失败。


四、实战:获取屏幕尺寸、窗口、能力上下文

场景:在页面中动态获取屏幕宽高并调整 UI

typescript 复制代码
// 导入正确的模块和类型(适配 API 6.0.2)
import window from '@ohos.window';
import common from '@ohos.app.ability.common';

@Entry
@Component
struct ScreenInfoPage {
  @State screenWidth: number = 0;
  @State screenHeight: number = 0;
  @State windowMode: string = 'API 6 不支持获取';

  aboutToAppear(): void {
    // 延迟执行,确保窗口已创建
    setTimeout(() => {
      this.updateScreenInfo();
    }, 300);
  }

  updateScreenInfo(): void {
    try {
      // 1. 获取并转换 Context 类型
      const context = getContext(this) as common.UIAbilityContext;
      if (!context) {
        console.error('获取 Context 失败');
        return;
      }

      // 2. 通过 windowStage 获取主窗口尺寸(API 6 兼容方式)
      const windowStage = context.windowStage;
      if (windowStage) {
        const mainWindow = windowStage.getMainWindowSync();
        const windowProperties = mainWindow.getWindowProperties();
        this.screenWidth = windowProperties.windowRect.width;
        this.screenHeight = windowProperties.windowRect.height;
      }

      // 3. 打印 Ability 信息
      if (context.abilityInfo) {
        console.log('UIAbility name:', context.abilityInfo.name);
      }

      // 4. 窗口模式获取在 API 6 中不可用,直接设置提示
      this.windowMode = 'API 6 不支持获取';
    } catch (e) {
      console.error('更新屏幕信息失败:', JSON.stringify(e));
    }
  }

  build() {
    Column() {
      Column() {
        Text(`屏幕尺寸:${this.screenWidth} x ${this.screenHeight}`)
          .fontSize(18)
        Text(`窗口模式:${this.windowMode}`)
          .fontSize(16)
          .margin({ top: 10 })
        Button("刷新信息")
          .onClick(() => this.updateScreenInfo())
          .margin({ top: 20 })
      }
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f0f0f0')
  }
}

AI写代码ts
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667

代码深度解析

  1. getContext(this):在 @Component 中安全获取上下文;
  2. context.config:直接读取屏幕宽高(单位:px),无需异步
  3. context.getUIAbility():获取 UIAbility 实例,用于访问生命周期或窗口;
  4. currentWindowStage.getMainWindowSync():同步获取主窗口(Stage 模型特有);
  5. getWindowMode():判断当前窗口模式(全屏/悬浮等)。
    优势

所有操作均为同步调用,无回调地狱,代码简洁可靠。


五、常见问题与最佳实践

❓ Q1:如何在非 UIAbility 中获取 Context?

A:通过 Ability 的 context 属性传递,或使用 ApplicationContext(需权限)。

❓ Q2:main_pages.json 能否动态修改?

A:不能。所有页面必须在编译时注册,这是出于安全与性能考虑。

✅ 最佳实践:

  • Ability 职责单一 :一个 UIAbility 只负责一类功能(如主界面、设置页);
  • 避免在 Page 中持有 Ability 引用:通过事件通信,而非直接调用;
  • 窗口操作放 Ability 中 :Page 只负责 UI 描述,窗口管理归 UIAbility

六、总结:Stage 模型的核心价值

维度 价值
架构清晰 Ability(能力) + Window(窗口) + Page(页面)三层解耦
生命周期可控 统一入口,便于资源管理与内存优化
多设备友好 原生支持手机、平板、车机、手表的窗口适配
未来-proof 华为官方唯一维护的模型,持续获得新特性

🚀 行动建议

  • 新项目必须使用 Stage 模型
  • 老 FA 项目尽快迁移(华为提供迁移工具);
  • 深入理解 UIAbilityWindowStage 的协作机制。
相关推荐
Cosolar2 小时前
阿里CoPaw进阶使用手册:从新手到高手的完整指南
人工智能·后端·算法
steel80883 小时前
SSM与Springboot是什么关系? -----区别与联系
java·spring boot·后端
ZHOUPUYU3 小时前
PHP 8.6的底层革命。那些看不见的优化,才是真正的惊喜
开发语言·后端·php
凌虚3 小时前
从聊天机器人到超级数字员工:一篇文章看懂 AI 世界的运转逻辑
人工智能·后端·程序员
kevinzeng3 小时前
mysql 的 explain
后端
金坷拉3 小时前
spring rocketmq集成
后端
未秃头的程序猿3 小时前
深入浅出MySQL事务:从ACID到Spring失效场景,2026最新实战指南
java·后端
用户4099322502123 小时前
Vue 3 静态与动态 Props 如何传递?TypeScript 类型约束有何必要?
前端·vue.js·后端
ponponon3 小时前
openclaw 打开 gui web 页面遇到 token 失效的问题原因和解决方案
后端