古诗小集:从零开发一款 HarmonyOS 古诗鉴赏应用
一、缘起
中国古典诗词是中华文化的瑰宝,千百年来传诵不衰。从李白的「床前明月光」到杜甫的「两个黄鹂鸣翠柳」,这些短短数十字的诗句承载着深邃的情感与哲思。作为一名开发者,我一直想做一款轻量、优雅的古诗鉴赏应用,让用户在碎片时间里能够随时翻阅经典,感受诗词之美。
恰逢 HarmonyOS 生态日趋成熟,ArkTS 语言与 ArkUI 框架为快速构建跨设备应用提供了强大的支持。本文将以「古诗小集」应用为例,详细讲解如何使用 HarmonyOS 6.1 SDK(API 23)开发一款完整的古诗阅读应用,涵盖项目初始化、数据建模、页面路由、UI 设计、构建打包等全流程。
二、项目概览
「古诗小集」是一个轻量级的古诗鉴赏应用,核心功能非常简单:
- 古诗列表页:以列表形式展示收录的古诗,显示标题、作者与朝代信息
- 古诗详情页:点击任意古诗进入详情页,展示原文(居中大字排版)以及详细的注释与译文
应用目前收录了 8 首脍炙人口的唐诗:
- 李白《静夜思》
- 孟浩然《春晓》
- 王之涣《登鹳雀楼》
- 贺知章《咏柳》
- 李白《望庐山瀑布》
- 杜甫《绝句》
- 李白《早发白帝城》
- 柳宗元《江雪》
这 8 首诗覆盖了写景、抒情、咏物、哲理等多种题材,极具代表性。后续可以轻松扩展至数百首,形成一个完整的古诗词库。
三、技术选型与项目初始化
3.1 技术栈
| 技术 | 选择 | 版本 |
|---|---|---|
| 开发工具 | DevEco Studio | 6.1 |
| 开发语言 | ArkTS | 6.1 |
| UI 框架 | ArkUI | 6.1 |
| 目标 SDK | HarmonyOS SDK | API 23 |
| 构建工具 | Hvigor | 内置 |
| 包管理 | Ohpm | 内置 |
HarmonyOS 6.1 对应的应用模型为 Stage 模型,这是 HarmonyOS 自 API 9 起主推的应用开发模型,具有更好的组件化能力和生命周期管理。
3.2 项目结构
app6115/
├── AppScope/
│ ├── app.json5 # 应用级配置(包名、版本号、图标等)
│ └── resources/
│ └── base/element/string.json
├── entry/
│ ├── build-profile.json5 # 模块构建配置
│ ├── oh-package.json5 # 模块依赖声明
│ └── src/main/
│ ├── ets/
│ │ ├── entryability/EntryAbility.ets # 应用 Ability 入口
│ │ ├── model/PoemData.ets # 古诗数据模型
│ │ └── pages/
│ │ ├── Index.ets # 古诗列表页
│ │ └── PoemDetailPage.ets # 古诗详情页
│ ├── module.json5 # 模块清单文件
│ └── resources/
│ └── base/
│ ├── element/ # 字符串、颜色、尺寸资源
│ ├── media/ # 图片资源
│ └── profile/ # 路由配置
├── build-profile.json5 # 项目级构建配置
├── hvigor/ # Hvigor 构建配置
└── oh-package.json5 # 项目级依赖
3.3 关键配置文件
AppScope/app.json5 定义了应用的基本信息:
json
{
"app": {
"bundleName": "com.example.app6115",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name"
}
}
这里的 bundleName 是应用的唯一标识符,类似于 Android 的 packageName。label 引用了资源文件中的字符串,这种方式有利于多语言适配。
entry/src/main/module.json5 定义了模块的 Ability 信息:
json
{
"module": {
"name": "entry",
"type": "entry",
"mainElement": "EntryAbility",
"deviceTypes": ["phone"],
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["ohos.want.action.home"]
}
]
}
]
}
}
其中 skills 字段声明了该 Ability 能够响应主屏启动意图,这是桌面图标点击启动应用的标配配置,不可或缺。
四、数据层设计
4.1 数据模型
在 model/PoemData.ets 中定义了古诗的数据结构:
typescript
export interface Poem {
id: number;
title: string;
author: string;
dynasty: string;
content: string;
注释: string;
}
这里用一个有趣的设计细节:字段名直接使用了中文「注释」。ArkTS 完全支持 Unicode 标识符,所以中文变量名是合法且可运行的。在实际团队协作中,建议还是使用英文命名以保持一致性,但在个人项目中使用中文字段名可以让数据定义更加直观------看到字段就知道它的含义,无需额外的注释说明。
4.2 数据组织
应用将古诗数据定义为一个常数组 poemList,每首诗包含完整的原文和注释译文。以《静夜思》为例:
typescript
{
id: 1,
title: '静夜思',
author: '李白',
dynasty: '唐',
content: '床前明月光,\n疑是地上霜。\n举头望明月,\n低头思故乡。',
注释: '【注释】①静夜思:安静的夜晚产生的思绪。②疑:好像...\n\n【译文】明亮的月光洒在床前...'
}
这种数据组织方式有以下优点:
- 自包含性:每首诗的数据完整独立,方便增删改查
- 可扩展性:可以轻松从 JSON 文件或网络 API 加载数据
- 低耦合:数据与 UI 分离,修改数据无需改动页面代码
五、页面开发详解
5.1 古诗列表页(Index.ets)
列表页是用户打开应用首先看到的界面,设计上追求简洁优雅的古风风格。
5.1.1 页面结构
Column
├── Row ------ 标题栏「古诗小集」
├── Text ------ 副标题「收录经典古诗,品味千年韵味」
└── List ------ 古诗列表
└── ForEach
└── ListItem
└── Column
├── Row
│ ├── Text ------ 序号(金色圆底)
│ ├── Column
│ │ ├── Text ------ 诗名
│ │ └── Text ------ 朝代·作者
│ ├── Blank
│ └── Text ------ 箭头 ›
└── (点击事件)
5.1.2 ForEach 的正确使用
在 ArkTS 中,ForEach 用于在容器组件内部循环渲染数据。其完整签名如下:
typescript
ForEach(
arr: any[],
itemGenerator: (item: any, index?: number) => void,
keyGenerator?: (item: any, index?: number) => string
)
- arr:数据源数组
- itemGenerator:列表项生成器,接收数组中的每个元素
- keyGenerator(可选):键值生成器,用于列表高效更新
实际使用示例:
typescript
List() {
ForEach(this.poems, (item: Poem) => {
ListItem() {
// 每个列表项的 UI 定义
}
.padding({ left: 16, right: 16, bottom: 10 })
}, (item: Poem) => item.id.toString()) // 以 id 作为唯一键
}
keyGenerator 不是必需的,但强烈建议提供。它可以帮助框架在数据更新时精确识别哪些列表项需要重新渲染,极大提升长列表的刷新性能。
5.1.3 样式与布局技巧
古风配色方案:
typescript
// 背景色:米黄色
.backgroundColor('#FAF6EF')
// 标题栏:浅棕色
.backgroundColor('#F5EDE0')
// 主文字:深褐色
.fontColor('#3A2E1E')
// 辅助文字:中褐色
.fontColor('#8B7355')
// 强调色:金色
.fontColor('#C4A265')
卡片阴影效果:
typescript
.shadow({
radius: 4,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
这里的 color 使用十六进制 ARGB 格式,前两位 20 表示透明度为 12.5%(约 32/255),实现轻柔的阴影效果,不喧宾夺主。
5.1.4 页面跳转
typescript
ListItem() {
// ... 列表项内容
}
.onClick(() => {
router.pushUrl({
url: 'pages/PoemDetailPage',
params: { poem: item }
});
})
router.pushUrl 方法用于导航到目标页面,通过 params 字段传递参数。在 HarmonyOS 中,传递复杂对象时,框架会自动序列化和反序列化,开发者无需手动处理。
不过需要注意的是,从 HarmonyOS 6.1 开始,router.pushUrl 已标记为废弃(deprecated),推荐使用新的路由 API。但在当前版本中仍然可以正常工作,迁移到新 API 也很简单。
5.2 古诗详情页(PoemDetailPage.ets)
详情页是用户阅读古诗的核心页面,设计上力求沉浸式阅读体验。
5.2.1 页面结构
Column
├── Row ------ 导航栏(返回按钮 + 标题)
└── Scroll
└── Column
├── Column ------ 诗题 + 作者信息(白色卡片)
├── Column ------ 原文区域(居中大字排版)
└── Column ------ 注释与译文区域
5.2.2 参数接收
typescript
@State poem: Poem = {} as Poem;
aboutToAppear(): void {
const params = router.getParams() as Record<string, Object>;
if (params) {
this.poem = params['poem'] as Poem;
}
}
aboutToAppear 是 ArkTS 的生命周期钩子,在页面即将显示时触发。在这里从路由参数中取出古诗数据并赋值给状态变量,ArkUI 会自动响应状态变化更新 UI。
需要注意的是,router.getParams() 同样已标记为废弃,推荐使用新的 getParams API,但当前版本依然兼容。
5.2.3 原文排版
typescript
Text(this.poem.content)
.fontSize(20)
.fontColor('#3A2E1E')
.lineHeight(36) // 行高适当加大,增强可读性
.letterSpacing(2) // 字间距略宽,营造古风韵味
.textAlign(TextAlign.Center) // 居中排版
.width('100%')
几个设计要点:
- 行高 = 36fp:相对于 20fp 的字号,约 1.8 倍行距,比常见的 1.5 倍更大,营造疏朗的阅读感受
- 字间距 = 2fp:适度加宽字间距,模拟古籍排版的效果
- 居中排版:古诗短小精悍,居中排版更符合传统书法作品的视觉习惯
5.2.4 注释区域
typescript
Text(this.poem.注释)
.fontSize(16)
.fontColor('#555555')
.lineHeight(28)
.width('100%')
注释区域使用稍小的字号和中灰色,与正文形成视觉层次。由于注释文本通常较长,使用 Scroll 容器包裹整个内容区域,确保内容过多时可以滚动查看。
六、路由配置
在 HarmonyOS 中,页面路由需要在 main_pages.json 中注册:
json
{
"src": [
"pages/Index",
"pages/PoemDetailPage"
]
}
列表中的顺序决定了页面在包中的索引顺序,首页必须排在第一位。当使用 router.pushUrl 跳转时,框架会根据这里注册的路径查找对应的页面文件进行加载。
这里有一个常见的坑:如果新增页面后忘记在 main_pages.json 中注册,运行时会报 "Cannot find page" 错误。所以每次新增页面文件时,一定要同步更新路由配置。
七、构建与打包
7.1 构建命令
HarmonyOS 项目使用 Hvigor 作为构建工具,类似于 Android 的 Gradle:
bash
# 查看可用任务
hvigorw tasks
# 构建应用包(APP)
hvigorw assembleApp
# 仅构建模块包(HAP)
hvigorw assembleHap
7.2 构建产物
构建成功后,输出目录如下:
build/outputs/default/
├── app6115-default-unsigned.app # 未签名的应用包
├── pac.json # 包信息
└── pack.info # 包索引
entry/build/default/outputs/default/
├── entry-default-unsigned.hap # 未签名的模块包
└── app/
└── entry-default.hap # 签了调试证书的 HAP(如有配置签名)
「HAP」(Harmony Ability Package)是 HarmonyOS 的应用模块包,类似于 Android 的 APK。一个「APP」包可以包含一个或多个 HAP 包。
7.3 签名配置
构建日志中有一行警告:
Will skip sign 'hos_hap'. No signingConfigs profile is configured in current project.
这是因为项目没有配置签名信息。要在真机上运行,需要在 build-profile.json5 中配置签名。签名配置需要从华为开发者联盟获取证书和密钥。在 DevEco Studio 中,可以通过「File → Project Structure → Signing Configs」界面自动生成签名配置。
八、设计思路与用户体验
8.1 为什么要做古诗应用?
在信息爆炸的时代,人们的注意力被短视频、社交媒体不断切割。古诗词恰恰需要静下心来品味,一两分钟就能读完一首诗。这类轻量级的内容消费非常适合碎片化场景:等公交时、午休间隙、睡前片刻------打开应用读一首诗,既放松身心,又有所收获。
8.2 设计原则
- 内容优先:没有广告、没有复杂的交互,打开就是诗
- 沉浸阅读:米黄色背景模拟古籍纸张质感,减少眩光刺激
- 渐进学习:先看原文自行体会,再翻阅注释和译文对照理解
- 低门槛:无需登录、无网络依赖(数据内置),开箱即用
8.3 后续扩展方向
当前版本功能较为基础,后续可以从以下几个方面扩展:
- 搜索功能:支持按诗名、作者、诗句关键词搜索
- 收藏功能:用户可以将喜欢的诗加入收藏夹
- 朗诵音频:为每首诗配上一段朗诵音频
- 诗词接龙:小游戏化学习机制,提升用户粘性
- 每日推荐:每天推送一首诗,培养阅读习惯
- 多诗源:扩展至宋词、元曲等更多体裁
- 深色模式:适配暗色主题,满足夜间阅读需求
九、踩坑与反思
9.1 问题一:ForEach 语法
在开发过程中遇到的第一个问题是 ForEach 的语法错误:
ERROR: ',' expected. At File: Index.ets:87:7
排查后发现,ForEach 在 ArkTS 中不是普通的函数调用,而是编译期特殊处理的语法结构。它需要三个参数,即使不需要 keyGenerator,也必须为编译器提供明确的结构。最终通过添加 keyGenerator 参数并确保正确的括号嵌套解决了问题。
9.2 问题二:app.json5 label 校验
另一个问题出现在修改应用名称时:
Schema validate failed: 'app.label' must match pattern
'^[$]string:[0-9a-zA-Z_.]+|(?=.*[{])(?=.*[}])[0-9a-zA-Z_.{}]+$'
原来 HarmonyOS 对 app.json5 中的 label 字段有严格的格式要求------它必须是资源引用(如 $string:app_name)或者包含模板占位符,不能直接写入中文文字。解决方案是将应用名称定义在 string.json 资源文件中,然后通过 $string:app_name 引用。
9.3 问题三:资源冲突警告
构建时出现了资源冲突警告:
WARN: 'app_name' conflict, first declared at AppScope/.../string.json but declared again at entry/.../string.json
解决方法是在 entry 模块的 string.json 中移除与 AppScope 重复的 app_name 定义,避免资源覆盖冲突。
十、总结
通过「古诗小集」这个项目的开发,我们完整地走了一遍 HarmonyOS 应用开发的全流程:从项目初始化、数据建模、页面开发、路由配置到构建打包。整个应用代码量不到 400 行(包括数据),却实现了一个功能完整、界面优雅的古诗阅读器。
技术要点回顾
| 知识点 | 对应实现 |
|---|---|
| Stage 模型 | 基于 UIAbility 的应用入口 |
| ArkUI 声明式 UI | Column / Row / List / Text 组件组合 |
| ForEach 列表渲染 | 循环渲染古诗列表 |
| 页面路由 | router.pushUrl + main_pages.json 注册 |
| 状态管理 | @State + aboutToAppear 生命周期 |
| 资源管理 | string.json / color.json / $r 引用 |
| 构建打包 | hvigorw assembleApp |
HarmonyOS 生态正在快速发展,ArkTS 和 ArkUI 的开发者体验也在不断提升。从我这个项目的实际体验来看,声明式 UI 的开发方式与 SwiftUI、Jetpack Compose 的思路非常接近,有相关经验的开发者可以很快上手。同时 HarmonyOS 对中文变量名、中文资源文件的良好支持,也体现了对本土开发者需求的深度理解。
古诗虽小,意境无穷。希望这款小应用能让更多人在忙碌的生活中,偶尔停下脚步,品味一首诗,感受千年前诗人笔下的月光与山河。
本文代码已在 HarmonyOS 6.1 SDK(API 23)环境下编译通过,构建产物为未签名的 APP 包,如需真机运行请自行配置签名证书。



