前言

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

上一篇梳理了通信协议的全貌,这一篇把 onMethodCall 的每个 case 分支都拆开来看。secure_application 的方法分发逻辑不复杂,但每个分支背后的设计考量值得细说——特别是 lock/unlock 为什么是空实现,以及 opacity 的参数解析为什么要包三层防御。

一、onMethodCall 完整实现

1.1 源码

onMethodCall(call: MethodCall, result: MethodResult): void {
  switch (call.method) {
    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;

    case "open":
      this.secured = false;
      this.setPrivacyMode(false);
      result.success(true);
      break;

    case "opacity":
      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");
      }
      result.success(true);
      break;

    case "unlock":
      result.success(true);
      break;

    case "lock":
      result.success(true);
      break;

    default:
      result.success(true);
      break;
  }
}

1.2 方法分类

类别 方法 有原生操作
核心方法 secure, open ✅ 控制隐私模式
参数方法 opacity ✅ 保存参数值
空实现 lock, unlock ❌ 直接返回 true
兜底 default ❌ 直接返回 true

二、secure 方法:开启保护

2.1 执行流程

case "secure":
  this.secured = true;                    // 1. 设置标志位
  try {
    const secureOpacity: number = call.argument("opacity");
    if (secureOpacity != null && secureOpacity != undefined) {
      this.opacity = secureOpacity;       // 2. 可选:更新透明度
    }
  } catch (e) {}
  this.setPrivacyMode(true);              // 3. 开启隐私模式
  result.success(true);                   // 4. 返回成功
  break;

2.2 三个关键操作

步骤 操作 作用
1 this.secured = true 标记保护已开启,后续窗口事件和生命周期回调会检查这个标志
2 解析 opacity 可选参数,当前 Dart 层不传
3 setPrivacyMode(true) 调用系统 API 开启截屏防护

2.3 secured 标志的重要性

// 窗口事件回调中
if (this.secured && this.channel != null) {
  this.channel.invokeMethod("lock", null);
}

// 生命周期回调中
if (this.secured && this.channel != null) {
  this.channel.invokeMethod("lock", null);
}

this.secured 是所有事件回调的门控条件。如果不设置这个标志,即使用户没有调用 secure(),切后台也会触发锁定。

2.4 result.success 的时机

this.setPrivacyMode(true);  // 异步操作
result.success(true);        // 立即返回

setPrivacyMode 内部是异步的(setWindowPrivacyMode 返回 Promise),但 result.success 是立即调用的。这意味着 Dart 层收到 true 时,隐私模式可能还没真正生效。

📌 这是一个设计取舍:如果等 Promise resolve 后再返回,Dart 层会被阻塞。对于 secure_application 来说,快速返回比精确反馈更重要。

三、open 方法:关闭保护

3.1 执行流程

case "open":
  this.secured = false;
  this.setPrivacyMode(false);
  result.success(true);
  break;

3.2 与 secure 的对称性

操作 secure open
secured 标志 true false
隐私模式 开启 关闭
返回值 true true

open 是 secure 的逆操作,逻辑完全对称。

3.3 调用 open 后的效果

open() 调用后:
├── this.secured = false → 窗口事件和生命周期回调不再触发锁定
├── setPrivacyMode(false) → 系统允许截屏和录屏
└── Dart 层收到 true → controller.open() 完成

四、opacity 方法:参数更新

4.1 执行流程

case "opacity":
  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");
  }
  result.success(true);
  break;

4.2 三层防御

层级 防御 防止的问题
1 try-catch call.argument 抛出异常
2 != null 参数不存在
3 != undefined 参数类型不对

4.3 opacity 在原生端的用途

当前 OpenHarmony 端保存了 opacity 值但没有实际使用。这个值主要是为 iOS 端的原生模糊视图准备的。OpenHarmony 的模糊遮罩由 Flutter 层的 SecureGate 处理,不需要原生端参与。

