Flutter三方库适配OpenHarmony【secure_application】— Dart 层核心源码逐行解析
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net上一篇我们从宏观层面分析了 secure_application 的架构设计。这篇我们把 Dart 层的每个核心文件都拆开来看,逐行理解它的实现。这些代码在 OpenHarmony 适配中完全不需要修改,但理解它们是理解原生端该做什么的前提。一共6个 Dart 文件,我们按依赖关系从底层往
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
上一篇我们从宏观层面分析了 secure_application 的架构设计。这篇我们把 Dart 层的每个核心文件都拆开来看,逐行理解它的实现。这些代码在 OpenHarmony 适配中完全不需要修改,但理解它们是理解原生端该做什么的前提。
一共6个 Dart 文件,我们按依赖关系从底层往上层讲。
一、SecureApplicationState — 状态数据类
1.1 完整源码
import 'package:flutter/foundation.dart';
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,
);
}
}
1.2 逐行分析
| 行 | 代码 | 说明 |
|---|---|---|
| 3 | @immutable |
标记为不可变类,IDE 会警告可变字段 |
| 5-8 | 四个 final bool |
四个状态字段,全部只读 |
| 10-15 | 构造函数 | 全部默认 false,即初始状态为"未保护、未锁定、未暂停、未认证" |
| 17-27 | copyWith |
创建新实例,未指定的字段保持原值 |
1.3 四个状态的含义
| 状态 | 默认值 | 含义 |
|---|---|---|
secured |
false | 保护开关。true 时切后台会触发锁定 |
locked |
false | 锁定状态。true 时 SecureGate 显示模糊遮罩 |
paused |
false | 暂停标志。true 时切后台不会触发锁定 |
authenticated |
false | 认证状态。记录最近一次认证结果 |
📌 这个类只有31行,但它是整个插件状态管理的基石。所有状态变更都通过
copyWith产生新实例,保证了不可变性。
二、SecureApplicationNative — MethodChannel 封装
2.1 完整源码
import 'dart:async';
import 'package:flutter/services.dart';
class SecureApplicationNative {
static const MethodChannel _channel = const MethodChannel('secure_application');
static void registerForEvents(VoidCallback lock, VoidCallback unlock) {
_channel.setMethodCallHandler(
(call) => secureApplicationHandler(call, lock, unlock));
}
static Future<dynamic> secureApplicationHandler(
MethodCall methodCall, lock, unlock) async {
switch (methodCall.method) {
case 'lock':
lock();
break;
case 'unlock':
unlock();
break;
default:
throw MissingPluginException('notImplemented');
}
}
static Future secure() {
return _channel.invokeMethod('secure');
}
static Future open() {
return _channel.invokeMethod('open');
}
static Future lock() {
return _channel.invokeMethod('lock');
}
static Future unlock() {
return _channel.invokeMethod('unlock');
}
static Future opacity(double opacity) {
return _channel.invokeMethod('opacity', {"opacity": opacity});
}
}
2.2 通信协议
这个类定义了 Dart 层与原生层的完整通信协议:
Dart → Native(5个方法):
| 方法 | 参数 | 作用 |
|---|---|---|
secure |
无 | 开启保护模式 |
open |
无 | 关闭保护模式 |
lock |
无 | 通知原生端锁定 |
unlock |
无 | 通知原生端解锁 |
opacity |
{"opacity": double} |
设置遮罩透明度 |
Native → Dart(2个事件):
| 事件 | 参数 | 作用 |
|---|---|---|
lock |
无 | 原生端通知 Dart 执行锁定 |
unlock |
无 | 原生端通知 Dart 执行解锁 |
2.3 registerForEvents 的关键作用
static void registerForEvents(VoidCallback lock, VoidCallback unlock) {
_channel.setMethodCallHandler(
(call) => secureApplicationHandler(call, lock, unlock));
}
这个方法在 SecureApplication.initState 中被调用,传入的两个回调分别是:
lock:secureApplicationController.lockIfSecuredunlock:secureApplicationController.unlock
这样当原生端调用 channel.invokeMethod("lock", null) 时,Dart 层就会执行锁定逻辑。
💡 设计亮点:通道名称
secure_application在 Dart 层和原生层必须完全一致。这是 MethodChannel 通信的基本约定。
三、SecureApplicationController — 状态控制器
3.1 核心结构
class SecureApplicationController extends ValueNotifier<SecureApplicationState> {
SecureApplicationController(SecureApplicationState value) : super(value);
// 两个事件流
final BehaviorSubject<SecureApplicationAuthenticationStatus> _authenticationEventsController = ...;
final BehaviorSubject<bool> _lockEventsController = ...;
// 状态访问器
bool get locked => value.locked;
bool get secured => value.secured;
bool get paused => value.paused;
bool get authenticated => value.authenticated;
}
3.2 认证相关方法
void authFailed({bool unlock = false}) {
value = value.copyWith(authenticated: false);
_authenticationEventsController.add(SecureApplicationAuthenticationStatus.FAILED);
if (unlock) this.unlock();
notifyListeners();
}
void authSuccess({bool unlock = false}) {
value = value.copyWith(authenticated: true);
_authenticationEventsController.add(SecureApplicationAuthenticationStatus.SUCCESS);
if (unlock) this.unlock();
notifyListeners();
}
void authLogout({bool unlock = false}) {
value = value.copyWith(authenticated: false);
_authenticationEventsController.add(SecureApplicationAuthenticationStatus.LOGOUT);
if (unlock) this.unlock();
notifyListeners();
}
三个方法结构一致:更新状态 → 发射事件 → 可选解锁 → 通知监听者。
3.3 锁定与解锁
void lock() {
SecureApplicationNative.lock(); // 通知原生端
if (!value.locked) {
value = value.copyWith(locked: true);
notifyListeners();
_lockEventsController.add(true); // 发射锁定事件
}
}
void unlock() {
SecureApplicationNative.unlock(); // 通知原生端
if (value.locked) {
value = value.copyWith(locked: false);
notifyListeners();
_lockEventsController.add(false); // 发射解锁事件
}
}
📌 防重入设计:
if (!value.locked)和if (value.locked)确保重复调用不会重复触发事件。
3.4 保护开关
void secure() {
SecureApplicationNative.secure(); // 通知原生端开启隐私模式
if (!value.secured) {
value = value.copyWith(secured: true);
notifyListeners();
}
}
void open() {
SecureApplicationNative.open(); // 通知原生端关闭隐私模式
if (value.secured) {
value = value.copyWith(secured: false);
notifyListeners();
}
}
3.5 暂停机制
void pause() {
SecureApplicationNative.lock(); // 暂停时也锁定原生端
if (!value.paused) {
value = value.copyWith(paused: true);
notifyListeners();
}
}
void unpause() {
if (value.paused) {
value = value.copyWith(paused: false);
notifyListeners();
}
}
pause 的典型场景:用户点击"选择图片"按钮,会跳转到系统相册。这时候不应该触发锁定,所以先 pause,选完图片回来再 unpause。
3.6 资源释放
void dispose() {
_authenticationEventsController.close();
_lockEventsController.close();
super.dispose();
}
关闭两个 BehaviorSubject,防止内存泄漏。
四、SecureApplicationProvider — 上下文传递
4.1 源码
class SecureApplicationProvider extends InheritedWidget {
final SecureApplicationController secureData;
const SecureApplicationProvider({
Key? key,
required this.secureData,
required Widget child,
}) : super(key: key, child: child);
static SecureApplicationController? of(BuildContext context, {bool listen = true}) {
if (listen) {
return context.dependOnInheritedWidgetOfExactType<SecureApplicationProvider>()?.secureData;
}
return context.findAncestorWidgetOfExactType<SecureApplicationProvider>()?.secureData;
}
bool updateShouldNotify(SecureApplicationProvider oldWidget) {
return secureData != oldWidget.secureData;
}
}
4.2 两种获取方式
| 方式 | listen = true |
listen = false |
|---|---|---|
| 方法 | dependOnInheritedWidgetOfExactType |
findAncestorWidgetOfExactType |
| 是否注册依赖 | ✅ | ❌ |
| Widget 是否重建 | 状态变化时重建 | 不重建 |
| 适用场景 | build 方法中 | initState 或回调中 |
// 在 build 中使用(会响应变化)
var controller = SecureApplicationProvider.of(context);
// 在 initState 中使用(不注册依赖)
var controller = SecureApplicationProvider.of(context, listen: false);
五、SecureApplication Widget — 主控 Widget
5.1 核心生命周期
class _SecureApplicationState extends State<SecureApplication> with WidgetsBindingObserver {
void initState() {
// 1. 订阅认证事件
_authStreamSubscription = secureApplicationController.authenticationEvents.listen((s) { ... });
// 2. 注册生命周期观察者
WidgetsBinding.instance.addObserver(this);
// 3. 注册原生事件回调
SecureApplicationNative.registerForEvents(
secureApplicationController.lockIfSecured,
secureApplicationController.unlock);
super.initState();
}
void dispose() {
_authStreamSubscription?.cancel();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
5.2 生命周期处理
void didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
// 用户回到 App
setState(() => _removeNativeOnNextFrame = true);
if (!secureApplicationController.paused) {
if (secureApplicationController.secured && secureApplicationController.value.locked) {
if (widget.onNeedUnlock != null) {
secureApplicationController.pause();
var authStatus = await widget.onNeedUnlock!(secureApplicationController);
if (authStatus != null) secureApplicationController.sendAuthenticationEvent(authStatus);
WidgetsBinding.instance.addPostFrameCallback((_) {
secureApplicationController.unpause();
});
}
}
secureApplicationController.resumed();
}
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
// 用户离开 App
if (!secureApplicationController.paused) {
if (secureApplicationController.secured) {
secureApplicationController.lock();
}
}
break;
}
}
这段代码是整个插件的核心逻辑,处理了用户离开和回到 App 时的完整流程。
5.3 build 方法
Widget build(BuildContext context) {
if (_removeNativeOnNextFrame && widget.autoUnlockNative) {
Future.delayed(Duration(milliseconds: widget.nativeRemoveDelay))
.then((_) => SecureApplicationNative.unlock());
_removeNativeOnNextFrame = false;
}
return SecureApplicationProvider(
secureData: secureApplicationController,
child: widget.child,
);
}
build 方法很简单:用 Provider 包裹子 Widget,并在适当时机移除原生端的保护。
💡
nativeRemoveDelay默认1000毫秒,是为了给 Flutter 渲染足够的时间。如果太快移除原生遮罩,用户可能会短暂看到未保护的内容。
六、文件间的依赖关系
6.1 依赖图
secure_application_state.dart ← 无依赖
↑
secure_application_native.dart ← 依赖 flutter/services.dart
↑
secure_application_controller.dart ← 依赖 State + Native + rxdart
↑
secure_application_provider.dart ← 依赖 Controller
↑
secure_application.dart ← 依赖 Controller + Provider + Native
↑
secure_gate.dart ← 依赖 Provider + Controller + Native
6.2 导出关系
// secure_application.dart 统一导出所有公开 API
export './secure_application.dart';
export './secure_gate.dart';
export './secure_application_provider.dart';
export './secure_application_state.dart';
export './secure_application_controller.dart';
用户只需要 import 'package:secure_application/secure_application.dart' 就能使用所有功能。
总结
本文逐行解析了 secure_application 的5个核心 Dart 文件:
- SecureApplicationState:31行,不可变状态类,四个 bool 字段
- SecureApplicationNative:48行,MethodChannel 封装,5个方法 + 2个事件
- SecureApplicationController:170行,状态控制器,ValueNotifier + BehaviorSubject
- SecureApplicationProvider:InheritedWidget,上下文传递
- SecureApplication:168行,主控 Widget,生命周期管理
下一篇我们分析 SecureGate 的模糊遮罩实现——BackdropFilter 和 AnimationController 的配合。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- secure_application 源码
- ValueNotifier 文档
- InheritedWidget 文档
- WidgetsBindingObserver 文档
- MethodChannel 文档
- rxdart pub.dev
- Dart immutable 设计模式
- 开源鸿蒙跨平台社区

SecureGate 锁定状态效果
更多推荐




所有评论(0)