
引言
在电力巡检、野外勘探、应急救灾等场景中,网络不稳定甚至完全中断是常态。传统"先联网再操作"的模式极易导致:
- 📉 数据丢失(提交失败未缓存);
- ⏳ 业务停滞(无网无法使用);
- 🔄 多端冲突(同一设备在手机和平板上修改)。
OpenHarmony 提供强大的 分布式数据管理(Distributed Data Management, DDM) 和 关系型数据库(RDB) ,支持跨设备自动同步;而 Flutter 虽有 hive、isar 等本地数据库,但缺乏原生分布式能力。
本文将教你如何:
✅ 构建"离线优先"架构 :无网时仍可完整操作
✅ 打通 Flutter 与 OpenHarmony RDB 分布式表
✅ 实现基于时间戳 + CRDT 的自动冲突解决
✅ 开发一个"电力设备巡检系统" ,支持 手机录入 → 平板查看 → 后台同步,全程无感。
所有方案基于 OpenHarmony API 10(4.1 SDK) + Flutter 3.19 + Riverpod + Isar,已在华为 MatePad + Pura 70(OpenHarmony 版)组成的分布式设备组实测。
一、核心挑战:离线与分布式的矛盾
| 需求 | Flutter 原生方案 | OpenHarmony 原生方案 | 混合方案 |
|---|---|---|---|
| 本地存储 | ✅ Hive/Isar | ✅ RDB | ✅ Isar(Flutter)+ RDB(同步桥) |
| 离线操作 | ✅ 完全支持 | ✅ 支持 | ✅ 主流程在 Flutter |
| 跨设备同步 | ❌ 无 | ✅ DDM 自动同步 | ✅ RDB 分布式表作为"同步总线" |
| 冲突解决 | ⚠️ 需自研 | ✅ 内置 LWW(Last Write Wins) | ✅ 扩展为 CRDT |
🔑 关键洞察 :
Flutter 负责 UI 与离线体验,OpenHarmony RDB 负责分布式同步 ,两者通过 双向同步代理 桥接。
二、整体架构设计
┌───────────────────────────────┐
│ Flutter (Dart) │
│ - Isar 本地数据库 │
│ - UI / 业务逻辑 │
│ - 监听同步状态 │
└──────────────▲────────────────┘
│ 双向同步
┌──────────────┴────────────────┐
│ OpenHarmony Sync Bridge │ ← MethodChannel + EventChannel
│ - 读写 RDB 分布式表 │
│ - 监听 DDM 数据变更 │
│ - 执行冲突解决策略 │
└──────────────▲────────────────┘
│
┌──────────────┴────────────────┐
│ OpenHarmony 分布式数据管理 (DDM)│
│ - 自动跨设备同步 │
│ - 设备发现与组网 │
└───────────────────────────────┘
✅ 优势:
- 用户始终操作 本地 Isar,响应快、无阻塞;
- 同步由 后台 RDB 桥 异步完成,对 UI 无感;
- 利用 OpenHarmony 原生分布式能力,无需自建 MQTT/WebSocket。
三、Step 1:定义统一数据模型
巡检记录模型(JSON Schema)
json
{
"id": "string", // 全局唯一 ID(UUIDv7)
"deviceId": "string", // 设备编号
"status": "normal|abnormal",
"notes": "string",
"timestamp": 1700000000, // 本地创建时间(Unix ms)
"synced": false, // 是否已同步
"lastModified": 1700000000 // 最后修改时间(用于冲突)
}
💡 使用 UUIDv7(时间有序) 保证全局唯一且可排序。
四、Step 2:Flutter 端 ------ 离线优先数据库(Isar)
dart
// lib/models/inspection.dart
part 'inspection.g.dart';
@Collection()
class Inspection {
Id id = Isar.autoIncrement; // 本地自增 ID(仅用于 Isar)
late String globalId; // 全局 UUID
late String deviceId;
late String status;
late String notes;
late int timestamp;
late bool synced;
late int lastModified;
Inspection({
required this.globalId,
required this.deviceId,
required this.status,
required this.notes,
required this.timestamp,
}) : lastModified = timestamp, synced = false;
}
保存巡检记录(离线可用)
dart
// lib/repositories/inspection_repo.dart
Future<void> saveInspection(Inspection record) async {
// 1. 生成全局 ID(若为新记录)
if (record.globalId.isEmpty) {
record.globalId = Uuid().v7();
record.timestamp = DateTime.now().millisecondsSinceEpoch;
}
record.lastModified = DateTime.now().millisecondsSinceEpoch;
record.synced = false;
// 2. 保存到 Isar
await isar.inspections.put(record);
// 3. 触发同步(异步)
_triggerSync();
}
五、Step 3:OpenHarmony 端 ------ 分布式 RDB 表
创建分布式表(SecurityLevel.S1 即可)
typescript
// model/InspectionModel.ts
const INSPECTION_TABLE_CREATE = `
CREATE TABLE IF NOT EXISTS inspections (
global_id TEXT PRIMARY KEY,
device_id TEXT NOT NULL,
status TEXT NOT NULL,
notes TEXT,
timestamp INTEGER NOT NULL,
last_modified INTEGER NOT NULL,
device_hash TEXT NOT NULL -- 用于冲突识别
)
`;
// 配置分布式
const STORE_CONFIG: rdb.StoreConfig = {
name: 'inspection_store.db',
securityLevel: rdb.SecurityLevel.S1,
distributed: true, // 关键!启用分布式
};
🌐 distributed: true 使该表自动在 同一用户、同一应用、同一网络 下的设备间同步。
六、Step 4:双向同步桥(核心!)
1. Flutter → OpenHarmony(上传未同步记录)
dart
// lib/services/sync_service.dart
Future<void> _uploadPendingRecords() async {
final pending = await isar.inspections.filter().syncedEqualTo(false).findAll();
for (final record in pending) {
await _channel.invokeMethod('putInspection', {
'globalId': record.globalId,
'deviceId': record.deviceId,
'status': record.status,
'notes': record.notes,
'timestamp': record.timestamp,
'lastModified': record.lastModified,
});
// 标记为已同步
final updated = record.copyWith(synced: true);
await isar.inspections.put(updated);
}
}
2. OpenHarmony → Flutter(拉取远程变更)
typescript
// EntryAbility.ts
// 监听 RDB 变更(包括远程设备同步来的)
rdbStore.on('dataChange', (mode, uri) => {
if (uri.tableName === 'inspections') {
this.syncBridge.pullChangesToFlutter(); // 推送至 Flutter
}
});
// 拉取并发送给 Flutter
async pullChangesToFlutter() {
const records = await rdbStore.query(new rdb.RdbPredicates('inspections'));
const list: any[] = [];
while (records.goToNextRow()) {
list.push({
globalId: records.getString('global_id'),
deviceId: records.getString('device_id'),
// ...其他字段
});
}
this.eventChannel.success({ type: 'remote_update', data: list });
}
3. Flutter 接收远程变更
dart
// 监听 EventChannel
eventChannel.receiveBroadcastStream().listen((event) {
if (event['type'] == 'remote_update') {
final remoteList = (event['data'] as List)
.map((e) => Inspection.fromJson(e))
.toList();
// 合并到本地 Isar(触发冲突解决)
_mergeRemoteRecords(remoteList);
}
});
七、Step 5:冲突解决策略(超越 LWW)
OpenHarmony RDB 默认使用 LWW(Last Write Wins) ,但业务上可能不合理。
例如:A 设备注"正常",B 设备注"异常",不能简单以时间为准。
方案:采用 CRDT(Conflict-Free Replicated Data Type) 思想
对于巡检状态,定义 "异常 > 正常" 的优先级规则。
dart
void _resolveConflict(Inspection local, Inspection remote) {
// 规则1:若任一方为 abnormal,则结果为 abnormal
final resolvedStatus = (local.status == 'abnormal' || remote.status == 'abnormal')
? 'abnormal'
: 'normal';
// 规则2:合并备注(避免覆盖)
final resolvedNotes = _mergeNotes(local.notes, remote.notes);
// 创建新版本(更新 lastModified)
final merged = Inspection(
globalId: local.globalId,
deviceId: local.deviceId, // 保留原始设备
status: resolvedStatus,
notes: resolvedNotes,
timestamp: local.timestamp, // 创建时间不变
);
// 保存合并结果,并标记为已同步
isar.inspections.put(merged.copyWith(synced: true));
}
String _mergeNotes(String a, String b) {
if (a == b) return a;
final set = <String>{...a.split('\n'), ...b.split('\n')}.where((s) => s.trim().isNotEmpty);
return set.join('\n');
}
🧠 高级扩展 :可引入 向量时钟(Vector Clock) 实现更精确因果序。
八、网络状态感知与自动重试
dart
// lib/providers/network_provider.dart
final networkProvider = StreamProvider<NetworkStatus>((ref) {
return NetworkStatusManager().onStatusChanged();
});
// 在同步服务中监听
ref.listen(networkProvider, (prev, curr) {
if (curr?.isConnected == true && prev?.isConnected == false) {
// 网络恢复,立即触发同步
syncService.syncNow();
}
});
断网时提示(非阻断)
dart
Consumer(builder: (context, ref, child) {
final offline = !ref.watch(networkProvider).value?.isConnected ?? false;
return Scaffold(
body: Stack(
children: [
// 主界面
InspectionForm(),
// 离线浮层(半透明提示)
if (offline) OfflineBanner(),
],
),
);
});
九、测试场景验证
| 场景 | 预期行为 |
|---|---|
| 手机无网时新增记录 | ✅ 本地保存成功,显示"离线"提示 |
| 手机联网后 | ✅ 自动同步至 RDB 分布式表 |
| 平板在线 | ✅ 几秒内收到同步,显示新记录 |
| 手机和平板同时修改同一设备 | ✅ 触发冲突解决,状态合并为"异常" |
| 删除设备后重新安装 App | ✅ 从分布式网络自动恢复历史数据 |
十、总结:让数据在边缘自由流动
通过本文,你已掌握:
✅ 离线优先架构设计
✅ Flutter 与 OpenHarmony RDB 双向同步
✅ 基于业务规则的冲突解决
✅ 利用 OpenHarmony 原生分布式能力免运维
🌍 未来方向:
- 结合 OpenHarmony 软总线,实现跨 OS(如 Linux 边缘服务器)同步;
- 引入 差分同步,减少流量消耗;
- 支持 部分同步(按区域/角色过滤数据)。
在万物分布式时代,数据不应被网络束缚 。通过深度融合 OpenHarmony 的分布式基因与 Flutter 的跨端体验,我们能构建真正 "随时随地、多端一致" 的下一代行业应用。