鸿蒙原生应用实战(五):塔罗牌App开发 — 数据模型、构建配置与工程优化
·
鸿蒙原生应用实战(五):塔罗牌App开发 — 数据模型、构建配置与工程优化
前言
经过前四篇的逐步开发,我们已经完成了塔罗牌 App 的所有功能页面。本篇作为收官之作,将聚焦于那些"看不见但至关重要"的部分:
- TarotData 全量数据模型:78 张塔罗牌的数据结构设计与内容填充
- 资源文件管理:string / float / color 资源的定义与引用
- 构建配置解析:build-profile / hvigor / module.json5 配置详解
- API 版本适配:compatibleSdkVersion 与 targetSdkVersion 的策略
- ArkTS 严格模式规则:常见编译错误及解决方案
- 工程构建与发布:从代码到 HAP 包的完整流程
一、TarotData 数据模型深度解析
1.1 数据结构设计
塔罗牌分为两大类:
- 大阿卡纳(Major Arcana):22 张(编号 0-XXI),代表重大人生课题
- 小阿卡纳(Minor Arcana):56 张(分四花色 × 14 张),代表日常事务
export interface TarotCard {
id: number; // 唯一标识(0-77)
name: string; // 中文名称(如"愚者""魔术师")
englishName: string; // 英文名称(如"The Fool""The Magician")
arcana: string; // 分类:'大阿卡纳' 或 '小阿卡纳'
number: string; // 编号(如'0'、'I'、'权杖一')
keywords: string; // 关键词(如"开始、冒险、天真")
meaningUp: string; // 正位含义
meaningDown: string; // 逆位含义
description: string; // 牌面描述
color: string; // 显示颜色(十六进制)
isFavorite: boolean; // 收藏状态(未使用,保留字段)
}
1.2 大阿卡纳数据示例
以下是部分大阿卡纳牌的数据(共 22 张,编号 0-XXI):
export const TAROT_CARDS: TarotCard[] = [
{
id: 0,
name: '愚者',
englishName: 'The Fool',
arcana: '大阿卡纳',
number: '0',
keywords: '开始、冒险、天真、无限可能',
meaningUp: '愚者正位象征着全新的开始、天真的冒险精神和对未知的期待。这张牌鼓励你放下过去的包袱,勇敢地踏上新的旅程。它代表着一个充满可能性的新阶段,提醒你保持开放的心态和对世界的好奇心。',
meaningDown: '愚者逆位暗示着鲁莽、不负责任的决策或对后果的忽视。你可能在逃避责任,或者在某个重要决定上过于草率。这张牌提醒你需要三思而后行,避免因冲动而后悔。',
description: '愚者站在悬崖边缘,背上背着一个行囊,手中握着一朵白玫瑰,仰望天空。他即将迈出脚步,却完全不在意前方的危险。身边的小狗在吠叫,试图提醒他注意。画面中明亮的黄色背景象征着新的开始和无限的可能性。',
color: '#F5E642',
isFavorite: false
},
{
id: 1,
name: '魔术师',
englishName: 'The Magician',
arcana: '大阿卡纳',
number: 'I',
keywords: '创造力、技能、资源、显化',
meaningUp: '魔术师正位代表着你有能力将想法转化为现实。你拥有所需的一切资源和技能,只需要善加运用。这张牌鼓励你相信自己的能力,主动采取行动去创造你想要的现实。',
meaningDown: '魔术师逆位暗示着才能被浪费、操控他人或缺乏方向。你可能没有充分利用自己的天赋,或者正在用不正当的手段达到目的。需要重新审视自己的动机和方法。',
description: '魔术师站在桌前,一只手举向天空接收能量,另一只手指向大地,象征着"如上如下"的宇宙法则。桌上摆放着四大元素的象征物——圣杯、宝剑、星币和权杖。他头上有无限符号,代表着无限的潜力。',
color: '#E8B832',
isFavorite: false
},
// ... 共 78 张牌
];
1.3 数据填充的工程化思考
为 78 张牌填写完整的中英文含义是一项大工程。在实际项目中,我有几点建议:
- 结构化优先:先确定接口字段,再填充数据
- 分批填充:按大阿卡纳(22 张)→ 权杖组(14 张)→ 圣杯组(14 张)→ 宝剑组(14 张)→ 星币组(14 张)分批完成
- 释义长度控制:正逆位释义各保持在 100-150 字之间,过长会影响阅读体验
- 颜色编码:为每张牌分配一个辨识色,增加视觉层次感
二、资源文件管理
2.1 字符串资源
// resources/base/element/string.json
{
"string": [
{ "name": "title_home", "value": "命运之轮" },
{ "name": "title_cards", "value": "全部牌义" },
{ "name": "title_spread", "value": "牌阵解读" },
{ "name": "title_favorites", "value": "我的收藏" },
{ "name": "today_card", "value": "今日塔罗" },
{ "name": "module_desc", "value": "塔罗牌占卜应用" },
{ "name": "EntryAbility_desc", "value": "塔罗牌主入口" },
{ "name": "EntryAbility_label", "value": "命运之轮" }
]
}
2.2 浮点尺寸资源
// resources/base/element/float.json
{
"float": [
{ "name": "app_title_size", "value": "28fp" },
{ "name": "app_subtitle_size", "value": "22fp" },
{ "name": "app_body_size", "value": "16fp" },
{ "name": "app_small_size", "value": "14fp" },
{ "name": "app_caption_size", "value": "12fp" },
{ "name": "app_card_radius", "value": "16vp" },
{ "name": "app_button_radius", "value": "24vp" }
]
}
2.3 颜色资源
// resources/base/element/color.json
{
"color": [
{ "name": "start_window_background", "value": "#1A0A2E" },
{ "name": "primary_text", "value": "#FFFFFF" },
{ "name": "secondary_text", "value": "#B8A8D0" }
]
}
为什么使用 $r() 引用资源?
- 支持多语言适配(国际化)
- 支持多设备适配(不同 dpi 自动缩放)
- 编译时校验,避免硬编码错误
三、构建配置解析
3.1 项目级 build-profile.json5
{
"app": {
"signingConfigs": [],
"products": [
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.1.1(24)", // 目标 SDK
"compatibleSdkVersion": "6.1.0(23)", // 兼容最低版本
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true, // 大小写检查
"useNormalizedOHMUrl": true // 归一化 OHM URL
}
}
}
],
"buildModeSet": [
{ "name": "debug" },
{ "name": "release" }
]
}
}
API 版本策略解读:
| 参数 | 值 | 含义 |
|---|---|---|
| compatibleSdkVersion | 23 | 最低支持 API 23 的设备 |
| targetSdkVersion | 24 | 最高使用 API 24 的特性 |
| runtimeOS | HarmonyOS | 仅运行在 HarmonyOS 上 |
3.2 模块级 build-profile.json5
{
"apiType": "stageMode", // Stage 模型
"buildOption": {
"resOptions": {
"copyCodeResource": {
"enable": false // 不复制代码资源
}
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": { // 代码混淆配置
"ruleOptions": {
"enable": false, // 可开启以减小包体
"files": ["./obfuscation-rules.txt"]
}
}
}
}
]
}
3.3 AppScope/app.json5 — 全局应用配置
{
"app": {
"bundleName": "com.example.myapplication", // 包名,全局唯一
"vendor": "example",
"versionCode": 1000000, // 内部版本号
"versionName": "1.0.0", // 对外版本名
"icon": "$media:layered_image",
"label": "$string:app_name" // 应用名称(仅在 AppScope 定义一次)
}
}
注意:
app_name只需在AppScope的string.json中定义一次,不可在entry模块中重复定义,否则编译会报冲突。
3.4 module.json5 — 模块配置
{
"module": {
"name": "entry",
"type": "entry", // entry 类型(可独立运行)
"mainElement": "EntryAbility",
"deviceTypes": ["phone"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages", // 路由配置引用
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["ohos.want.action.home"]
}
]
}
]
}
}
关键字段解释:
type: "entry":可独立安装运行的应用入口模块skills:声明 Ability 的能力,entity.system.home+ohos.want.action.home表明这是桌面入口pages:引用main_pages.json中注册的所有页面路由
四、ArkTS 严格模式规则详解
在开发过程中,严格模式(arkts-no-untyped-obj-literals 等)是误报最多的配置。以下是完整的规则及应对方案:
4.1 规则清单
| 规则 | 含义 | 触发场景 |
|---|---|---|
arkts-no-untyped-obj-literals |
对象字面量必须显式类型 | const obj = {a:1, b:2} |
arkts-no-noninferrable-arr-literals |
数组字面量必须可推断类型 | const arr = [{a:1, b:2}] |
arkts-no-nullable-array |
不允许可空数组类型 | arr?: string[] |
arkts-no-any |
不允许 any 类型 | let x: any |
arkts-no-eval |
不允许 eval | eval(code) |
4.2 实战解决方案
方案一:提取为具名变量
// ❌ 错误:字面量数组无法推断
// ForEach(this.drawnCards, (item: NumberedCard) => { ... })
// ✅ 正确:显式声明后使用
const positions = ['过去', '现在', '未来'];
方案二:对象赋值使用类型断言
// ❌ 可能的不严格写法
const card = { id: 0, name: '愚者' };
// ✅ 显式声明类型
const card: TarotCard = {
id: 0, name: '愚者', englishName: '', arcana: '', // 全部字段
number: '', keywords: '', meaningUp: '', meaningDown: '',
description: '', color: '#FFF', isFavorite: false
};
方案三:@Component 属性必须初始化
@Component
struct MyComponent {
// ✅ 所有属性必须赋默认值
name: string = '';
count: number = 0;
items: string[] = [];
callback?: () => void; // 可选属性用 ?
}
4.3 编译错误排查技巧
当 DevEco Studio 报编译错误时,按以下步骤排查:
- 看错误码:
arkts-no-xxx的格式直接表明违反的规则 - 定位行号:大多数错误会精确到行
- 检查字面量:70% 的错误是对象/数组字面量缺少类型声明
- 检查类型:组件属性、函数参数是否都有明确类型
五、构建与发布流程
5.1 本地构建命令
# 使用 DevEco Studio 内置的 hvigor 构建
"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 文件 |
--parallel |
并行构建加速 |
--incremental |
增量编译 |
--daemon |
守护进程模式 |
5.2 构建产物
构建完成后,HAP 包位于:
entry/build/default/outputs/default/entry-default-unsigned.hap
5.3 签名与发布
- 在 DevEco Studio 中配置签名证书(
.p12+.cer+.p7b) - 使用
build→Build HAP(s)生成已签名的 HAP - 上传至华为应用市场 AppGallery Connect
六、项目经验总结
6.1 架构回顾
经过五篇文章的开发,我们的塔罗牌 App 形成了清晰的架构分层:
┌─────────────────────────┐
│ UI 层 (pages/) │ ← 5 个页面
├─────────────────────────┤
│ 模型层 (model/) │ ← TarotData 数据 + 管理器
├─────────────────────────┤
│ 能力层 (ability/) │ ← EntryAbility 入口
├─────────────────────────┤
│ 配置层 (config/) │ ← build / module / resources
└─────────────────────────┘
6.2 关键技术决策
| 决策 | 选择 | 理由 |
|---|---|---|
| 开发模型 | Stage 模型 | 官方推荐,适合复杂应用 |
| 开发语言 | ArkTS | 类型安全,编译期校验 |
| 状态管理 | 静态类管理器 | 轻量、无第三方依赖 |
| 主题切换 | 订阅发布模式 | 解耦、可扩展 |
| 路由导入 | @ohos.router |
API 23 兼容性 |
6.3 后续可扩展方向
- 数据持久化:Preferences 存储收藏数据
- 网络请求:对接塔罗牌 API 获取每日运势
- 动画效果:抽牌翻转动画、卡片入场动画
- 自定义牌阵:用户自由选择牌数和位置
- 多语言支持:英文版、日文版国际化
- Widget 服务卡片:桌面显示今日塔罗

