前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

MethodChannel 是 Dart 层和原生层之间的桥梁。secure_application 的通信协议比 flutter_speech 简单得多——只有5个 Dart→Native 方法和2个 Native→Dart 事件。但简单不代表可以随意设计,通道名称、参数格式、返回值约定都需要严格一致。

今天把完整的通信协议梳理清楚。

一、通道注册与名称约定

1.1 通道名称

// Native 端
new MethodChannel(binding.getBinaryMessenger(), "secure_application");
// Dart 端
static const MethodChannel _channel = const MethodChannel('secure_application');

通道名称 "secure_application" 在两端必须完全一致,包括大小写和空格。

1.2 与 flutter_speech 的对比

插件 通道名称 命名风格
flutter_speech com.flutter.speech_recognition Java 包名风格
secure_application secure_application 简单下划线风格

两种命名风格都可以,没有强制规范。但建议保持项目内一致。

1.3 通道的生命周期

onAttachedToEngine
    │
    ├── new MethodChannel(...)        ← 创建通道
    ├── channel.setMethodCallHandler(this)  ← 注册处理器
    │
    │ ... 通道活跃,可以双向通信 ...
    │
onDetachedFromEngine
    │
    ├── channel.setMethodCallHandler(null)  ← 移除处理器
    └── channel = null                      ← 释放通道

二、Dart → Native 方法调用

2.1 五个方法总览

方法名 参数 返回值 触发时机
secure 无(或 opacity) true 用户调用 controller.secure()
open true 用户调用 controller.open()
lock true controller.lock()
unlock true controller.unlock()
opacity {“opacity”: double} true SecureGate 初始化或 opacity 变化

2.2 Dart 端调用代码

class SecureApplicationNative {
  static const MethodChannel _channel = const MethodChannel('secure_application');

  static Future secure() => _channel.invokeMethod('secure');
  static Future open() => _channel.invokeMethod('open');
  static Future lock() => _channel.invokeMethod('lock');
  static Future unlock() => _channel.invokeMethod('unlock');
  static Future opacity(double opacity) =>
      _channel.invokeMethod('opacity', {"opacity": opacity});
}

2.3 参数传递

只有 opacity 方法带参数:

// Dart 端发送
_channel.invokeMethod('opacity', {"opacity": 0.6});
// Native 端接收
case "opacity":
  const newOpacity: number = call.argument("opacity");
  if (newOpacity != null && newOpacity != undefined) {
    this.opacity = newOpacity;
  }
  result.success(true);
  break;
字段 类型 范围 说明
opacity double/number 0.0 ~ 1.0 遮罩透明度

2.4 secure 方法的可选参数

case "secure":
  this.secured = true;
  try {
    const secureOpacity: number = call.argument("opacity");
    if (secureOpacity != null && secureOpacity != undefined) {
      this.opacity = secureOpacity;
    }
  } catch (e) {
    // No opacity argument passed, use default
  }
  this.setPrivacyMode(true);
  result.success(true);
  break;

secure 方法可以可选地携带 opacity 参数。当前 Dart 层没有传这个参数,但原生端做了兼容处理。

三、Native → Dart 事件回调

3.1 两个事件

事件名 参数 触发时机
lock null 窗口失焦或应用进入后台
unlock null (当前未使用)

3.2 Native 端发送

// 窗口失焦时
this.channel.invokeMethod("lock", null);

// 应用进入后台时
this.channel.invokeMethod("lock", null);

3.3 Dart 端接收

static Future<dynamic> secureApplicationHandler(
    MethodCall methodCall, lock, unlock) async {
  switch (methodCall.method) {
    case 'lock':
      lock();   // 调用 controller.lockIfSecured()
      break;
    case 'unlock':
      unlock(); // 调用 controller.unlock()
      break;
    default:
      throw MissingPluginException('notImplemented');
  }
}

3.4 与 flutter_speech 的对比

维度 flutter_speech secure_application
Native→Dart 事件数 5个 2个
事件携带数据 有(识别文本等) 无(null)
事件频率 高(实时识别结果) 低(只在切换时)
复杂度

💡 secure_application 的 Native→Dart 通信非常简单——只需要告诉 Dart 层"该锁了"或"该解锁了",不需要传递任何数据。

四、通信时序图

4.1 开启保护

  Dart                    Native                  系统
   │                        │                      │
   │──secure()─────────────►│                      │
   │                        │──setPrivacyMode(true)─►│
   │                        │◄──────Promise.resolve──│
   │◄──result.success(true)─│                      │

