我做了一款精力管理App「元気手账」,聊聊从 Swift 移植到鸿蒙 ArkTS 的真实经历
·
起因:我想把自己的精力变化「看见」
去年有段时间状态特别差,每天下午三点准时犯困,开会完脑子一片浆糊,但又说不清到底是什么在消耗我。
市面上的情绪记录App我试了好几个,要么让我写一大段日记(我懒),要么就是打个心情emoji完事(太粗糙)。我想要的是一个特别轻量的东西——就像手机电量百分比一样,随手记一笔"+20 跑步回来精神了"或者"-30 项目评审被锤了",然后在时间轴上看到今天的能量流向。
于是我做了「元気手账」。iOS 版先上了,用 SwiftData 写的,核心就四个模型:EnergyRecord(精力变化记录)、DailyBaseline(每天的基准电量)、Project(方舟项目,追踪精力投在哪)、QuickAction(快捷动作条)。跑了一段时间自己用着挺顺手,就开始琢磨鸿蒙版。
为什么要做鸿蒙版
说实话,不是因为什么"看好鸿蒙生态"这种大话。
原因很朴素:我手边有一台 Mate 60,日常双持。iOS版我自己用着爽,但换到华为手机的时候就断了,记录习惯一中断基本就废了。加上 HarmonyOS NEXT 搞纯血鸿蒙,ArkTS 开发工具链也成熟了不少,我想趁这波把坑踩一遍。
另外 CSDN 和华为开发者社区对 HarmonyOS 内容确实有流量倾斜,这个我不装,也是动力之一。
移植过程中最头疼的三件事
1. 数据层从 SwiftData 到关系型存储的思维切换
iOS 版用 SwiftData 特别舒服,@Model 一标注,关系用 @Relationship 一声明就完事了。比如 Project 和 EnergyRecord 的一对多关系:
@Model
final class Project {
var id: UUID = UUID()
var name: String = ""
var exp: Double = 0
var level: Int = 1
var isLegendary: Bool = false
var totalSeconds: Int = 0
@Relationship(deleteRule: .nullify, inverse: \EnergyRecord.project)
var records: [EnergyRecord] = []
}
```
到了鸿蒙这边,我用的是 `@ohos.data.relationalStore`,得自己建表、自己写 SQL、自己维护外键。说白了就是从 ORM 退回到手写 SQL 的年代。
一开始我想偷懒直接把数据全塞 JSON 存 preferences,后来记录一多查询就卡,老老实实换成了关系型数据库。这个弯路大概浪费了两天。
### 2. ArkUI 的状态管理和 SwiftUI 的差异
SwiftUI 里 `@State`、`@Observable`、`@Environment` 这套我很熟。ArkTS 里对应的是 `@State`、`@Prop`、`@Link`、`@Provide/@Consume`,概念上类似但细节上坑不少。
比如我做时间轴视图的时候,父组件的电量列表更新了,子组件的曲线图没刷新。排查了半天发现是 `@Prop` 传的是值拷贝而不是引用,应该用 `@Link`。这种事在 SwiftUI 里也踩过类似的坑,但鸿蒙的文档当时写得比较模糊,Stack Overflow 上相关问答也少,基本靠自己试。
### 3. 快捷动作条的交互实现
iOS 版的 QuickAction 是一个横向滚动条,点一下就记录一笔,delta 值预设好的。这个交互在 ArkUI 里用 `List` 横向布局加 `onClick` 就能实现,但我想加一个长按编辑的手势,这时候发现 ArkUI 的手势系统和 SwiftUI 差别挺大。
最后用了 `GestureGroup` 配合 `LongPressGesture` 和 `TapGesture` 的组合,调了几版才让长按和点击不冲突。
```arkts
Row() {
ForEach(this.quickActions, (action: QuickActionItem) => {
Column() {
Image($r(`app.media.${action.icon}`))
.width(28).height(28)
Text(action.title)
.fontSize(12)
}
.gesture(
GestureGroup(GestureMode.Exclusive,
LongPressGesture({ repeat: false, duration: 500 })
.onAction(() => { this.editAction(action) }),
TapGesture({ count: 1 })
.onAction(() => { this.recordDelta(action.delta, action.title) })
)
)
})
}
.width('100%')
```
这段是简化过的,实际还有动画和 haptic feedback 的处理,但核心思路就是这样。
## 几个做对了的决策
**用"电量"隐喻而不是"情绪"。** 这个决定是在 iOS 版就定下来的。跟朋友聊的时候发现,很多人对"记录情绪"有心理负担——觉得太私密,或者觉得矫情。但"今天还剩多少电"这个说法大家秒懂,记录起来也没压力。一个 delta 值加一句话,三秒钟搞定。
**方舟项目维度。** 这个功能是后来加的。我自己记了两周发现光看总电量曲线还不够,我想知道"到底是哪个项目把我榨干的"。加了 Project 维度之后,我真的发现写代码其实不怎么费电,反而是写文档和开需求评审会最消耗精力。这个洞察直接影响了我排日程的方式。
**纯本地存储,不联网。** 精力数据算是挺私密的东西,我不想碰云端同步这个坑(也没精力搞服务器)。iOS 版用 App Group + SwiftData 本地存储,鸿蒙版用 relationalStore 存在应用沙箱里。这个在 HarmonyOS 的隐私审核上也省了很多事。
## 当前状态和一些数据
坦白说,鸿蒙版刚上架不久,下载量还很小。七天数据基本是零,付费也是零。
这个我有心理准备。独立开发者做工具类App,冷启动就是这样。iOS 版也是上架头两周没什么动静,第三周在某个效率社区被人分享了一次才开始有自然流量。
鸿蒙的应用市场分发逻辑和 App Store 不太一样,我还在摸索。目前版本号 1.2.0,基本功能都有了:电量记录、时间轴、方舟项目、快捷动作条、周/月统计图。接下来想加的是桌面卡片(HarmonyOS 的 FormAbility),让用户不打开App就能看到当前电量。
## 鸿蒙开发的体感
说几个真实感受:
**DevEco Studio 比两年前好用太多了。** 预览器虽然偶尔抽风,但日常开发够用。热重载的速度可以接受。
**ArkUI 的声明式写法学习曲线不高,** 特别是如果你写过 SwiftUI 或者 Flutter。但一些组件的行为细节文档写得不够清楚,经常得靠试。
**鸿蒙应用市场的审核比 App Store 快,** 基本一两天就过了。但应用市场内的搜索权重逻辑我到现在没完全搞明白。
**有点可惜的是**,鸿蒙的开发者社区讨论质量参差不齐,很多帖子还是"hello world"级别的入门教程,深度踩坑分享太少了。
## 我自己怎么用这个App
每天大概记 5-8 条。早上起来默认 50 点电量(如果昨晚睡得好会手动调到 55),然后一天下来就是加加减减。
上周有一天我发现下午两点电量已经掉到 15 了——上午连着开了三个会。看到这个数字我直接取消了下午的一个非必要会议,出去走了二十分钟。回来记了个"+15 散步",剩余电量够我把当天最重要的代码写完。
这种"量化→决策"的反馈循环,说实话是我做这个App之前没想到的。我以为记录就是记录,没想到看到数字会真的改变行为。
## 写在后面
如果你也在做 HarmonyOS 开发,或者对 ArkTS/ArkUI 有兴趣,欢迎交流。我踩过的坑不少,特别是 SwiftData 到 relationalStore 的数据层迁移、ArkUI 手势系统的组合用法这些,如果有人感兴趣我可以单独写一篇展开讲。
应用商店搜「元気手账」就能找到。
更多推荐


所有评论(0)