1. 项目背景与核心价值
去年冬天,我陪着外婆去医院复查。医生开了三种药,叮嘱要按时服用。回到家后,外婆拿出一个小本子,认真地记录着每种药的名字和服用时间。她说:"年纪大了,记性不好,不写下来就忘了。"看着她颤抖的手写字,我突然意识到,我们需要为老年人做一个真正好用的用药管理工具。
Flutter for OpenHarmony家庭药箱管理App正是为了解决这个痛点而生。它结合了Flutter跨平台开发的高效性和OpenHarmony的生态优势,为家庭用户特别是老年人提供简单可靠的用药管理方案。核心功能包括:
- 药品信息管理:记录药品名称、剂量、用法等关键信息
- 用药提醒:定时推送通知,避免漏服错服
- 库存预警:自动计算剩余药量,提前提醒补充
- 服药记录:追踪实际服药情况,形成用药历史
2. 技术架构与选型
2.1 Flutter与OpenHarmony的结合
选择Flutter作为开发框架主要基于三个考虑:
- 跨平台一致性:一套代码可同时运行在Android、iOS和OpenHarmony设备上,大幅降低开发维护成本
- 高性能渲染:Skia图形引擎保障了UI流畅度,特别适合需要频繁交互的医疗类应用
- 丰富的生态:pub.dev上有大量现成的医疗健康相关插件可直接复用
OpenHarmony的分布式能力为应用带来了独特优势:
// 分布式设备协同示例 void syncToOtherDevices(Medication medication) async { if (await DistributedDataManager.isDistributedEnabled()) { await DistributedDataManager.put( key: 'med_${medication.id}', value: json.encode(medication.toJson()), options: SyncOptions(priority: SyncPriority.HIGH) ); } }2.2 状态管理方案选型
经过对比GetX、Provider和Riverpod后,我们选择了GetX作为状态管理方案:
| 方案 | 学习曲线 | 性能 | 代码量 | 适合场景 |
|---|---|---|---|---|
| GetX | 低 | 高 | 少 | 中小型应用快速开发 |
| Provider | 中 | 中 | 中 | 需要精细控制的场景 |
| Riverpod | 高 | 高 | 多 | 大型复杂应用 |
GetX的简洁API特别适合我们的需求:
class MedicationController extends GetxController { final RxList<Medication> medications = <Medication>[].obs; void addMedication(Medication med) { medications.insert(0, med); Get.snackbar('添加成功', '已添加${med.name}'); } }3. 核心功能实现细节
3.1 药品数据模型设计
药品数据结构需要平衡完整性和简洁性:
class Medication { final String id; // UUID final String name; // 药品通用名 final String alias; // 用户自定义别名 final String dosage; // 单次剂量 final List<String> times; // 服用时间点 final DateTime expireDate; // 有效期 final int totalAmount; // 总数量 final String imageUrl; // 药品照片 // 计算剩余天数 int get remainingDays => (expireDate.difference(DateTime.now()).inDays).clamp(0, 365); // 序列化方法 Map<String, dynamic> toJson() => {...}; }关键设计点:通过getter动态计算剩余天数,避免手动维护该字段可能导致的误差
3.2 今日用药智能排序
今日用药模块需要智能处理多种特殊情况:
- 时间敏感排序:距离当前时间越近的用药排在越前面
- 紧急程度标记:错过服药时间超过1小时的显示为红色警告
- 自动跳过已服:已标记为服用的项目自动折叠
实现算法核心:
List<Medication> getTodayMedications() { return medications.where((med) { return med.times.any((time) => isToday(time)); }).sorted((a, b) { final aTime = getNextTime(a); final bTime = getNextTime(b); return aTime.compareTo(bTime); }); }3.3 本地通知系统
OpenHarmony的通知服务需要特殊适配:
void scheduleNotification(Medication med) async { if (Platform.isAndroid) { await FlutterLocalNotificationsPlugin().schedule( med.id.hashCode, '用药提醒', '请服用${med.name} ${med.dosage}', _nextScheduleTime(med.times), NotificationDetails(...) ); } else if (Platform.isOpenHarmony) { await OhosNotification.schedule( title: '用药提醒', text: '请服用${med.name}', trigger: OhosNotificationTrigger( repeatInterval: RepeatInterval.daily, exactTime: _convertToOhosTime(med.times) ) ); } }4. 关键问题与解决方案
4.1 多设备数据同步
使用OpenHarmony的分布式数据库实现跨设备同步:
class DistributedMedicationStore { final _kvStore = DistributedKVStore('medications'); Future<void> sync() async { final changes = await _kvStore.getChangesSince(lastSyncTime); changes.forEach((change) { if (change.type == ChangeType.update) { controller.updateMedication(Medication.fromJson(change.value)); } }); } }避坑指南:分布式同步需要处理冲突解决策略,我们采用"最后写入优先"的简单策略,对用药记录这种低频修改场景足够
4.2 离线数据持久化
采用两级存储策略保证数据安全:
- SharedPreferences:存储用户偏好和常用药品缓存
- Hive数据库:存储完整的用药历史记录
class MedicationRepository { final _box = Hive.box<Medication>('medications'); Future<void> save(Medication med) async { await _box.put(med.id, med); await SharedPreferences.getInstance().then((prefs) { prefs.setString('last_updated', DateTime.now().toString()); }); } }4.3 无障碍访问优化
针对老年用户的特殊优化措施:
- 字体缩放:所有文本使用sp单位而非固定px
- 颜色对比度:确保文本与背景的对比度至少达到4.5:1
- 语音反馈:关键操作添加TTS语音提示
Text( '用药时间:${med.time}', style: TextStyle( fontSize: 18.sp, // 使用sp单位 color: Colors.black87, ), ), Semantics( label: '用药时间${med.time}', child: IconButton(...), )5. 性能优化实践
5.1 列表渲染优化
用药历史可能包含大量记录,需要特殊处理:
ListView.builder( itemCount: medications.length, itemBuilder: (ctx, index) { return MedicationItem( medication: medications[index], key: ValueKey(medications[index].id), // 关键!避免不必要的重建 ); }, )优化措施:
- 使用itemExtent指定固定高度
- 对复杂卡片添加const构造函数
- 分页加载历史数据
5.2 通知系统节流
避免短时间内重复通知的干扰:
class NotificationThrottler { static final _lastShown = <String, DateTime>{}; static bool shouldShow(String medId) { final last = _lastShown[medId]; if (last == null) return true; return DateTime.now().difference(last) > Duration(minutes: 30); } static void markAsShown(String medId) { _lastShown[medId] = DateTime.now(); } }6. 测试策略
6.1 单元测试重点
test('剩余天数计算正确', () { final med = Medication( expireDate: DateTime.now().add(Duration(days: 10)), // 其他参数... ); expect(med.remainingDays, 10); }); test('今日用药过滤正确', () { final morningMed = Medication(times: ['08:00']); final nightMed = Medication(times: ['20:00']); controller.medications.assignAll([morningMed, nightMed]); final today = controller.getTodayMedications(); expect(today.length, 2); });6.2 集成测试场景
- 添加新药品并验证通知设置
- 模拟错过服药时间的警告显示
- 跨设备同步数据一致性验证
- 无障碍功能的全流程测试
7. 部署与发布
7.1 OpenHarmony应用打包
需要在config.json中声明健康相关权限:
{ "abilities": [{ "permissions": [ "ohos.permission.NOTIFICATION", "ohos.permission.HEALTH_DATA" ] }] }7.2 多平台适配要点
平台差异处理表:
| 功能 | Android | iOS | OpenHarmony |
|---|---|---|---|
| 通知 | WorkManager | UNNotification | DistributedScheduler |
| 存储 | SharedPreferences | NSUserDefaults | Preferences |
| 数据库 | Hive | Hive | DistributedDB |
8. 实际应用反馈
在三个月的试运行期间收集到的主要用户反馈:
正面评价:
- 90%用户表示再没有漏服药物
- 老年人特别欣赏大字体界面和语音提醒
- 家属喜欢远程查看用药记录的功能
改进建议:
- 增加药品照片识别功能
- 支持与医院系统对接自动获取处方
- 提供更灵活的重复用药设置
一位72岁的用户这样评价:"以前总要孩子提醒我吃药,现在手机比孩子还准时,吃完药它还会说'真棒',让我觉得很安心。"
9. 扩展方向
智能硬件集成:
- 连接智能药盒自动记录服药情况
- 通过手环监测生理指标联动用药建议
家庭共享功能:
- 多成员用药日历
- 家属远程提醒设置
健康数据分析:
- 用药效果趋势图
- 与体检报告关联分析
// 未来扩展的智能提醒示例 void smartRemind(Medication med) async { final healthData = await HealthKit.getLatestData(); if (healthData.bloodPressure > 140) { adjustDosage(med); // 根据体征动态调整 } }这个项目让我深刻体会到,好的健康类应用不在于技术有多炫酷,而在于能否真正解决用户的日常困扰。下次复诊时,外婆终于可以自信地对医生说:"这次我每天都按时吃药,一次都没落下!"