《鸿蒙原生应用开发实战》第一篇:项目框架搭建与路由体系
《鸿蒙原生应用开发实战》第一篇:项目框架搭建与路由体系
前言
从零开始构建一个鸿蒙原生应用,第一步就是搭好脚手架。本文将详细讲解如何基于 HarmonyOS Stage 模型,从创建项目到完成路由体系的完整搭建。我们以「光遇·心境」App 为例,这是一个沉浸式光感场景探索应用。
本文将涵盖:
- Stage 模型与 FA 模型的区别
- 项目目录结构与配置文件
- Ability 的注册与生命周期
- 沉浸式窗口配置(状态栏/导航栏透明)
- 页面路由注册与跳转体系
一、Stage 模型 vs FA 模型
HarmonyOS 从 API 9 开始推荐使用 Stage 模型,相比旧的 FA 模型,Stage 模型有以下优势:
| 对比维度 | Stage 模型 | FA 模型 |
|---|---|---|
| 组件化 | 一个应用包含多个 Module | 以 Ability 为核心 |
| 生命周期 | UIAbility + ExtensionAbility 明确分工 | 生命周期耦合较重 |
| 窗口管理 | WindowStage 统一管理 | 每个 Ability 各自管理 |
| 后台任务 | ExtensionAbility 专职后台 | 与前台 Ability 混在一起 |
本项目配置 build-profile.json5 中指定了 stage 模式:
{
"apiType": "stageMode",
"buildOption": {
"resOptions": {
"copyCodeResource": {
"enable": false
}
}
}
}
二、项目目录结构解析
一个标准的 Stage 模型项目结构如下:
MyApplication/
├── AppScope/ # 全局应用配置
│ ├── app.json5 # 应用级配置(bundleName、版本号等)
│ └── resources/
│ ├── base/element/ # 全局资源(string.json)
│ └── media/ # 应用图标
├── entry/ # 主模块
│ ├── src/main/
│ │ ├── ets/
│ │ │ ├── entryability/ # Ability 入口
│ │ │ ├── entrybackupability/ # 备份扩展能力
│ │ │ ├── model/ # 数据模型层
│ │ │ └── pages/ # 页面层
│ │ ├── module.json5 # 模块配置
│ │ └── resources/ # 模块资源
│ └── build-profile.json5 # 模块构建配置
├── build-profile.json5 # 项目级构建配置
└── hvigor/ # 构建工具配置
AppScope/app.json5 —— 应用的"身份证"
{
"app": {
"bundleName": "com.example.myapplication", // 应用唯一标识
"vendor": "example",
"versionCode": 1000000, // 版本号(整数)
"versionName": "1.0.0", // 展示给用户的版本
"icon": "$media:layered_image", // 应用图标
"label": "$string:app_name" // 应用名称
}
}
⚠️ 注意事项:
app_name只需在AppScope中定义一次,不可在entry模块的string.json中重复定义,否则编译会报资源重复错误。
三、Ability 注册与生命周期
EntryAbility —— 应用的"大门"
// entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
// 1. Ability 创建时调用 —— 适合做全局初始化
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 设置颜色模式(跟随系统)
this.context.getApplicationContext().setColorMode(
ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
);
}
// 2. WindowStage 创建 —— 这是最关键的生命周期方法
onWindowStageCreate(windowStage: window.WindowStage): void {
// 这里配置沉浸式窗口
// ...
// 加载首页
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', '加载失败: %{public}s', JSON.stringify(err));
}
});
}
// 3. 前后台切换
onForeground(): void { /* 应用进入前台 */ }
onBackground(): void { /* 应用进入后台 */ }
// 4. 销毁
onDestroy(): void { /* 释放资源 */ }
}
module.json5 —— Ability 的注册地
{
"module": {
"name": "entry",
"type": "entry", // entry=主模块, feature=特性模块
"mainElement": "EntryAbility", // 入口 Ability
"deviceTypes": ["phone"],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"exported": true, // 是否暴露给外部应用调用
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["ohos.want.action.home"] // 桌面图标启动
}
]
}
],
// 扩展 Ability —— 这里我们注册了备份能力
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup", // 备份恢复类型
"exported": false
}
]
}
}
四、沉浸式窗口 —— 打造全屏无边框体验
作为光感场景应用,沉浸式体验是核心。我们需要让内容延伸到状态栏和导航栏区域。
// EntryAbility.ets —— onWindowStageCreate 中的关键配置
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.getMainWindow((err, wnd) => {
// 1. 启用全屏布局(状态栏和导航栏区域也可绘制内容)
wnd.setWindowLayoutFullScreen(true, (err1) => {
// 2. 设置状态栏和导航栏透明
wnd.setWindowSystemBarProperties({
statusBarColor: '#00000000', // 完全透明
navigationBarColor: '#00000000', // 完全透明
isStatusBarLightIcon: true, // 白色图标(适配深色背景)
isNavigationBarLightIcon: true // 白色图标
});
// 3. 窗口背景透明(避免白块闪烁)
wnd.setWindowBackgroundColor('#00000000');
});
});
}
实现效果:
- 状态栏不再是黑条或白条,而是完全透明
- 页面的渐变背景从屏幕顶部开始渲染
- 底部导航栏同样透明,页面内容铺满全屏
页面中需要预留状态栏高度的占位:
build() {
Column() {
// 状态栏占位(5%高度的空行,让内容不被状态栏遮挡)
Row().height('5%').width('100%')
// 实际内容...
Scroll() { /* ... */ }
}
}
五、页面路由注册体系
路由表配置
在 main_pages.json 中注册所有页面路由:
{
"src": [
"pages/Index", // 首页
"pages/ScenePage", // 场景探索列表页
"pages/DetailPage", // 场景详情页
"pages/FavPage", // 收藏页
"pages/ProfilePage" // 个人中心页
]
}
路由规范
API 23 下,路由的导入和使用有严格规范:
// ✅ 正确的导入方式
import router from '@ohos.router';
// ❌ 错误方式(API 23 不导出此路径)
// import router from '@kit.AbilityKit';
// 页面跳转(携带参数)
router.pushUrl({
url: 'pages/DetailPage',
params: { sceneId: 1 }
});
// 页面返回
router.back();
// 接收参数
const params = router.getParams() as Record<string, Object>;
const id = params['sceneId'] as number;
路由体系总览
Index(首页)
├── push → ScenePage(场景列表,可携带 category 参数)
│ └── push → DetailPage(场景详情,携带 sceneId)
├── push → DetailPage(每日推荐直接进入)
├── push → FavPage(收藏页)
└── push → ProfilePage(个人中心)
这种星型路由结构非常清晰:所有子页面都可以通过 router.back() 返回首页,用户体验一致。
六、构建配置说明
API 版本配置(build-profile.json5)
{
"products": [
{
"name": "default",
"targetSdkVersion": "6.1.1(24)", // 目标 SDK
"compatibleSdkVersion": "6.1.0(23)", // 兼容的最低 SDK
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true // ArkTS 严格模式
}
}
}
]
}
构建命令
hvigorw --mode module -p module=entry@default -p product=default \
-p requiredDeviceType=phone assembleHap \
--analyze=normal --parallel --incremental --daemon
七、常见踩坑记录
坑1:app_name 重复定义
现象:编译报错 “duplicate resource”
原因:同时在 AppScope 和 entry 模块中定义了 app_name
解决:app_name 只在 AppScope/resources/base/element/string.json 中定义
坑2:router 导入路径错误
现象:运行时崩溃 “Cannot find module”
原因:API 23 不支持 @kit.AbilityKit 导出的 router
解决:统一使用 import router from '@ohos.router'
坑3:沉浸式窗口出现白底闪烁
现象:启动时背景短暂变白
原因:startWindowBackground 未设置为深色
解决:在 module.json5 中将 startWindowBackground 设为 $color:start_window_background(在我们项目中是 #1a1a2e)

总结
本篇我们完成了:
- ✅ 理解 Stage 模型的核心概念
- ✅ 项目目录结构与配置文件解析
- ✅ Ability 生命周期与注册
- ✅ 沉浸式窗口配置实战
- ✅ 页面路由注册与跳转体系
- ✅ 构建配置与常见踩坑记录
项目的路由体系是整个应用的骨架,下一篇我们将深入 ArkTS 数据模型设计,看看如何优雅地管理应用的状态和数据流。
下一篇预告:ArkTS 数据模型与状态管理 —— @State 装饰器、AppStorage 全局存储、数据流设计模式
更多推荐




所有评论(0)