前言

欢迎加入开源鸿蒙跨平台社区: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 中被调用,传入的两个回调分别是:

  • locksecureApplicationController.lockIfSecured
  • unlocksecureApplicationController.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 文件:

  1. SecureApplicationState:31行,不可变状态类,四个 bool 字段
  2. SecureApplicationNative:48行,MethodChannel 封装,5个方法 + 2个事件
  3. SecureApplicationController:170行,状态控制器,ValueNotifier + BehaviorSubject
  4. SecureApplicationProvider:InheritedWidget,上下文传递
  5. SecureApplication:168行,主控 Widget,生命周期管理

下一篇我们分析 SecureGate 的模糊遮罩实现——BackdropFilter 和 AnimationController 的配合。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

请添加图片描述

SecureGate 锁定状态效果

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