前言

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

flutter_web_auth 的 OpenHarmony 实现需要同时实现 三个接口:FlutterPlugin、MethodCallHandler、AbilityAware。这比 secure_application(只需要两个接口)多了一个 AbilityAware。为什么?因为打开浏览器需要 UIAbilityContext,而不是普通的 ApplicationContext。

这篇把三个接口的职责和实现细节都讲清楚。

一、三接口组合的设计意图

1.1 类声明

export default class FlutterWebAuthPlugin implements FlutterPlugin, MethodCallHandler, AbilityAware {
  private channel: MethodChannel | null = null;
  private ability: UIAbility | null = null;
  private static callbacks: Map<string, MethodResult> = new Map();
  // ...
}

1.2 三个接口的职责

请添加图片描述

1.3 为什么需要 AbilityAware

// 打开浏览器需要 UIAbilityContext
context.openLink(url);  // context 来自 UIAbility

// 普通的 ApplicationContext 不能调用 openLink
// binding.getApplicationContext().openLink(url);  // ❌ 没有这个方法
API 需要的 Context 类型 来源
openLink UIAbilityContext AbilityAware → UIAbility.context
startAbility UIAbilityContext AbilityAware → UIAbility.context
getLastWindow ApplicationContext FlutterPluginBinding

💡 这就是 flutter_web_auth 和 secure_application 的核心架构差异。secure_application 只需要 ApplicationContext 来获取窗口,所以不需要 AbilityAware。flutter_web_auth 需要 UIAbilityContext 来打开浏览器,所以必须实现 AbilityAware。

二、onAttachedToEngine:MethodChannel 创建

2.1 实现

onAttachedToEngine(binding: FlutterPluginBinding): void {
  this.channel = new MethodChannel(binding.getBinaryMessenger(), "flutter_web_auth");
  this.channel.setMethodCallHandler(this);
  console.info(TAG, 'onAttachedToEngine called');
}

2.2 执行时机

Flutter 引擎启动
    ↓
框架扫描已注册的插件
    ↓
调用 onAttachedToEngine(binding)
    ↓
创建 MethodChannel + 注册 Handler

2.3 通道名称

new MethodChannel(binding.getBinaryMessenger(), "flutter_web_auth");
通道名称 必须一致
Dart MethodChannel('flutter_web_auth')
OpenHarmony new MethodChannel(messenger, "flutter_web_auth")

2.4 与 flutter_speech 的对比

// flutter_web_auth
new MethodChannel(binding.getBinaryMessenger(), "flutter_web_auth");

// flutter_speech
new MethodChannel(binding.getBinaryMessenger(), "speech_recognition");

// secure_application
new MethodChannel(binding.getBinaryMessenger(), "secure_application");

每个插件的通道名称都不同,确保消息不会串。

三、onAttachedToAbility:UIAbility 引用获取

3.1 实现

onAttachedToAbility(binding: AbilityPluginBinding): void {
  this.ability = binding.getAbility();
  console.info(TAG, 'onAttachedToAbility called, ability is set');
}

3.2 AbilityPluginBinding 提供的能力

interface AbilityPluginBinding {
  getAbility(): UIAbility;  // 获取 UIAbility 引用
}

3.3 调用时序

onAttachedToEngine(binding)     ← 先调用
    ↓
onAttachedToAbility(binding)    ← 后调用

两个方法的调用顺序是固定的:先 Engine,后 Ability。这意味着在 onAttachedToEngine 中 this.ability 还是 null。

3.4 时序问题

时间线:
t0: onAttachedToEngine → channel 创建 ✅, ability = null
t1: onAttachedToAbility → ability 设置 ✅
t2: 用户调用 authenticate → 需要 ability.context

如果用户在 t0 和 t1 之间调用 authenticate,ability 还是 null,会触发 NO_CONTEXT 错误。实际上这种情况几乎不会发生,因为 t0 和 t1 之间的间隔极短。

四、onDetachedFromEngine / onDetachedFromAbility

4.1 onDetachedFromEngine

onDetachedFromEngine(_binding: FlutterPluginBinding): void {
  if (this.channel != null) {
    this.channel.setMethodCallHandler(null);
  }
}

4.2 onDetachedFromAbility

onDetachedFromAbility(): void {
  this.ability = null;
  console.info(TAG, 'onDetachedFromAbility called');
}

4.3 清理顺序

onDetachedFromAbility()     ← 先调用
    ↓
