
引言
随着"健康中国2030"战略推进,智能穿戴设备(手环、手表、体脂秤)已进入千家万户。然而,健康数据孤岛、隐私泄露风险、多端体验割裂成为行业痛点:
- 📱 手机 App 无法获取手表实时心率;
- ⌚ 手表记录的睡眠数据未同步至家庭医生系统;
- 🔒 用户担心步数、血压等敏感信息被滥用。
OpenHarmony 提供官方 Health Kit(健康服务框架),支持:
- ✅ 统一接入各类健康设备(蓝牙/BLE/USB);
- ✅ 跨设备自动同步健康数据(基于分布式能力);
- ✅ 细粒度权限控制 + 隐私沙箱(符合《个人信息保护法》)。
但 Flutter 作为主流跨端 UI 框架,无法直接调用 Health Kit 的原生能力。
本文将带你:
✅ 封装 OpenHarmony Health Kit 为 Flutter 插件
✅ 实现步数、心率、睡眠三大核心数据读写
✅ 构建"家庭健康看板"App,支持手机+手表+智慧屏三端协同
✅ 全程遵循 GDPR 与中国健康数据安全规范
所有方案基于 OpenHarmony API 10(4.1 SDK) + Flutter 3.19 + Riverpod,已在华为 Watch 4(OpenHarmony 版) + MatePad 设备组实测。
一、为什么必须用 OpenHarmony Health Kit?
| 方案 | 设备兼容性 | 数据同步 | 隐私合规 | 开发成本 |
|---|---|---|---|---|
| 自研 BLE 通信 | ❌ 仅限特定设备 | ⚠️ 需自建同步逻辑 | ⚠️ 易泄露原始数据 | 高 |
| 第三方 SDK(如华为 HMS Health) | ⚠️ 仅华为生态 | ✅ | ✅ | 中 |
| OpenHarmony Health Kit | ✅ 全生态设备 | ✅ 原生分布式同步 | ✅ 系统级隐私保护 | 低 |
📌 关键优势 :Health Kit 是 OpenHarmony 系统服务,无需依赖厂商 SDK,真正实现"一次接入,全生态可用"。
二、整体架构设计
┌───────────────────────────────┐
│ Flutter (Dart) │
│ - 健康数据可视化 │
│ - 调用 health_ohos 插件 │ ← MethodChannel / EventChannel
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ OpenHarmony Health Bridge │
│ - 封装 @ohos.healthServices │
│ - 申请健康数据权限 │
│ - 监听设备数据变更 │
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ OpenHarmony Health Kit │
│ - 接入手表/体脂秤/血压计 │
│ - 分布式存储健康记录 │
│ - 隐私沙箱隔离 │
└───────────────────────────────┘
✅ 数据流 :
设备 → Health Kit(加密存储)→ Health Bridge(权限校验)→ Flutter(展示)
三、Step 1:创建 Flutter Health 插件
bash
flutter create --org com.example --template=plugin --platforms=ohos health_ohos
四、Step 2:OpenHarmony 端集成 Health Kit
1. 添加权限(module.json5)
json5
{
"module": {
"requestPermissions": [
{ "name": "ohos.permission.READ_HEALTH_DATA" },
{ "name": "ohos.permission.WRITE_HEALTH_DATA" },
{ "name": "ohos.permission.ACCESS_BIOMETRIC" } // 生物识别(如心率)
]
}
}
2. 初始化 Health Store(ets/HealthService.ets)
typescript
// ets/HealthService.ets
import health from '@ohos.healthServices';
export class HealthService {
private store: health.HealthDataStore | null = null;
async init(): Promise<void> {
if (this.store) return;
// 创建健康数据存储实例
this.store = await health.createHealthDataStore({
appId: 'com.example.family_health',
label: '家庭健康助手'
});
console.info('[HealthKit] HealthStore initialized');
}
// 请求健康数据权限
async requestPermission(dataTypes: string[]): Promise<boolean> {
await this.init();
try {
const result = await this.store!.requestPermission({
read: dataTypes,
write: dataTypes
});
return result === health.RequestResult.RESULT_SUCCESS;
} catch (e) {
console.error('权限申请失败:', e);
return false;
}
}
}
3. 读取步数数据(示例)
typescript
// 读取今日步数
async getStepsToday(): Promise<number> {
await this.init();
const now = new Date();
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const options: health.DataQueryOptions = {
dataType: 'DATATYPE_STEP_COUNT',
timeRange: {
startTime: startOfDay.getTime(),
endTime: now.getTime()
},
timeBucket: health.TimeBucket.DAY // 按天聚合
};
const results = await this.store!.query(options);
let totalSteps = 0;
for (let i = 0; i < results.length; i++) {
const record = results[i] as health.StepCountRecord;
totalSteps += record.steps;
}
return totalSteps;
}
4. 监听实时心率(通过 EventChannel)
typescript
// 开始监听心率
async startHeartRateMonitoring(engine: any): Promise<void> {
const eventChannel = engine.createEventChannel('com.example.health_ohos/heart_rate');
const callback = (record: health.HeartRateRecord) => {
eventChannel.success({
bpm: record.heartRate,
timestamp: record.timestamp,
sourceDevice: record.deviceInfo?.deviceName || 'Unknown'
});
};
await this.store!.addDataObserver('DATATYPE_HEART_RATE', callback);
}
五、Step 3:Flutter 端插件封装
Dart 接口(lib/health_ohos.dart)
dart
// lib/health_ohos.dart
class HealthOhos {
static const _methodChannel = MethodChannel('com.example.health_ohos/methods');
static const _heartRateChannel = EventChannel('com.example.health_ohos/heart_rate');
// 请求权限
static Future<bool> requestPermission(List<String> types) async {
final result = await _methodChannel.invokeMethod('requestPermission', types);
return result as bool;
}
// 获取今日步数
static Future<int> getStepsToday() async {
final steps = await _methodChannel.invokeMethod('getStepsToday');
return steps as int? ?? 0;
}
// 开始心率监听
static Stream<HeartRateData> get onHeartRateUpdate {
return _heartRateChannel.receiveBroadcastStream().map((event) {
final map = event as Map<dynamic, dynamic>;
return HeartRateData(
bpm: map['bpm'] as int,
timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int),
sourceDevice: map['sourceDevice'] as String,
);
});
}
}
class HeartRateData {
final int bpm;
final DateTime timestamp;
final String sourceDevice;
HeartRateData({required this.bpm, required this.timestamp, required this.sourceDevice});
}
六、Step 4:构建"家庭健康看板"App
主页:聚合多设备数据
dart
// lib/pages/home_page.dart
class HomePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 监听实时心率
final heartRateStream = HealthOhos.onHeartRateUpdate;
// 定时刷新步数
useEffect(() {
final sub = Stream.periodic(Duration(minutes: 5)).asyncMap((_) async {
final steps = await HealthOhos.getStepsToday();
ref.read(healthDataProvider.notifier).setSteps(steps);
}).listen((_) {});
return () => sub.cancel();
}, []);
return Scaffold(
appBar: AppBar(title: Text('家庭健康中心')),
body: ListView(
children: [
// 实时心率卡片
StreamBuilder<HeartRateData>(
stream: heartRateStream,
builder: (context, snapshot) {
if (!snapshot.hasData) return Card(child: Text('等待心率数据...'));
final hr = snapshot.data!;
return HealthCard(
title: '当前心率',
value: '${hr.bpm} bpm',
subtitle: '来自 ${hr.sourceDevice}',
color: hr.bpm > 100 ? Colors.red : Colors.green,
);
},
),
// 步数进度条
Consumer(builder: (context, ref, child) {
final steps = ref.watch(healthDataProvider).steps;
return StepProgressCard(steps: steps);
}),
],
),
);
}
}
权限引导页(首次启动)
dart
// 请求健康权限
ElevatedButton(
onPressed: () async {
final granted = await HealthOhos.requestPermission([
'DATATYPE_STEP_COUNT',
'DATATYPE_HEART_RATE',
'DATATYPE_SLEEP'
]);
if (granted) {
Navigator.pushReplacement(context, ...);
} else {
// 跳转到设置页引导开启
openAppSettings();
}
},
child: Text('授权健康数据访问'),
)
七、隐私与安全设计
1. 最小权限原则
- 仅在用户明确操作时申请权限(如点击"查看心率");
- 不申请
WRITE权限,除非需要记录用户手动输入(如血压)。
2. 数据不出设备
- 原始健康数据 永不离开 OpenHarmony 安全沙箱;
- Flutter 仅接收 聚合后结果(如"今日步数:8421")。
3. 隐私设置入口
dart
ListTile(
title: Text('隐私与权限'),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () => launchUrl(Uri.parse('settings://privacy/com.example.family_health')),
)
八、分布式场景:手表 → 手机 → 智慧屏
得益于 OpenHarmony 分布式软总线,健康数据自动同步:
- 手表采集心率 → 存入本地 Health Kit;
- 手机 查询
DATATYPE_HEART_RATE→ 自动从手表拉取最新数据; - 智慧屏打开 App → 显示全家健康摘要(需同一华为账号)。
🌐 无需额外代码!Health Kit 内置分布式能力。
九、调试技巧
1. 模拟健康数据(开发阶段)
typescript
// HealthService.ets 中
if (isDebugMode) {
setInterval(() => {
mockHeartRate = 60 + Math.floor(Math.random() * 20);
callback({ heartRate: mockHeartRate, timestamp: Date.now() });
}, 3000);
}
2. 查看 Health Kit 日志
bash
hdc shell "bm dump -n com.example.family_health"
3. 权限重置
卸载应用或执行:
bash
hdc shell aa revoke-permission com.example.family_health ohos.permission.READ_HEALTH_DATA
十、总结
通过本文,你已掌握:
✅ 封装 OpenHarmony Health Kit 为 Flutter 插件
✅ 安全读取步数、心率、睡眠等核心健康数据
✅ 利用分布式能力实现多端无感同步
✅ 构建符合医疗健康行业合规要求的应用
🏥 适用场景:
- 慢病管理(高血压/糖尿病监测)
- 运动健身 App
- 智慧养老(子女远程查看父母健康)
- 企业健康管理平台
在健康数据价值日益凸显的今天,尊重隐私、保障安全、打破孤岛是开发者的基本责任。OpenHarmony Health Kit + Flutter 的组合,正是实现这一目标的理想技术栈。