【鸿蒙原生应用开发实战】第一篇:从零搭建"萌宠日记"项目------Stage模型与工程架构解析
哈喽大家好,我是AtomCode。最近在搞一个鸿蒙原生应用"萌宠日记",一个宠物健康管理+日常记录的小工具。本文是系列第一篇,带你从新建项目开始,一步步理解鸿蒙Stage模型的工程架构。
一、项目背景与功能概览
"萌宠日记"是一个面向养宠人群的轻量级管理工具,核心功能包括:
| 模块 | 功能说明 | 页面 |
|---|---|---|
| 首页概览 | 宠物卡片切换、快捷入口、动态信息流 | Index.ets |
| 添加宠物 | 表单录入宠物信息(类型/名字/品种/性别等) | AddPetPage.ets |
| 宠物详情 | 健康档案、体重趋势图表、疫苗接种记录 | PetDetailPage.ets |
| 萌宠相册 | 网格/列表双模式切换、按宠物筛选照片 | AlbumPage.ets |
| 提醒管理 | 疫苗/驱虫/美容提醒、今日待办、已完成归档 | ReminderPage.ets |
技术栈:ArkTS + Stage模型 + API 23 (HarmonyOS 6.1)
二、项目初始化与DevEco Studio配置
2.1 创建项目
打开DevEco Studio,选择 File → New → Create Project:
- Application Name: 萌宠日记
- Bundle Name :
com.example.petdiary - Project Type: Application
- Compile SDK: API 23 (HarmonyOS 6.1+)
- Model: Stage
- Language: ArkTS
注意:API 23 对应的是 HarmonyOS 6.1,用的是 Stage 模型而非 FA 模型。Stage 模型是鸿蒙主推的元程序框架,和 FA 模型最大的区别是:Ability 和 UI 分离,支持多实例、组件化、更好的生命周期管理。
2.2 工程目录结构
创建完成后,项目结构如下:
MyApplication/
├── AppScope/ # 全局应用配置
│ ├── app.json5 # 应用级配置(bundleName, version等)
│ └── resources/
│ └── base/element/string.json # 全局字符串(app_name)
├── entry/ # 应用模块
│ ├── src/main/
│ │ ├── ets/
│ │ │ ├── entryability/ # Ability入口
│ │ │ └── pages/ # 页面目录(业务代码)
│ │ ├── module.json5 # 模块配置
│ │ └── resources/ # 资源文件(颜色/字号/字符串)
│ ├── build-profile.json5 # 模块级构建配置
│ └── oh-package.json5 # OHPM依赖管理
├── build-profile.json5 # 项目级构建配置
├── hvigor/ # 构建工具配置
└── oh_modules/ # 依赖包
关键文件解读
AppScope/app.json5 ------ 应用的身份证:
json
{
"app": {
"bundleName": "com.example.myapplication",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name"
}
}
$string:app_name 引用的是 AppScope/resources/base/element/string.json 中定义的 app_name:
json
{ "name": "app_name", "value": "萌宠日记" }
⚠️ 踩坑:
app_name只能在 AppScope 中定义一次。如果在entry模块里也定义同名的app_name,编译时会报冲突。
build-profile.json5 ------ SDK版本控制:
json
{
"products": [{
"name": "default",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.0(23)",
"runtimeOS": "HarmonyOS"
}]
}
compatibleSdkVersion: 23 表示最低兼容 API 23,targetSdkVersion: 24 表示目标 SDK 版本。
三、Stage模型的核心概念
3.1 Ability与UI分离
Stage 模型下,Ability 是应用入口,负责生命周期管理;UI 由页面组件独立完成。
看我们的 EntryAbility.ets:
typescript
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// Ability创建时的初始化逻辑
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// 加载首页
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load content: %{public}s', JSON.stringify(err));
}
});
}
}
生命周期顺序:onCreate → onWindowStageCreate → onForeground。
注意:
@kit.AbilityKit是 API 23+ 的模块导入写法。如果你在 API 23 以下,需要用@ohos.ability.abilityLifecycleCallback。
3.2 页面路由注册
所有页面必须在 main_pages.json 中注册,否则跳转时会找不到页面:
json
{
"src": [
"pages/Index",
"pages/AddPetPage",
"pages/PetDetailPage",
"pages/AlbumPage",
"pages/ReminderPage"
]
}
module.json5 中通过 "pages": "$profile:main_pages" 引用该配置文件。
3.3 路由跳转与参数传递
我们使用 @ohos.router 进行页面导航:
typescript
import router from '@ohos.router';
// 跳转到详情页,携带参数
router.pushUrl({
url: 'pages/PetDetailPage',
params: { petId: 1 }
});
// 接收参数
const params: Record<string, Object> = router.getParams() as Record<string, Object>;
const petId: number = params['petId'] as number;
// 返回上一页
router.back();
关于 @ohos.router vs @kit.AbilityKit
这里有个重要的兼容性问题需要说明:
在 API 23 下,router 模块从 @ohos.router 导入。有些同学在查阅官方文档时可能会看到 @kit.AbilityKit 的写法,但 API 23 的 @kit.AbilityKit 并不导出 router。所以一定要用:
typescript
import router from '@ohos.router'; // ✅ 正确
// import router from '@kit.AbilityKit'; // ❌ API 23 不适用
四、资源管理体系
鸿蒙的资源管理通过 $r 和 $media 等语法糖实现。我们项目中用到了三类资源:
4.1 颜色资源 color.json
json
{
"color": [
{ "name": "start_window_background", "value": "#FFFFFF" },
{ "name": "primary_color", "value": "#FF6B35" },
{ "name": "background_color", "value": "#F5F5F5" },
{ "name": "header_bg", "value": "#1A1A2E" }
]
}
使用方式:$r('app.color.primary_color') 或直接在代码中用字符串 '#FF6B35'。
4.2 字号资源 float.json
json
{
"float": [
{ "name": "title_font_size", "value": "22fp" },
{ "name": "subtitle_font_size", "value": "16fp" },
{ "name": "card_radius", "value": "12vp" },
{ "name": "list_item_height", "value": "80vp" }
]
}
fp是字体像素(Font Pixel),会跟随系统字体大小缩放;vp是虚拟像素(Virtual Pixel),适配不同屏幕密度。
4.3 为什么不把所有样式写在资源文件里?
很多人刚接触鸿蒙开发会问:样式写在代码里还是资源文件里?
我的实践原则是:
- 全局统一Token → 资源文件(主题色、主字体、圆角标准)
- 页面局部样式 → 代码内直接写(方便调试、所见即所得)
我们的项目里颜色直接在代码中写字符串,是因为每个页面有自己的配色风格,抽到资源文件反而增加维护成本。
五、构建与运行
5.1 命令行构建
DevEco Studio 提供了图形化构建,但我们也可以命令行构建:
bash
node "D:\DevEco Studio\tools\node\node.exe" "D:\DevEco Studio\tools\hvigor\bin\hvigorw.js" \
--mode module \
-p module=entry@default \
-p product=default \
-p requiredDeviceType=phone \
assembleHap \
--analyze=normal \
--parallel \
--incremental \
--daemon
参数说明:
--mode module:模块级构建-p module=entry@default:构建 entry 模块的 default 产品assembleHap:打包成 HAP 文件--incremental:增量编译,二次构建更快--daemon:守护进程模式
5.2 真机调试
鸿蒙应用调试推荐使用 远程模拟器 或 真机:
- 在 DevEco Studio 中登录华为账号
- 连接设备或启动模拟器
- 点击运行按钮(▶️)
六、踩坑总结
这一篇先列几个新手必踩的坑:
| 问题 | 表现 | 解决方案 |
|---|---|---|
app_name 重复定义 |
编译报 resource conflict | 只在 AppScope 中定义一次 |
router 导入路径错误 |
编译报找不到模块 | 用 @ohos.router 而非 @kit.AbilityKit |
| 页面跳转报 404 | router.pushUrl 找不到页面 |
检查 main_pages.json 中是否注册 |
| 对象字面量类型错误 | arkts-no-untyped-obj-literals |
为对象字面量显式声明类型/提取为类型变量 |

七、下篇预告
下一篇我们开始写代码!重点分析 首页(Index.ets) 的实现:
- 宠物卡片横向滚动选择器
- 快速操作功能区(4个核心入口)
- 萌宠动态信息流(ForEach 渲染、Emoji 搭配)
咱们下篇见!🚀
SDK版本 : API 23 (HarmonyOS 6.1) | 框架: Stage模型 + ArkTS