ArkTS Stage 工程入门:从目录结构到第一个页面
HarmonyOS 应用开发刚入门时,最容易卡住的不是语法,而是"不知道代码从哪里开始跑"。打开 DevEco Studio 新建的 ArkTS Stage 工程后,目录里有 app.json5、module.json5、EntryAbility.ets、Index.ets、resources 等文件。每个文件看起来都重要,但它们分别负责什么?页面是怎么被加载出来的?修改哪个地方才能让应用显示自己的界面?
这篇文章站在第一次接触 Stage 模型的读者角度,把官方快速入门文档里的主线重新梳理一遍:先理解工程结构,再看 UIAbility 入口,最后写一个能运行的首页。

1. 为什么 HarmonyOS 推荐 Stage 模型
Stage 模型是 HarmonyOS 当前主推的应用模型。和早期 FA 模型相比,Stage 模型更强调"模块化"和"生命周期清晰":应用可以由多个模块组成,每个模块里声明自己的 Ability,Ability 再负责窗口、页面和系统交互。
对普通开发者来说,可以先记住三个结论:
UIAbility是应用界面入口,类似"一个可以被系统启动的界面能力"。WindowStage是窗口舞台,首页通常通过它加载。ArkUI 页面是具体界面,常见文件是pages/Index.ets。
2. 新建工程后先看哪几个文件
一个典型 ArkTS Stage 工程会包含下面这些关键文件。
text
entry
├── src
│ └── main
│ ├── ets
│ │ ├── entryability
│ │ │ └── EntryAbility.ets
│ │ └── pages
│ │ └── Index.ets
│ ├── module.json5
│ └── resources
│ ├── base
│ │ ├── element
│ │ ├── media
│ │ └── profile
│ └── rawfile
└── build-profile.json5
这里不要一上来就改很多地方。建议按"配置 -> 入口 -> 页面"的顺序理解:
| 文件 | 作用 | 初学时重点 |
|---|---|---|
app.json5 |
应用级配置 | 应用名称、版本、图标等 |
module.json5 |
模块级配置 | 声明 Ability、页面路由、权限 |
EntryAbility.ets |
UIAbility 入口 | 生命周期、窗口创建、首页加载 |
Index.ets |
ArkUI 首页 | 页面布局、状态、点击事件 |
resources |
资源目录 | 字符串、颜色、图片、profile 配置 |
3. app.json5:应用级配置
app.json5 通常描述整个应用,而不是单个页面。开发时常见的配置包括应用包名、版本、图标、标签等。
json5
{
"app": {
"bundleName": "com.example.stagequickstart",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}
代码解释:
bundleName是应用包名,正式项目中要保持唯一。versionCode面向系统和市场,用数字表示版本递增。versionName面向用户展示,比如1.0.0。icon和label使用资源引用,不建议直接写死文件路径或中文。
4. module.json5:模块和 Ability 的声明入口
module.json5 是初学者必须认真看的文件,因为它决定了系统能不能找到你的 UIAbility。
json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:app_icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}
代码解释:
mainElement指定模块主入口,一般指向EntryAbility。srcEntry指向 UIAbility 源码文件。exported表示该 Ability 是否可以被外部启动。skills中的 home 能力声明决定应用图标入口能否从桌面启动。startWindowIcon和startWindowBackground用于启动页展示。
如果桌面点图标后应用没有正常启动,除了看代码报错,也要检查这里的 mainElement、srcEntry 和 skills。
5. EntryAbility.ets:应用界面的真正入口
EntryAbility.ets 是 Stage 工程里最关键的入口文件。它继承自 UIAbility,系统启动应用时,会回调它的生命周期方法。
ts
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
const DOMAIN = 0x0000;
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'StageQuickStart', 'EntryAbility onCreate');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(DOMAIN, 'StageQuickStart', 'WindowStage create');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'StageQuickStart', 'loadContent failed: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'StageQuickStart', 'loadContent success');
});
}
onForeground(): void {
hilog.info(DOMAIN, 'StageQuickStart', 'EntryAbility foreground');
}
onBackground(): void {
hilog.info(DOMAIN, 'StageQuickStart', 'EntryAbility background');
}
}
代码解释:
onCreate表示 Ability 被创建,适合做轻量初始化。onWindowStageCreate表示窗口舞台创建,这里通常加载首页。windowStage.loadContent('pages/Index')会加载pages/Index.ets。onForeground和onBackground分别对应前台和后台切换。- 日志使用
hilog,调试生命周期时比console.log更适合。
6. pages/Index.ets:第一个 ArkUI 页面
首页文件一般放在 entry/src/main/ets/pages/Index.ets。下面写一个简单但完整的页面:标题、说明、计数器按钮、状态展示都有。
ts
@Entry
@Component
struct Index {
@State count: number = 0;
build() {
Column({ space: 18 }) {
Text('ArkTS Stage 快速入门')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
Text('这个页面由 EntryAbility 通过 WindowStage 加载。')
.fontSize(16)
.fontColor('#5A6B7B')
.textAlign(TextAlign.Center)
Text(`当前点击次数:${this.count}`)
.fontSize(20)
.fontColor('#0A7F64')
Button('点击一次')
.width('80%')
.height(48)
.fontSize(18)
.onClick(() => {
this.count++;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.padding(24)
.backgroundColor('#F7FAFC')
}
}
代码解释:
@Entry表示这是一个入口组件。@Component表示这是 ArkUI 自定义组件。@State修饰的变量变化后会触发界面刷新。build()描述页面结构。Column是纵向布局容器,适合做入门页面。
7. 初学者要理解的页面加载关系
这一点非常关键:Index.ets 本身不会凭空显示出来,它需要被窗口加载。
ts
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
return;
}
});
这里的 'pages/Index' 不写 .ets 后缀。路径和文件结构必须对应:
text
entry/src/main/ets/pages/Index.ets
如果你把页面文件改名为 Home.ets,那么加载路径也要同步改成:
ts
windowStage.loadContent('pages/Home');
8. 加一个更接近真实项目的首页布局
真实项目不会只有一个按钮。下面这个首页更接近业务应用:上方展示标题,中间展示功能卡片,底部提供操作入口。
ts
@Entry
@Component
struct Index {
private features: string[] = ['Stage 模型', 'ArkUI 页面', '资源引用', '页面跳转'];
build() {
Column({ space: 20 }) {
this.Header()
this.FeatureList()
this.Footer()
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#EEF4F8')
}
@Builder
Header() {
Column({ space: 8 }) {
Text('HarmonyOS Stage 工程')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Text('先理解入口,再写页面,最后扩展业务。')
.fontSize(16)
.fontColor('#667788')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
@Builder
FeatureList() {
Column({ space: 12 }) {
ForEach(this.features, (item: string) => {
Row() {
Text(item)
.fontSize(18)
.fontWeight(FontWeight.Medium)
Blank()
Text('查看')
.fontSize(14)
.fontColor('#0A7F64')
}
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor(Color.White)
}, (item: string) => item)
}
.width('100%')
.layoutWeight(1)
}
@Builder
Footer() {
Button('开始学习')
.width('100%')
.height(52)
.fontSize(18)
}
}
代码解释:
@Builder可以把复杂页面拆成多个局部构建函数。ForEach用于渲染列表。Blank()可以把左右内容撑开。layoutWeight(1)可以让中间列表占据剩余空间。- 页面拆分后更容易维护,也更接近真实项目写法。
9. 日志怎么看
生命周期代码写了 hilog.info 后,可以在 DevEco Studio 的 Log 窗口查看。建议给日志设置统一 tag,方便过滤。
ts
hilog.info(0x0000, 'StageQuickStart', 'WindowStage create');
调试时重点看三类日志:
onCreate是否执行。onWindowStageCreate是否执行。loadContent是否成功。
如果 onCreate 有日志,但 loadContent 失败,多半是页面路径写错或页面编译报错。
10. 常见问题排查
10.1 页面白屏
先检查 EntryAbility.ets 中的路径:
ts
windowStage.loadContent('pages/Index');
再检查文件是否真的存在:
text
entry/src/main/ets/pages/Index.ets
10.2 桌面图标点不开
优先检查 module.json5:
json5
"mainElement": "EntryAbility"
以及 abilities 里的 name 是否一致。
10.3 页面状态不刷新
检查变量是否使用了 @State:
ts
@State count: number = 0;
普通字段变化不会自动触发 UI 刷新。
10.4 改了配置但运行没变化
可以尝试:
- 停止当前运行任务。
- Clean Project。
- 重新 Build。
- 重新安装到设备或模拟器。
11. 这篇文章的学习路线
如果你是初学者,建议按下面顺序练习:
- 新建 ArkTS Stage 工程。
- 找到
EntryAbility.ets。 - 在
onCreate、onWindowStageCreate里加日志。 - 修改
Index.ets页面标题。 - 添加一个
@State计数器。 - 改造页面布局,把页面拆成
Header、FeatureList、Footer。 - 运行到模拟器或真机。
按照这个顺序练一遍,你会真正理解"工程配置、Ability 入口、ArkUI 页面"之间的关系。
12. 总结
ArkTS Stage 工程入门不应该从背 API 开始,而应该先建立运行链路:
text
应用配置 app.json5
↓
模块配置 module.json5
↓
UIAbility 入口 EntryAbility.ets
↓
WindowStage 加载页面
↓
ArkUI 页面 Index.ets
只要这条链路清楚,后面学习页面路由、资源管理、生命周期、Want 跳转、多 Ability 协作都会容易很多。