4.2 用户切后台

  用户     系统      Native           Dart          SecureGate
   │        │         │                │               │
   │─Home──►│         │                │               │
   │        │─INACTIVE►│               │               │
   │        │         │──lock──────────►│              │
   │        │         │                │──lockIfSecured►│
   │        │─BG─────►│               │               │──显示遮罩
   │        │         │──lock──────────►│              │
   │        │         │                │──(防重入跳过)  │

4.3 用户切回前台

  用户     系统      Native           Dart          SecureGate
   │        │         │                │               │
   │─切回──►│         │                │               │
   │        │─FG─────►│               │               │
   │        │         │──(不操作)      │               │
   │        │         │                │               │
   │        │         │      Flutter: resumed          │
   │        │         │                │──onNeedUnlock  │
   │        │         │                │   (认证流程)   │
   │        │         │                │──authSuccess   │
   │        │         │                │──unlock───────►│
   │        │         │◄──unlock───────│               │──隐藏遮罩

4.4 关闭保护

  Dart                    Native                  系统
   │                        │                      │
   │──open()───────────────►│                      │
   │                        │──setPrivacyMode(false)►│
   │                        │◄──────Promise.resolve──│
   │◄──result.success(true)─│                      │

五、返回值约定

5.1 所有方法都返回 true

case "secure":
  // ... 逻辑 ...
  result.success(true);
  break;

case "open":
  // ... 逻辑 ...
  result.success(true);
  break;

// 甚至 default 也返回 true
default:
  result.success(true);
  break;

5.2 为什么不返回操作结果

方案 优点 缺点
始终返回 true 简单,Dart 层不需要处理失败 无法知道操作是否真正成功
返回实际结果 精确,可以做降级处理 Dart 层需要额外的错误处理逻辑

secure_application 选择了始终返回 true,因为:

  1. 隐私模式设置是异步的,result.success 时可能还没完成
  2. 即使原生端失败,Dart 层的模糊遮罩仍然有效
  3. 简化了 Dart 层的代码

5.3 default 分支的处理

// secure_application:default 返回 true
default:
  result.success(true);
  break;

// flutter_speech:default 返回 notImplemented
default:
  result.notImplemented();
  break;
处理方式 效果 适用场景
result.success(true) Dart 层不会报错 容错优先
result.notImplemented() Dart 层抛出 MissingPluginException 严格模式

📌 secure_application 的 default 返回 true 是一种容错设计——即使 Dart 层发送了未知方法,也不会导致异常。但这也意味着拼写错误不容易被发现。

六、opacity 参数的跨层传递

6.1 完整链路

SecureGate.initState()
    │
    ▼
SecureApplicationNative.opacity(0.6)
    │
    ▼
_channel.invokeMethod('opacity', {"opacity": 0.6})
    │
    ▼ MethodChannel
    │
onMethodCall(call, result)
    │ case "opacity"
    ▼
call.argument("opacity")  →  0.6
    │
    ▼
this.opacity = 0.6

6.2 类型安全

const newOpacity: number = call.argument("opacity");

call.argument("opacity") 返回的是 Object 类型,需要转换为 number。如果 Dart 层传的不是数字,这里可能得到 null 或异常。

6.3 防御性编程

try {
  const newOpacity: number = call.argument("opacity");
  if (newOpacity != null && newOpacity != undefined) {
    this.opacity = newOpacity;
  }
} catch (e) {
  Log.e(TAG, "Failed to parse opacity argument");
}

三层防御:

  1. try-catch 捕获类型转换异常
  2. null 检查
  3. undefined 检查

七、通信协议的完整清单

7.1 Dart → Native

# 方法 参数 原生行为 返回值
1 secure 无/opacity setPrivacyMode(true) true
2 open setPrivacyMode(false) true
3 lock 空实现 true
4 unlock 空实现 true
5 opacity {“opacity”: double} 保存 opacity 值 true

7.2 Native → Dart

# 事件 参数 Dart 行为
1 lock null lockIfSecured()
2 unlock null unlock()

7.3 通道信息

属性
通道名称 “secure_application”
编码方式 StandardMethodCodec
通信方向 双向

总结

本文梳理了 secure_application 的完整 MethodChannel 通信协议:

  1. 5个 Dart→Native 方法:secure、open、lock、unlock、opacity
  2. 2个 Native→Dart 事件:lock、unlock
  3. 参数传递:只有 opacity 带参数,其他都无参数
  4. 返回值:所有方法统一返回 true
  5. 通信频率:低频通信,只在状态切换时触发

下一篇我们详细分析 onMethodCall 的方法分发实现——每个 case 分支的具体逻辑。

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


相关资源:

请添加图片描述

MethodChannel 双向通信示意图

Logo

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

更多推荐