onDetachedFromEngine()      ← 后调用

与 attach 相反:先 detach Ability,后 detach Engine。

4.4 清理职责划分

方法 清理内容
onDetachedFromAbility 置空 ability 引用
onDetachedFromEngine 注销 MethodCallHandler

4.5 为什么不清理 static callbacks

// 注意:没有清理 static callbacks
onDetachedFromEngine(_binding: FlutterPluginBinding): void {
  if (this.channel != null) {
    this.channel.setMethodCallHandler(null);
  }
  // 没有 FlutterWebAuthPlugin.callbacks.clear()
}

因为 callbacks 是 static 的,它的生命周期不绑定到插件实例。Dart 层的 _cleanUpDanglingCalls 会负责清理。

五、与 secure_application 的架构差异对比

5.1 接口对比

维度 flutter_web_auth secure_application
FlutterPlugin
MethodCallHandler
AbilityAware
接口总数 3 2

5.2 Context 获取方式对比

// flutter_web_auth:通过 AbilityAware 获取 UIAbilityContext
onAttachedToAbility(binding: AbilityPluginBinding): void {
  this.ability = binding.getAbility();
  // this.ability.context → UIAbilityContext
}

// secure_application:通过 FlutterPluginBinding 获取 ApplicationContext
onAttachedToEngine(binding: FlutterPluginBinding): void {
  this.context = binding.getApplicationContext();
  // this.context → ApplicationContext
}

5.3 为什么不同

插件 需要的操作 需要的 Context 获取方式
flutter_web_auth openLink 打开浏览器 UIAbilityContext AbilityAware
secure_application getLastWindow 获取窗口 ApplicationContext FlutterPluginBinding
flutter_speech 创建语音识别引擎 UIAbilityContext AbilityAware

5.4 经验法则

📌 如果你的插件需要与 UI 交互(打开页面、弹窗、启动其他应用),就需要 AbilityAware。如果只需要后台操作(窗口属性、文件读写),ApplicationContext 就够了。

六、成员变量分析

6.1 实例变量

private channel: MethodChannel | null = null;
private ability: UIAbility | null = null;
变量 类型 初始值 设置时机 清理时机
channel MethodChannel null onAttachedToEngine onDetachedFromEngine
ability UIAbility null onAttachedToAbility onDetachedFromAbility

6.2 静态变量

private static callbacks: Map<string, MethodResult> = new Map();
变量 类型 生命周期 清理方式
callbacks Map<string, MethodResult> 应用进程 cleanUpDanglingCalls / onNewWant

6.3 为什么 callbacks 是 static

场景:
1. FlutterWebAuthPlugin 实例 A 调用 authenticate → 存入 callbacks
2. 浏览器打开,用户认证
3. 系统通过 onNewWant 回调 → 需要从 callbacks 中取出 result
4. onNewWant 是 static 方法 → 只能访问 static 变量

如果 callbacks 不是 static,onNewWant(static 方法)就无法访问它。

七、getUniqueClassName 方法

7.1 实现

getUniqueClassName(): string {
  return "FlutterWebAuthPlugin"
}

7.2 作用

Flutter-OHOS 框架用这个方法来唯一标识插件,防止重复注册。

7.3 命名规范

插件 getUniqueClassName
flutter_web_auth “FlutterWebAuthPlugin”
secure_application “SecureApplicationPlugin”
flutter_speech “FlutterSpeechRecognitionPlugin”

返回值通常与类名相同。

八、构造函数

8.1 实现

constructor() {
}

空构造函数。Flutter-OHOS 框架通过反射创建插件实例,所以构造函数不能有参数。

8.2 初始化时机

操作 时机
创建实例 框架反射调用 constructor()
设置 channel onAttachedToEngine
设置 ability onAttachedToAbility
可以处理方法调用 onAttachedToAbility 之后

总结

本文详细分析了 flutter_web_auth 的三接口实现:

  1. FlutterPlugin:管理 MethodChannel 的创建和销毁
  2. MethodCallHandler:处理 Dart 层的方法调用
  3. AbilityAware:获取 UIAbility 引用,用于 openLink
  4. static callbacks:跨实例共享认证回调
  5. 与 secure_application 的差异:需要 UIAbilityContext vs ApplicationContext

下一篇我们讲深度链接机制——OpenHarmony 的 Want 和 skills 配置。

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


相关资源:

请添加图片描述

Flutter 插件平台通道架构

Logo

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

更多推荐