OpenHarmony + Flutter 混合开发进阶:构建支持离线优先、边缘同步与冲突解决的分布式数据应用

引言

在电力巡检、野外勘探、应急救灾等场景中,网络不稳定甚至完全中断是常态。传统"先联网再操作"的模式极易导致:

  • 📉 数据丢失(提交失败未缓存);
  • 业务停滞(无网无法使用);
  • 🔄 多端冲突(同一设备在手机和平板上修改)。

OpenHarmony 提供强大的 分布式数据管理(Distributed Data Management, DDM)关系型数据库(RDB) ,支持跨设备自动同步;而 Flutter 虽有 hiveisar 等本地数据库,但缺乏原生分布式能力

本文将教你如何:

构建"离线优先"架构 :无网时仍可完整操作

打通 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 的跨端体验,我们能构建真正 "随时随地、多端一致" 的下一代行业应用。


https://openharmonycrossplatform.csdn.net/content

相关推荐
大龄秃头程序员2 小时前
Dart/Flutter StatefulWidget 生命周期 + ChangeNotifier Listener 泄漏的经典坑。
flutter
清风与日月4 小时前
Yitter.IdGenerator:高性能分布式唯一ID生成器详解
分布式·c#·.net·.netcore
大龄秃头程序员5 小时前
Flutter踩坑记-WebSocket 通知挤占事件循环
flutter
FfHUCisI5 小时前
Golang Redis 分布式锁
redis·分布式·golang
陈皮波比茶6 小时前
RabbitMQ 消息队列
分布式·rabbitmq
恋猫de小郭7 小时前
Gradle 9.7.0 将提速 Android 构建,Sync 提升接近一倍
android·前端·flutter
敖行客 Allthinker7 小时前
分布式远程研发团队,借助云 IDE 统一开发环境
ide·分布式
iFlyCai8 小时前
Flutter三棵树核心详解之Widget树完全解析(二)
flutter·statelesswidget
磐链科技18 小时前
交场景下的钱包开发痛点:并发交易与消息推送的分布式一致性技术方案
分布式
GitLqr20 小时前
Flutter 实战:使用 local_auth 实现生物识别(指纹/Face ID)
安全·flutter·全栈