
从一行 flutter create 到一个完整的鸿蒙心理健康应用——本文是对整个开发旅程的全面回顾。


一、项目速览
| 代码行数 | ~2000 行 Dart(13 个源文件) |
| 页面数 | 4 个主页面 + 首页 |
| 核心依赖 | 2 个(hive_ce + hive_ce_flutter) |
| 目标平台 | HarmonyOS 6.1.0 (API 23) |
| 网络权限 | 0 |
| 外部资源 | 0(全部程序化生成) |
| 构建产物 | ~15 MB(Release HAP) |
二、架构决策回顾
决策 1:Hive CE → ✅ 正确
纯 Dart 的 Hive CE 替代需要原生 SQLite 的 sqflite。在鸿蒙上运行完美,零兼容性问题。写入性能比标准 Hive 慢 60%,但用户完全无感知。
教训:跨平台应用中,"纯 Dart"方案的长期价值远超短期性能。
决策 2:ChangeNotifier → ✅ 正确
不引入 Provider/Bloc/Riverpod,直接用 Flutter 内置的 ChangeNotifier。2 个数据源、5 个页面的规模下,原生方案完全胜任。
边界:如果页面超过 15 个或 Widget 嵌套超过 5 层,应该切换到 Provider。
决策 3:离线优先 → ✅ 正确
零网络权限,所有数据本地存储。AppGallery 审核零阻力,用户隐私信任度最高。
决策 4:程序化资源 → ✅ 正确
用 Dart 代码生成图标和音频。Git 仓库体积减小 350 倍,构建完全可复现,零版权风险。
决策 5:无音频播放 → ⚠️ 待改进
白噪音功能仅有视觉脉冲动画。等待 audioplayers_ohos 或类似方案成熟后接入。音频文件已生成好(WAV),只差播放器。
三、开发时间线与工作量分布
整个项目从零到 AppGallery 上架,实际开发周期约 8 周(业余时间,日均 2-3 小时)。以下是各阶段的时间分布估算:
| 环境搭建与鸿蒙适配 | 25% | DevEco Studio 配置、Flutter 鸿蒙引擎编译、签名证书调试、Hive 迁移 |
| 核心功能开发 | 30% | 情绪记录 CRUD、呼吸引导动画、白噪音视觉、MoodChart 柱状图 |
| 程序化资源生成 | 15% | WAV 编码器、PNG 图标生成器、噪声合成算法、花瓣纹理渲染 |
| 测试与调试 | 10% | 单元测试、Widget 测试、真机测试、多设备兼容性验证 |
| 文档与博客系列 | 15% | 50 篇博客、README、项目文档、代码注释 |
| 发布与审核 | 5% | AppGallery 上架、证书管理、隐私政策、商店截图 |
关键观察:
- 环境搭建占据了四分之一的时间——这是鸿蒙 Flutter 开发最大的门槛。DevEco Studio 与 Flutter 工具链的磨合、签名证书的配置、模拟器连接问题,每一项都可能消耗数天。如果你的团队考虑鸿蒙 Flutter,建议为环境搭建预留充足的缓冲时间。
- 文档投入 15% 看起来奢侈,但物超所值。写博客的过程迫使我系统性地审视每一个技术决策,多次在写作中发现代码中隐藏的边界条件问题。这也是后续 AppGallery 审核中隐私政策一次通过的底气所在。
- 程序化资源生成虽然只占 15%,但避免了长期维护负担。不需要维护二进制资源文件的版本控制、不需要追踪版权来源、不需要在每次设计变更时重新导出 PNG/WAV。
四、技术亮点(展开)
4.1 BreathingCircle:动画驱动与状态机设计
BreathingCircle 是整个应用最核心的交互组件,负责引导用户完成 4-7-8 呼吸法。其技术实现包含三个层次的协同:
- AnimationController:驱动圆形缩放动画,配合 CurvedAnimation 实现缓入缓出的自然呼吸节奏。呼吸周期通过 repeat(reverse: true) 实现无限循环,每个周期精确映射到一个呼吸阶段(吸气/屏息/呼气)。
- Timer 层:独立于动画系统的计时器负责管理阶段切换。每完成一个呼吸阶段,Timer 触发状态转换——这个设计确保了即使动画帧率波动,阶段时长依然精确。
- 状态机:BreatheState 枚举定义了 idle、inhale、hold、exhale、paused 五种状态。暂停/恢复逻辑通过保存动画当前进度值实现无缝恢复,而不是简单地 stop/start。
难点:在鸿蒙平板上测试时发现,部分设备的 AnimationController 在应用切换到后台后不会自动暂停,导致恢复时动画跳帧。解决方案是在 didChangeAppLifecycleState 中显式调用 AnimationController 的停止与重定向。
4.2 MoodChart:纯 Widget 柱状图
没有引入 fl_chart 或 syncfusion,完全用 Flutter 原生 Widget 实现了一个情绪趋势柱状图:
- 每个柱子是一个 AnimatedContainer,高度通过情绪评分(1-5)映射为 20%-100% 的容器高度。
- 五级颜色映射:深绿(愉悦)→ 浅绿(平静)→ 黄(中性)→ 橙(低落)→ 红(沮丧),使用 HSV 色彩空间均匀插值,确保色觉障碍用户可辨识(亮度差异化)。
- 横轴通过 Row + Expanded 实现自适应分布,不依赖绝对定位。
- 图例和标签使用 Column + Text 组合,完全响应式。
为什么不用第三方库:鸿蒙 Flutter 的第三方图表库兼容性参差不齐。fl_chart 在鸿蒙上渲染异常(Canvas 坐标偏移),syncfusion 需要商业授权。自己实现虽然多了 150 行代码,但零依赖、零兼容性问题、零授权费用。
4.3 WAV 编码器:60 行手写
纯 Dart 实现 16-bit PCM mono WAV 文件生成。核心逻辑:
[RIFF 头 4B] + [文件大小 4B] + [WAVE 标记 4B] +
[fmt 块 24B:PCM=1, mono=1, sampleRate, byteRate, blockAlign, bitsPerSample=16] +
[data 块 8B + 音频采样数据]
使用 dart:typed_data 的 ByteData 进行小端字节序写入。采样数据通过 Int16List 直接写入,避免了逐字节转换的性能开销。生成的 WAV 文件在 Windows、Android、鸿蒙系统播放器上均验证通过。
4.4 PNG 编码器:100 行手写 + 花瓣纹理算法
完整的 PNG 编码管线:
为什么不用 dart:ui 的 toImage + toByteData:这些 API 需要一个 Flutter 渲染上下文(即 Widget 树),无法在纯 Dart 脚本中运行。手写 PNG 编码器使得 generate_cover.dart 可以在 CI/CD 流水线中以纯命令行模式运行,不依赖 Flutter 引擎。
4.5 高斯噪声合成:Box-Muller + 滤波 + 调制
四种自然音效的生成链路:
局限性:纯算法合成的声音"干净"但缺少真实录音的复杂泛音结构。白噪音作为放松背景音是可以接受的,但如果追求高保真自然音效,建议接入真实录音库。
五、遇到的坑
| 1 | Hive 崩溃 | FFI 找不到原生库 | 迁移到 hive_ce |
| 2 | 某鸿蒙平板 Hive.initFlutter 失败 | 应用沙箱路径差异 | 降级到 systemTemp |
| 3 | 签名验证失败 | bundleName 不一致 | 统一为 com.flutter.brufen |
| 4 | 模拟器 DevEco 连接超时 | 虚拟化冲突 | 关闭 Hyper-V |
| 5 | 音频插件全部不可用 | 鸿蒙无原生音频 API | 视觉脉冲替代,规划后期接入 |
六、测试覆盖与质量指标
项目采用了分层测试策略,覆盖了数据层、业务逻辑层和 UI 层:
| 单元测试 | MoodModel、AppSettings、WAV 编码器、PNG 编码器、噪声合成算法 | 18 | 纯 Dart,无 Flutter 依赖,CI 中毫秒级完成 |
| Widget 测试 | MoodPicker、MoodChart、BreathingCircle、MoodTimeline | 8 | 使用 pumpWidget + MaterialApp 包裹,验证渲染与交互 |
| 手动真机测试 | 4 个主页面在鸿蒙手机 + 平板上的完整流程 | 12 个场景 | DevEco Studio 连接真机,覆盖安装/卸载/权限/后台恢复 |
未覆盖的部分:
- 集成测试(端到端自动化):鸿蒙目前缺乏稳定的 Flutter 集成测试驱动(flutter drive 对鸿蒙支持有限)。
- 性能测试:未使用 DevEco Profiler 做系统级性能分析。
- 无障碍测试:未覆盖 TalkBack/ScreenReader 的语义标注。
质量反馈循环:在开发过程中,所有单元测试和 Widget 测试在每次提交前通过 flutter test 运行,平均耗时 3 秒。这使得重构时可以快速验证是否引入回归——在将 Hive 迁移到 Hive CE 的过程中,测试套件捕获了 2 处 API 调用不兼容的问题,避免了手动测试的时间成本。
七、经验教训:给开发者的六条 actionable 建议
八、如果重来一次——我会做什么不同
8.1 架构层面
- Hive CE 的 TypeAdapter 应该更早写,而不是等到数据模型稳定后。项目早期手动做了很多 JSON 序列化/反序列化,迁移到 TypeAdapter 后扔掉了约 80 行样板代码。如果从一开始就用 @HiveType 注解标记 Model 类,可以节省大量重构时间。
- 导航设计应该考虑"底部导航 + 嵌套路由"。当前使用的是简单的 IndexedStack + 页面切换,当未来需要从"呼吸页"跳转到"情绪详情页"时,会面临路由状态管理难题。GoRouter 或 Navigator 2.0 的早期引入会更好。
8.2 工程实践
- 应该建立 CI/CD 流水线而不是手动构建。每次 DevEco Studio 构建耗时约 3 分钟,手动构建了至少 30 次——累计浪费了两个小时。GitHub Actions 或 AtomGit CI 配置大约只需要半天,往后的每一次提交都能自动验证。
- Widget 测试应该和 UI 组件同步编写,而不是事后补。项目中期有三次重构(MoodPicker 布局调整、BreathingCircle 参数化、MoodChart 颜色映射变更),每次重构后都需要手动验证 UI 是否正常。如果当时有 Widget 测试,每次重构后 flutter test 3 秒就能给出答案。
8.3 产品设计
- 应该在早期就做一次用户访谈。我的"4-7-8 呼吸法"和"五种情绪分级"设计来自文献调研,但从未在真实用户中验证过。如果能在第一版原型阶段就拿给 3-5 个人试用,可能会发现"情绪粒度不够"或"呼吸节奏太难跟随"等问题,避免后期返工。
- 考虑添加一个引导页(Onboarding)。当前应用打开即是主界面,首次使用的用户可能不清楚"情绪记录"和"白噪音"的关系、不知道呼吸引导怎么用。一个 3 页的滑动引导页可以显著降低新用户的流失率。
九、用户反馈与社区反响
9.1 当前状态
项目于 AppGallery 上架后,截至复盘时,尚处于早期分发阶段。因为是个人项目,未进行付费推广,主要依靠开源社区和博客系列的有机流量。
9.2 已获得的初步反馈
- 博客系列反响:50 篇系列文章在 AtomGit/CSDN 合计获得约 3000 阅读量,其中"环境搭建"和"签名证书"类文章的阅读量最高,说明鸿蒙 Flutter 开发者的首要痛点是开发环境配置。
- 开源社区:GitCode 仓库获得约 20 个 Star,有 2 位开发者提了 Issue 询问鸿蒙 Flutter 的编译问题。
9.3 计划中的用户调研
- 应用内反馈:计划在 2.0 版本中添加"设置 -> 反馈"入口,收集真实的用户评价。
- 目标用户画像验证:设想中目标用户是 18-35 岁、有轻度情绪管理需求的城市人群,但这一假设尚未通过数据验证。
- A/B 测试:如果有足够的用户基数(DAU > 100),计划对"纯视觉白噪音 vs. 真实音频白噪音"的效果做一组 A/B 对照。
9.4 对后来者的建议
如果你也在做一个个人全栈应用并希望获得早期反馈,我的建议是:在功能开发的同时,先完成博客/社交媒体渠道的建设。一篇好的技术文章可能带来 10 倍于商店搜索的初始用户,而且技术读者往往是最有价值的种子用户——他们能给出有深度的反馈。
十、系列文章索引
| 第一篇 | 01-10 | 环境搭建、Hive CE、Stage 模型、离线设计、编译构建、图标生成 |
| 第二篇 | 11-20 | 情绪模型、MoodPicker、时间线、柱状图、呼吸模式、呼吸球、白噪音、触觉反馈 |
| 第三篇 | 21-30 | ChangeNotifier、CRUD、AppSettings、初始化流水线、Tab 架构、错误处理 |
| 第四篇 | 31-42 | AnimatedBuilder、隐式动画、渐变、脉冲、WAV、噪声、PNG、zlib、零资源策略 |
| 第五篇 | 43-50 | 单元测试、Widget 测试、AppGallery 发布、证书管理、Git Workflow、项目复盘 |
十一、展望
十二、给后来者的结语
如果你正在考虑启动一个 Flutter + 鸿蒙的个人项目,以下是我在写完 50 篇文章、完成一个完整应用后最想说的三句话:
第一,鸿蒙 Flutter 的坑比想象中少,但比想象中深。 基本 UI 和业务逻辑几乎零摩擦——Flutter 的跨平台能力在鸿蒙上兑现得很好。真正卡人的地方是三个:签名证书配置、原生插件兼容性、模拟器连接。这三个问题各烧掉了我至少一天的时间。好消息是,一旦跨过这些坎,后续的开发体验和 Android/iOS 几乎没有差别。
第二,做好一个"小"产品比做完一个"大"产品难。 这个项目没有用户系统、没有云同步、没有社交功能——看起来很简单。但真正把 4 个页面打磨到"可以用",需要的精力远超预期。动画的缓动曲线调了 3 版、情绪颜色的对比度改了 5 次、WAV 编码器重写了 2 遍。如果你也追求"小而美",请做好心理准备:小不等于快。
第三,50 篇文章写完后,最大的收获不是项目本身,而是写作过程中建立的系统性思维。 当你强迫自己把每一个技术决策写成 2000 字的中文文章时,那些模糊的"我觉得这样比较好"会变成清晰的"因为 A、B、C 三个原因,在 X 约束下,Y 方案优于 Z 方案"。这种思维方式的转变,是任何教程都教不了的。
项目源码:https://gitcode.com/PengXiansheng/E-Brufen 全系列索引:README.md
作者简介:E-Brufen Dev,Flutter & 鸿蒙开发者。希望这 50 篇文章对你的鸿蒙 Flutter 之旅有所帮助。




