---
一、痛点:混合应用为何"数据割裂"?
在 OpenHarmony + Flutter 混合开发中,开发者常陷入 "双状态地狱":
- 📱 用户登录后,Flutter 页面显示"已登录",但原生通知插件仍用旧 Token 请求失败;
- 🔔 手表点击"稍后处理",手机 Flutter 页面未刷新待办列表;
- 🌐 多设备协同编辑文档,平板保存后,手机端仍显示旧内容;
- 🧩 状态分散在 Dart、ArkTS、SharedPreferences、Ability Context 中,难以追踪和调试。
根本原因 :缺乏统一的状态源(Single Source of Truth) ,且 跨语言数据同步机制缺失。
二、目标:构建"一次写入,处处响应"的共享状态架构
我们要实现:
✅ Dart 与 ArkTS 共享同一份业务状态 (如用户信息、待办列表);
✅ 任一端修改状态,另一端自动响应 (无需手动刷新);
✅ 支持持久化 + 跨设备同步 ;
✅ 兼容 Riverpod 的响应式编程模型。
三、整体架构设计
┌───────────────────────────────┐
│ Shared State Store │ ← 核心:统一状态容器
│ - 用户信息 │
│ - 待办列表 │
│ - 文档草稿 │
└──────────────▲────────────────┘
│ (双向同步)
┌──────────────┴────────────────┐ ┌──────────────────────┐
│ Flutter (Dart) │ │ OpenHarmony (ArkTS) │
│ - Riverpod Provider │◄────►│ - Observed State │
│ - 自动 rebuild UI │ │ - 触发原生操作 │
└───────────────────────────────┘ └──────────────────────┘
▲ ▲
│ (持久化) │ (持久化)
┌──────┴───────┐ ┌────────┴─────────┐
│ SecureStorage│ │ Preferences Kit │
└──────────────┘ └──────────────────┘
💡 核心思想 :
状态不归属任何一方,而是由一个"中间层"托管,并通过事件总线双向同步。
四、Step 1:定义共享状态模型(JSON Schema)
首先约定 跨平台通用数据结构(使用 JSON 兼容格式):
json
// shared_models/user.json
{
"userId": "string",
"name": "string",
"avatarUri": "string?",
"isLoggedIn": "boolean"
}
// shared_models/todo.json
{
"id": "string",
"title": "string",
"isCompleted": "boolean",
"createdAt": "number" // timestamp
}
✅ 所有字段必须为 基本类型或数组/对象嵌套,避免平台特有类型。
五、Step 2:在 OpenHarmony 端实现状态存储与监听
ohos/src/main/ets/SharedStateStore.ets
typescript
import preferences from '@ohos.data.preferences';
import context from '@ohos.app.ability.context';
import { emitter } from '@ohos.events.emitter';
// 事件 ID(与 Flutter 约定)
const EVENT_USER_UPDATE = 1001;
const EVENT_TODO_UPDATE = 1002;
export class SharedStateStore {
private pref: preferences.Preferences;
private static instance: SharedStateStore | null = null;
private constructor(private ctx: context.Context) {
this.pref = preferences.getPreferences(this.ctx, 'shared_state');
}
static getInstance(ctx?: context.Context): SharedStateStore {
if (!SharedStateStore.instance && ctx) {
SharedStateStore.instance = new SharedStateStore(ctx);
}
return SharedStateStore.instance!;
}
// 获取用户信息
async getUser(): Promise<Record<string, any> | null> {
const jsonStr = this.pref.get('user', '');
return jsonStr ? JSON.parse(jsonStr) : null;
}
// 更新用户并广播
async setUser(user: Record<string, any>): Promise<void> {
await this.pref.put('user', JSON.stringify(user));
await this.pref.flush();
// 广播事件(Flutter 会监听)
emitter.emit({ event: EVENT_USER_UPDATE, data: user });
console.info('[SharedState] User updated and emitted');
}
// 获取待办列表
async getTodos(): Promise<Array<Record<string, any>>> {
const jsonStr = this.pref.get('todos', '[]');
return JSON.parse(jsonStr);
}
// 添加待办
async addTodo(todo: Record<string, any>): Promise<void> {
const todos = await this.getTodos();
todos.push(todo);
await this.pref.put('todos', JSON.stringify(todos));
await this.pref.flush();
emitter.emit({ event: EVENT_TODO_UPDATE, data: todos });
}
// 订阅事件(供 Flutter 初始化后注册)
subscribe(eventId: number, callback: (data: any) => void): void {
emitter.on({ event: eventId }, callback);
}
// 取消订阅
unsubscribe(eventId: number): void {
emitter.off({ event: eventId });
}
}
🔒 安全说明:
- 使用
@ohos.data.preferences实现 加密持久化(需开启 secure 模式);- 所有数据以 JSON 字符串 存储,确保跨平台兼容。
六、Step 3:在 Flutter 端封装共享状态服务
1. 定义 Dart 模型(与 ArkTS 保持一致)
dart
// lib/models/user.dart
class User {
final String userId;
final String name;
final String? avatarUri;
final bool isLoggedIn;
User({
required this.userId,
required this.name,
this.avatarUri,
required this.isLoggedIn,
});
factory User.fromJson(Map<String, dynamic> json) => User(
userId: json['userId'] as String,
name: json['name'] as String,
avatarUri: json['avatarUri'] as String?,
isLoggedIn: json['isLoggedIn'] as bool,
);
Map<String, dynamic> toJson() => {
'userId': userId,
'name': name,
'avatarUri': avatarUri,
'isLoggedIn': isLoggedIn,
};
}
2. 创建共享状态 Bridge(通过 MethodChannel + EventChannel)
dart
// lib/core/shared_state_bridge.dart
import 'package:flutter/services.dart';
class SharedStateBridge {
static const _methodChannel = MethodChannel('com.example.shared_state/methods');
static const _eventChannel = EventChannel('com.example.shared_state/events');
// 初始化(主工程调用)
static Future<void> initialize() async {
await _methodChannel.invokeMethod('initialize');
}
// 获取用户
static Future<User?> getUser() async {
final json = await _methodChannel.invokeMethod('getUser') as String?;
return json != null ? User.fromJson(jsonDecode(json)) : null;
}
// 设置用户
static Future<void> setUser(User user) async {
await _methodChannel.invokeMethod('setUser', user.toJson());
}
// 监听用户变更(返回 Stream)
static Stream<User> onUserUpdate() {
return _eventChannel.receiveBroadcastStream('user')
.map((event) => User.fromJson(event as Map<String, dynamic>));
}
// 监听待办变更
static Stream<List<Todo>> onTodoUpdate() {
return _eventChannel.receiveBroadcastStream('todo')
.map((event) => (event as List).map((e) => Todo.fromJson(e)).toList());
}
}
3. 实现 Riverpod Provider
dart
// lib/providers/shared_state_provider.dart
final userProvider = StreamProvider<User?>((ref) {
// 首次加载
ref.onDispose(() {
// 可选:清理
});
return SharedStateBridge.onUserUpdate().asyncMap((user) async {
return user;
});
});
// 或使用 StateNotifier(更灵活)
class UserNotifier extends StateNotifier<User?> {
UserNotifier() : super(null) {
_loadInitialUser();
_listenToUpdates();
}
Future<void> _loadInitialUser() async {
final user = await SharedStateBridge.getUser();
state = user;
}
void _listenToUpdates() {
SharedStateBridge.onUserUpdate().listen((user) {
state = user;
});
}
Future<void> updateUser(User newUser) async {
await SharedStateBridge.setUser(newUser);
// 不需要手动 setState,事件会自动触发
}
}
final userNotifierProvider = StateNotifierProvider<UserNotifier, User?>((ref) {
return UserNotifier();
});
七、Step 4:双向同步机制打通
OpenHarmony 端:接收 Flutter 的状态变更请求
typescript
// MainAbility.ets 中注册 MethodChannel
flutter.MethodChannel('com.example.shared_state/methods')
.setMethodCallHandler(async (call) => {
const store = SharedStateStore.getInstance();
switch (call.method) {
case 'initialize':
// 初始化完成
return Promise.resolve(true);
case 'getUser':
const user = await store.getUser();
return Promise.resolve(user ? JSON.stringify(user) : null);
case 'setUser':
await store.setUser(call.args as Record<string, any>);
return Promise.resolve(true);
default:
return Promise.reject('Not implemented');
}
});
// 同时,将 emitter 事件转发给 Flutter(通过 EventChannel)
const eventChannel = new flutter.EventChannel('com.example.shared_state/events');
eventChannel.setStreamHandler({
onListen: (arguments) => {
const eventType = arguments as string;
const eventId = eventType === 'user' ? 1001 : 1002;
// 注册监听(emitter → Flutter)
SharedStateStore.getInstance().subscribe(eventId, (data) => {
eventChannel.send(data); // 推送数据
});
return Promise.resolve();
},
onCancel: () => {
// 取消监听
return Promise.resolve();
}
});
✅ 关键逻辑:
- Flutter 通过 MethodChannel 写入状态;
- OpenHarmony 通过 emitter 广播变更;
- Flutter 通过 EventChannel 接收广播 → 自动 rebuild。
八、实战:用户登录状态同步
场景:用户在 Flutter 页面点击"登录"
dart
// 登录按钮回调
onPressed: () async {
final user = await loginApi(); // 假设已获取用户数据
// 更新共享状态
ref.read(userNotifierProvider.notifier).updateUser(user);
// 此时:
// 1. OpenHarmony Preferences 被更新
// 2. 手表/平板上的原生组件收到新用户数据
// 3. 手机 Flutter 页面自动刷新(因 Stream 触发)
}
原生侧(如通知插件)使用最新用户:
typescript
// notification_ohos 插件中
const user = await SharedStateStore.getInstance().getUser();
if (user?.isLoggedIn) {
sendNotification(`欢迎回来,${user.name}!`);
}
九、高级能力扩展
1. 跨设备状态同步
- 将
Preferences替换为 DistributedDataManager; - 状态变更时自动同步到同一账号下的其他设备。
2. 离线优先
- 本地状态立即生效,网络请求异步提交;
- 冲突解决策略:最后写入胜出(LWW) 或 自定义合并函数。
3. 调试工具
- 提供 状态快照导出 功能(用于 bug 复现);
- 在 DevTools 中集成 Shared State Inspector。
十、总结
通过本文,你已掌握:
✅ 构建 Dart 与 ArkTS 共享的状态中心
✅ 利用 Riverpod + emitter 实现响应式数据流
✅ 打破混合应用的数据孤岛
✅ 为多设备协同提供统一状态基础
🚀 适用场景:
- 企业办公(统一身份+待办)
- 智慧医疗(患者档案跨端同步)
- 政务服务(电子证照状态一致)
真正的混合开发,不是 UI 的拼接,而是数据的融合。只有状态统一,体验才能无缝。