结语
五篇文章,从环境搭建到发布上线,我们完整地走了一遍鸿蒙原生应用的开发流程。这个塔罗牌 App 虽小,但五脏俱全——路由导航、列表渲染、组件化、状态管理、主题切换、构建配置,覆盖了日常开发中的大多数场景。
鸿蒙生态正在快速发展,现在入局正当时。希望这个系列能成为你鸿蒙开发路上的实战参考。如果你有任何问题或想法,欢迎在评论区交流讨论!
项目代码: 基于 HarmonyOS API 23 + Stage 模型 + ArkTS
源码位置:entry/src/main/ets/
构建工具: DevEco Studio + hvigor
全文完 🎉
附录:本系列目录
| 篇号 | 标题 | 核心内容 |
|---|---|---|
| 第一篇 | 环境搭建与首页开发 | 项目初始化、Stage 模型、Index 首页 |
| 第二篇 | 牌义列表与路由导航 | CardListPage、CardDetailPage、路由传参 |
| 第三篇 | 牌阵解读与交互设计 | SpreadPage、随机算法、正逆位判定 |
| 第四篇 | 收藏功能与主题切换 | FavoriteManager、ThemeManager、FavPage |
| 第五篇 | 数据模型与工程优化 | TarotData、构建配置、严格模式、发布流程 |
更多推荐




所有评论(0)