HarmonyOS 技术实战 01:从 0 到 1 打造离线优先的养宠 App 架构
前言
很多 HarmonyOS 入门 Demo 停留在“页面跳转 + 列表渲染”,但真正做一个能发布的 App,难点往往不是某一个 API,而是如何把业务闭环、系统能力、状态持久化和体验细节串起来。
本系列会基于一个真实项目“喵汪星球”来拆解。它是一款离线优先的养宠助手 App,核心功能包括:
- 宠物档案与多宠管理
- 投喂、饮水、清洁、睡前记录等照护打卡
- 系统日历提醒
- 陪玩建议与收藏
- 健康症状本地比对与就医信息卡
- 宠物叫声录音、音频导入和本地规则分析
- FormKit 桌面卡片联动
- 明暗色主题适配
这篇先讲整体架构。后续每篇再深入一个模块。
为什么选择“离线优先”
养宠工具有一个很典型的使用场景:用户不是每天坐下来认真填表,而是在喂饭、清洁、出门前、发现异常时快速打开 App。这个场景要求应用具备三个特点:
第一,启动后马上可用。宠物档案、今日照护、最近记录不应该依赖网络返回。
第二,隐私边界清晰。宠物健康记录、叫声录音、照片等内容默认保存在本地,用户更容易信任。
第三,功能要能闭环。不是做一个“知识库页面”,而是让用户从建档、提醒、打卡、异常处理到信息汇总都能走完。
所以项目从一开始就把“本地数据 + 离线可用 + 单机闭环”作为主架构,而不是先做账号体系和云同步。
Stage 模型下的入口设计
项目入口在 entry/src/main/ets/entryability/EntryAbility.ets。作为一个 Stage 模型应用,主 Ability 负责创建窗口、加载 ArkUI 页面,并处理来自桌面卡片的跳转参数。
核心代码如下:
export default class EntryAbility extends UIAbility {
onCreate(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
this.context
.getApplicationContext()
.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET)
this.applyCardNavigation(want)
}
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, TAG, 'Failed to load content.')
}
})
}
onNewWant(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
this.applyCardNavigation(want)
}
}
这里有两个值得注意的点。
第一,loadContent('pages/Index') 让主页面集中在 ArkUI 侧组织。这个项目当前是一个单页多模块结构,底部 Tab 切换由 @State 控制,适合 MVP 快速验证。
第二,onNewWant 处理桌面卡片再次拉起应用的情况。很多同学只在 onCreate 里读参数,结果应用已经在后台时,卡片点击无法切到目标页面。这里把参数处理抽成 applyCardNavigation,在创建和新 Want 两个生命周期里都调用。
模块边界怎么划分
虽然当前核心页面集中在 Index.ets,但业务模型已经很清晰。可以把它拆成六层看:
entry/
entryability/ 应用入口、Want 参数处理
entryformability/ 桌面卡片数据更新
widget/pages/ 卡片 UI
common/ 主题、颜色、字号、间距
pages/Index.ets 当前 MVP 主页面与业务逻辑
resources/
base/element/ 浅色主题资源
dark/element/ 深色主题资源
base/media/ 图标、头像、玩法图片
如果后续继续工程化,可以按项目文档里规划的结构拆成:
model/
services/
repository/
components/
pages/
common/
但是在首版 MVP 中,先把业务闭环跑通是更关键的。代码不是越早拆越好,而是当状态、数据、页面复用开始变多时,再把它们拆到稳定边界里。
业务闭环设计
喵汪星球不是一个单点功能 App,而是一个围绕“宠物日常照护”的闭环:
- 用户先创建宠物档案。
- App 根据档案生成默认照护任务。
- 用户在记录页完成、延后、跳过或新增照护项目。
- 首页聚合下一件事和未完成任务。
- 桌面卡片展示当前宠物和下一件事。
- 发现异常时,用户进入健康页做症状比对。
- 必要时生成就医信息卡,带上档案和最近记录。
- 日常陪伴时使用陪玩推荐或叫声分析。
这种闭环的好处是:每一个模块都不是孤立页面。档案影响记录,记录影响卡片,健康模块引用档案和记录,翻译器也根据宠物类型调整分析结果。
关键状态模型
项目在 Index.ets 中定义了比较完整的状态集合,例如:
@StorageLink('mwCurrentTab') currentTab: string = '首页'
@State selectedPetId: string = ''
@State selectedPetName: string = ''
@State petProfiles: PetProfile[] = []
@State todayTasks: CareTask[] = []
@State careTaskGroups: DayCareTaskGroup[] = []
@State translationHistory: TranslationHistory[] = []
@State symptomInput: string = ''
@State customHealthAdvice: string = ''
这里可以看到两类状态:
- 页面交互状态:当前 Tab、表单草稿、弹层是否展示、录音是否进行中。
- 业务持久状态:宠物档案、照护任务、历史记录、症状输入、翻译反馈。
@StorageLink('mwCurrentTab') 是一个亮点。它让应用主页面可以响应来自 AppStorage 的 Tab 更新。桌面卡片点击后,Ability 把目标 Tab 写入 AppStorage,页面自动切换。
离线数据怎么落地
首版没有引入数据库,而是使用 Preferences 存储一个序列化后的 App 状态快照:
const store = await preferences.getPreferences(context, { name: 'miaowang_state' })
await store.put('app_state', JSON.stringify(this.buildPersistedState()))
await store.flush()
这不是适合所有场景的方案,但对这个 MVP 很合适。原因是:
- 数据量可控,主要是档案、任务、收藏、记录和历史。
- 读写频率不极端,用户操作后保存即可。
- 结构迭代快,方便做字段兼容。
后续如果健康日志、图片记录、统计趋势继续增长,可以再把记录型数据迁移到关系型数据库或键值分表。
系统能力接入清单
这个项目已经接入或预留了多项 HarmonyOS 能力:
"requestPermissions": [
{ "name": "ohos.permission.MICROPHONE" },
{ "name": "ohos.permission.READ_CALENDAR" },
{ "name": "ohos.permission.WRITE_CALENDAR" }
]
对应功能包括:
MICROPHONE:宠物叫声录音。READ_CALENDAR / WRITE_CALENDAR:把照护项目同步到系统日历。FormKit:桌面服务卡片。PhotoViewPicker:宠物头像选择。AudioViewPicker:音频文件导入。Preferences:本地状态持久化。AppStorage:App 与卡片、Ability 间的轻量状态传递。
这些能力组合起来,比单纯做页面 Demo 更能体现 HarmonyOS App 的完整性。
本篇小结
喵汪星球的架构核心不是复杂,而是克制:
- 用 Stage + ArkUI 搭建主应用。
- 用单页多模块先跑通 MVP。
- 用 Preferences 支撑离线优先。
- 用 AppStorage 打通卡片与主应用。
- 用系统日历、录音、Picker 等能力增强真实使用价值。
下一篇我们进入 ArkUI 页面层,拆解如何用 @State、@StorageLink 和 Builder 方法搭建一个五 Tab 的应用首页。
更多推荐


所有评论(0)