Flutter三方库适配OpenHarmony【secure_application】— 插件架构设计哲学
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net大多数 Flutter 插件的架构很直白:Dart 层调,原生端处理完返回结果,完事。但走了一条完全不同的路——它的 Dart 层不是薄薄的一层封装,而是一个完整的状态管理框架,包含 Widget、Controller、Provider、事件流。理解这个架构设计,是理解整个适配工作的前提。
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
大多数 Flutter 插件的架构很直白:Dart 层调 MethodChannel.invokeMethod,原生端处理完返回结果,完事。但 secure_application 走了一条完全不同的路——它的 Dart 层不是薄薄的一层封装,而是一个完整的状态管理框架,包含 Widget、Controller、Provider、事件流。
理解这个架构设计,是理解整个适配工作的前提。今天我们来拆解它的设计哲学。
一、与传统 Flutter Plugin 的架构对比
1.1 传统 Plugin 架构
以 flutter_speech 为例,典型的 Flutter Plugin 架构是这样的:
┌─────────────────────────┐
│ Dart 层(薄封装) │
│ SpeechRecognition │
│ - activate() │
│ - listen() │
│ - cancel() │
│ - stop() │
└──────────┬──────────────┘
│ MethodChannel
┌──────────▼──────────────┐
│ Native 层(重逻辑) │
│ FlutterSpeechPlugin │
│ - 引擎创建/销毁 │
│ - 权限申请 │
│ - 监听器管理 │
│ - 回调转发 │
└─────────────────────────┘
特点:Dart 层轻,Native 层重。核心逻辑在原生端。
1.2 secure_application 的架构
┌──────────────────────────────────────┐
│ Dart 层(重逻辑) │
│ SecureApplication (Widget) │
│ ├── SecureApplicationController │
│ │ ├── State 管理 │
│ │ ├── BehaviorSubject 事件流 │
│ │ └── secure/lock/unlock 方法 │
│ ├── SecureApplicationProvider │
│ ├── SecureGate (Widget) │
│ │ └── BackdropFilter 模糊遮罩 │
│ └── WidgetsBindingObserver 生命周期 │
└──────────────┬───────────────────────┘
│ MethodChannel(指令下发 + 事件上报)
┌──────────────▼───────────────────────┐
│ Native 层(轻逻辑) │
│ SecureApplicationPlugin │
│ ├── setWindowPrivacyMode │
│ ├── 窗口事件监听 │
│ └── 生命周期回调 │
└──────────────────────────────────────┘
特点:Dart 层重,Native 层轻。核心逻辑在 Dart 端。
1.3 为什么这样设计
| 考量 | 传统 Plugin | secure_application |
|---|---|---|
| 核心能力在哪 | 平台原生 API | Flutter Widget 层 |
| 跨平台一致性 | 各平台行为可能不同 | Dart 层保证一致 |
| UI 相关吗 | 不相关 | 强相关(模糊遮罩) |
| 状态复杂度 | 简单 | 复杂(四状态机) |
| 适配工作量 | 原生端为主 | 原生端较少 |
💡 核心洞察:secure_application 的模糊遮罩是用 Flutter 的
BackdropFilter实现的,不是原生 UI。原生端只负责"告诉 Flutter 该锁了"和"设置截屏防护"。这意味着适配 OpenHarmony 时,Dart 层代码完全不用改。
二、Widget 驱动 vs 纯方法调用
2.1 纯方法调用模式
// flutter_speech 的使用方式
final speech = SpeechRecognition();
speech.activate('zh_CN');
speech.listen();
speech.setRecognitionResultHandler((text) => print(text));
开发者直接调用方法,手动管理回调。
2.2 Widget 驱动模式
// secure_application 的使用方式
SecureApplication(
onNeedUnlock: (controller) async {
// 认证逻辑
controller?.authSuccess(unlock: true);
return null;
},
child: SecureGate(
blurr: 20,
opacity: 0.6,
lockedBuilder: (context, controller) => UnlockScreen(),
child: MyProtectedContent(),
),
)
开发者通过声明式 Widget 来使用插件,状态管理由框架自动处理。
2.3 两种模式的优劣
| 维度 | 纯方法调用 | Widget 驱动 |
|---|---|---|
| 学习成本 | 低 | 中 |
| 使用灵活性 | 高 | 中(受 Widget 树约束) |
| 状态管理 | 开发者自己管 | 框架自动管 |
| UI 集成 | 需要手动 setState | 自动响应状态变化 |
| 适合场景 | 功能型插件 | UI 型插件 |
2.4 对适配的影响
Widget 驱动模式对 OpenHarmony 适配来说是个好消息:
- Dart 层零改动:所有 Widget、Controller、Provider 代码跨平台通用
- 原生端职责明确:只需要实现 MethodChannel 的几个方法
- 测试更容易:可以在任意平台上测试 Dart 层逻辑
三、ValueNotifier + InheritedWidget 状态管理
3.1 为什么不用 Provider 或 Bloc
secure_application 没有引入 Provider、Bloc、Riverpod 等状态管理库,而是用了 Flutter 自带的 ValueNotifier + InheritedWidget。
原因很简单:作为一个基础设施级别的插件,它不应该强制用户依赖某个状态管理方案。
// SecureApplicationController 继承自 ValueNotifier
class SecureApplicationController extends ValueNotifier<SecureApplicationState> {
SecureApplicationController(SecureApplicationState value) : super(value);
// ...
}
3.2 ValueNotifier 的工作方式
// 状态变更时通知监听者
void lock() {
SecureApplicationNative.lock();
if (!value.locked) {
value = value.copyWith(locked: true);
notifyListeners(); // 触发所有监听者重建
}
}
notifyListeners() 会通知所有通过 addListener 注册的回调,包括 SecureGate 的 _sercureNotified 方法。
3.3 InheritedWidget 的上下文传递
// SecureApplicationProvider 是一个 InheritedWidget
class SecureApplicationProvider extends InheritedWidget {
final SecureApplicationController secureData;
static SecureApplicationController? of(BuildContext context, {bool listen = true}) {
// 从 Widget 树中查找最近的 Provider
if (listen) {
return context.dependOnInheritedWidgetOfExactType<SecureApplicationProvider>()?.secureData;
}
return context.findAncestorWidgetOfExactType<SecureApplicationProvider>()?.secureData;
}
}
这样任何子 Widget 都可以通过 SecureApplicationProvider.of(context) 获取 Controller。
3.4 状态流转的完整链路
用户切后台
│
▼
WidgetsBindingObserver.didChangeAppLifecycleState(inactive)
│
▼
SecureApplicationController.lock()
│
├── SecureApplicationNative.lock() → MethodChannel → Native
├── value = value.copyWith(locked: true)
└── notifyListeners()
│
▼
SecureGate._sercureNotified()
│
▼
_gateVisibility.value = 1 → 模糊遮罩显示
四、BehaviorSubject 响应式事件流
4.1 为什么用 rxdart
secure_application 引入了 rxdart 依赖,使用了其中的 BehaviorSubject:
dependencies:
rxdart: ^0.28.0
final BehaviorSubject<SecureApplicationAuthenticationStatus>
_authenticationEventsController =
BehaviorSubject<SecureApplicationAuthenticationStatus>.seeded(
SecureApplicationAuthenticationStatus.NONE);
4.2 BehaviorSubject vs StreamController
| 特性 | StreamController | BehaviorSubject |
|---|---|---|
| 新订阅者收到最新值 | ❌ | ✅ |
| 默认值 | ❌ | ✅(seeded) |
| 多次订阅 | broadcast 才行 | 默认支持 |
| 获取当前值 | 不支持 | .value 属性 |
BehaviorSubject 的关键特性是新订阅者立即收到最新值。这对 secure_application 很重要——当一个新页面订阅认证事件时,它需要立即知道当前的认证状态,而不是等到下次状态变化。
4.3 两个事件流
// 认证事件流
Stream<SecureApplicationAuthenticationStatus> get authenticationEvents =>
_authenticationEventsController.stream;
// 锁定事件流
Stream<bool> get lockEvents => _lockEventsController.stream;
| 事件流 | 触发时机 | 用途 |
|---|---|---|
| authenticationEvents | authSuccess/authFailed/authLogout | 清除敏感数据、更新 UI |
| lockEvents | lock/unlock | 暂停媒体播放、保存草稿 |
4.4 使用示例
// 监听认证失败,清除敏感数据
controller.authenticationEvents
.where((s) => s == SecureApplicationAuthenticationStatus.FAILED)
.listen((_) {
// 清除缓存的用户数据
userDataCache.clear();
// 导航到登录页
Navigator.of(context).pushReplacementNamed('/login');
});
五、SecureApplicationState 不可变状态设计
5.1 不可变状态类
class SecureApplicationState {
final bool locked;
final bool secured;
final bool paused;
final bool authenticated;
SecureApplicationState({
this.locked = false,
this.secured = false,
this.paused = false,
this.authenticated = false,
});
SecureApplicationState copyWith({
bool? locked,
bool? secured,
bool? paused,
bool? authenticated,
}) {
return SecureApplicationState(
locked: locked ?? this.locked,
secured: secured ?? this.secured,
paused: paused ?? this.paused,
authenticated: authenticated ?? this.authenticated,
);
}
}
5.2 为什么用不可变状态
- 线程安全:不可变对象天然线程安全
- 变更追踪:每次状态变更都产生新对象,方便调试
- 防止意外修改:不能直接修改字段,必须通过 copyWith
5.3 copyWith 模式
// 只修改 locked,其他保持不变
value = value.copyWith(locked: true);
// 同时修改多个字段
value = value.copyWith(locked: false, authenticated: true);
📌 设计启示:这种不可变状态 + copyWith 的模式在 Flutter 中非常常见(如 ThemeData、TextStyle),值得在自己的项目中借鉴。
六、架构设计对 OpenHarmony 适配的影响
6.1 适配工作量评估
| 层级 | 需要修改 | 工作量 | 原因 |
|---|---|---|---|
| SecureApplication Widget | ❌ | 0 | 纯 Dart,跨平台通用 |
| SecureApplicationController | ❌ | 0 | 纯 Dart,跨平台通用 |
| SecureApplicationState | ❌ | 0 | 纯 Dart,跨平台通用 |
| SecureApplicationProvider | ❌ | 0 | 纯 Dart,跨平台通用 |
| SecureGate | ❌ | 0 | 纯 Flutter Widget |
| SecureApplicationNative | ❌ | 0 | MethodChannel 调用不变 |
| SecureApplicationPlugin.ets | ✅ 新建 | 中 | OpenHarmony 原生实现 |
| pubspec.yaml | ✅ 修改 | 低 | 添加 ohos 平台声明 |
| ohos/ 目录 | ✅ 新建 | 低 | 工程配置文件 |
6.2 原生端需要实现的方法
// OpenHarmony 原生端需要响应的 MethodChannel 方法
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case "secure": // 开启保护 → setWindowPrivacyMode(true)
case "open": // 关闭保护 → setWindowPrivacyMode(false)
case "lock": // 锁定(原生端可以空实现)
case "unlock": // 解锁(原生端可以空实现)
case "opacity": // 设置透明度(原生端可以空实现)
}
}
6.3 原生端需要主动通知的事件
// 需要主动通知 Dart 层的事件
this.channel.invokeMethod("lock", null); // 窗口失焦或进入后台时
这就是全部了。相比 flutter_speech 需要处理引擎创建、监听器回调、音频参数等复杂逻辑,secure_application 的原生端实现简洁得多。
6.4 架构优势总结
- Dart 层零改动:所有业务逻辑在 Dart 层,跨平台通用
- 原生端职责单一:只做窗口控制和事件监听
- 测试友好:Dart 层可以用 Mock 测试,不依赖真机
- 维护成本低:原生端代码量少,后续维护简单
总结
本文深入分析了 secure_application 的架构设计哲学:
- Widget 驱动模式:声明式 API,状态自动管理
- Dart 层重、Native 层轻:核心逻辑在 Dart 端,原生端只做平台对接
- ValueNotifier + InheritedWidget:轻量级状态管理,不引入额外依赖
- BehaviorSubject 事件流:响应式事件分发,新订阅者立即收到最新值
- 不可变状态:copyWith 模式保证状态变更的安全性
下一篇我们逐行解析 Dart 层的核心源码——从 SecureApplication Widget 到 SecureApplicationNative。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- secure_application 源码
- Flutter ValueNotifier 文档
- Flutter InheritedWidget 文档
- rxdart BehaviorSubject
- Flutter BackdropFilter
- Flutter Plugin 开发指南
- WidgetsBindingObserver
- 开源鸿蒙跨平台社区

secure_application 未锁定状态下的正常内容显示
更多推荐

所有评论(0)