// 保存了但没用到
private opacity: number = 0.2;

💡 保留这个逻辑是为了协议一致性——Dart 层不知道当前运行在哪个平台,它会向所有平台发送 opacity 参数。原生端接收并保存,即使不用也不报错。

五、lock / unlock:空实现的设计考量

5.1 代码

case "unlock":
  result.success(true);
  break;

case "lock":
  result.success(true);
  break;

5.2 为什么是空实现

Dart 层的 SecureApplicationNative.lock()SecureApplicationNative.unlock() 会调用这两个方法。但在 OpenHarmony 端,锁定和解锁的原生操作已经在其他地方处理了:

操作 在哪里处理 为什么不在 lock/unlock 中处理
开启隐私模式 secure 方法 隐私模式跟随 secure/open,不跟随 lock/unlock
窗口事件监听 registerWindowEventCallback 已经在 onAttachedToEngine 中注册
生命周期回调 registerLifecycleCallback 已经在 onAttachedToEngine 中注册

5.3 lock/unlock 在其他平台的作用

平台 lock 的原生行为 unlock 的原生行为
Android 空实现 空实现
iOS 添加模糊视图 移除模糊视图
OpenHarmony 空实现 空实现
Web 空实现 空实现

只有 iOS 在 lock/unlock 时有原生操作(添加/移除 UIVisualEffectView)。其他平台都是空实现。

5.4 为什么不直接返回 notImplemented

// 当前做法:返回 true
case "lock":
  result.success(true);
  break;

// 替代做法:返回 notImplemented
case "lock":
  result.notImplemented();
  break;

如果返回 notImplemented,Dart 层会抛出 MissingPluginException。虽然 Dart 层的调用代码没有 await 这个 Future,但异常仍然会出现在控制台中,造成不必要的噪音。

六、default 分支

6.1 代码

default:
  result.success(true);
  break;

6.2 容错 vs 严格

策略 default 行为 优点 缺点
容错 result.success(true) 不会因未知方法崩溃 拼写错误不易发现
严格 result.notImplemented() 拼写错误立即暴露 可能导致异常

secure_application 选择了容错策略。对于安全类插件来说,稳定性比严格性更重要——宁可某个方法静默失败,也不要让 App 因为一个未知方法而崩溃。

七、方法调用的完整生命周期

7.1 一次 secure() 调用的完整链路

1. 用户代码:controller.secure()
2. Controller:SecureApplicationNative.secure()
3. Native类:_channel.invokeMethod('secure')
4. MethodChannel:序列化 → 平台通道 → 反序列化
5. onMethodCall:case "secure"
6. 原生逻辑:this.secured = true; setPrivacyMode(true)
7. 系统API:win.setWindowPrivacyMode(true)
8. 返回:result.success(true)
9. MethodChannel:序列化 → 平台通道 → 反序列化
10. Dart Future:resolve(true)

7.2 耗时分析

步骤 耗时 说明
1-4 <1ms Dart 层调用 + 序列化
5-6 <1ms 方法分发 + 标志位设置
7 5-20ms 系统 API 异步调用
8-10 <1ms 返回 + 反序列化
总计 <25ms 用户无感知

📌 注意:result.success 在步骤7之前就返回了,所以 Dart 层感知到的延迟只有步骤1-6和8-10,大约2ms。系统 API 的20ms 延迟是在后台异步完成的。

总结

本文详细分析了 onMethodCall 的每个分支:

  1. secure:设置标志位 + 解析可选参数 + 开启隐私模式
  2. open:清除标志位 + 关闭隐私模式
  3. opacity:三层防御解析参数,保存但不使用
  4. lock/unlock:空实现,原生操作在其他地方处理
  5. default:容错返回 true,不抛异常

下一篇我们讲资源释放与回调注销——插件生命周期结束时的清理工作。

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


相关资源:

请添加图片描述

方法调用分发流程示意图

Logo

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

更多推荐