Flutter三方库适配OpenHarmony【flutter_web_auth】— iOS/macOS 端 ASWebAuthenticationSession 实现分析
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.netiOS 和 macOS 的实现是三个原生平台中最"优雅"的——Apple 提供了这个专门为 OAuth 设计的 API,一个方法调用就搞定了浏览器打开和回调接收。不需要配置 Intent Filter,不需要手动处理深度链接。理解这个实现有助于我们看清 OpenHarmony 适配中哪些复
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
iOS 和 macOS 的实现是三个原生平台中最"优雅"的——Apple 提供了 ASWebAuthenticationSession 这个专门为 OAuth 设计的 API,一个方法调用就搞定了浏览器打开和回调接收。不需要配置 Intent Filter,不需要手动处理深度链接。理解这个实现有助于我们看清 OpenHarmony 适配中哪些复杂度是"平台强加的"。
一、ASWebAuthenticationSession 的演进
1.1 历史版本

1.2 ASWebAuthenticationSession 的优势
let session = ASWebAuthenticationSession(
url: authURL,
callbackURLScheme: scheme
) { callbackURL, error in
// 认证完成或取消
}
session.prefersEphemeralWebBrowserSession = preferEphemeral
session.presentationContextProvider = self
session.start()
一个 API 完成了 Android 需要 CallbackActivity + Intent Filter + Chrome Custom Tabs 三个组件才能做到的事情。
1.3 与其他平台的对比
| 维度 | iOS/macOS | Android | OpenHarmony |
|---|---|---|---|
| API 数量 | 1个 | 3个组件 | 2个方法 + 宿主集成 |
| 回调方式 | 闭包回调 | Activity 启动 | onNewWant 回调 |
| 配置负担 | 无 | AndroidManifest | module.json5 + EntryAbility |
| 取消处理 | 自动(error 参数) | 手动(dangling calls) | 手动(dangling calls) |
二、prefersEphemeralWebBrowserSession
2.1 什么是 Ephemeral Session
session.prefersEphemeralWebBrowserSession = true
| preferEphemeral | 行为 |
|---|---|
| false(默认) | 共享 Safari 的 Cookie 和登录状态 |
| true | 使用独立的浏览器会话,不共享 Cookie |
2.2 使用场景
| 场景 | 推荐值 | 原因 |
|---|---|---|
| 用户登录 | false | 利用已有的登录状态,减少输入 |
| 切换账号 | true | 不使用已有的登录状态 |
| 隐私敏感 | true | 不留浏览痕迹 |
2.3 各平台的 Ephemeral 支持
| 平台 | 支持 | 实现方式 |
|---|---|---|
| iOS/macOS | ✅ | prefersEphemeralWebBrowserSession |
| Android | ✅ | FLAG_ACTIVITY_NO_HISTORY |
| OpenHarmony | ❌ | openLink 不支持 |
| Web | ❌ | window.open 无法控制 |
📌 OpenHarmony 的 openLink API 目前不支持隐私浏览模式。如果需要这个功能,可能需要使用 Web 组件(ArkWeb)替代 openLink,但这会失去系统浏览器的 Cookie 共享优势。
三、presentationContextProvider 窗口锚定
3.1 iOS 实现
extension FlutterWebAuthPlugin: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return UIApplication.shared.keyWindow!
}
}
3.2 macOS 实现
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return NSApplication.shared.keyWindow!
}
3.3 窗口锚定的作用
| 有锚定 | 无锚定 |
|---|---|
| 认证弹窗出现在当前窗口上方 | 可能出现在错误的窗口 |
| 用户体验一致 | 多窗口时可能混乱 |
3.4 OpenHarmony 不需要窗口锚定
OpenHarmony 的 openLink 直接打开系统浏览器应用,不是在当前窗口上方弹出。所以不需要窗口锚定的概念。
四、iOS 与 macOS 实现差异
4.1 代码差异
// iOS
#if os(iOS)
import UIKit
typealias ASPresentationAnchor = UIWindow
#endif
// macOS
#if os(macOS)
import AppKit
typealias ASPresentationAnchor = NSWindow
#endif
4.2 差异对比
| 维度 | iOS | macOS |
|---|---|---|
| 窗口类型 | UIWindow | NSWindow |
| 获取方式 | UIApplication.shared.keyWindow | NSApplication.shared.keyWindow |
| 认证弹窗 | 底部弹出 Sheet | 居中弹出窗口 |
| 用户交互 | 触摸 | 鼠标/键盘 |
4.3 共享的逻辑
除了窗口类型不同,iOS 和 macOS 的核心逻辑完全相同:
- 创建 ASWebAuthenticationSession
- 设置 prefersEphemeralWebBrowserSession
- 设置 presentationContextProvider
- 调用 start()
- 在闭包中处理结果
五、取消处理的优雅性
5.1 iOS 的取消处理
let session = ASWebAuthenticationSession(...) { callbackURL, error in
if let error = error as? ASWebAuthenticationSessionError,
error.code == .canceledLogin {
result(FlutterError(code: "CANCELED", message: "User canceled", details: nil))
return
}
if let url = callbackURL {
result(url.absoluteString)
}
}
5.2 与 Android/OpenHarmony 的对比
| 平台 | 取消检测方式 | 时机 |
|---|---|---|
| iOS/macOS | ASWebAuthenticationSessionError.canceledLogin | 即时 |
| Android | App resumed + cleanUpDanglingCalls | 延迟(回到前台时) |
| OpenHarmony | App resumed + cleanUpDanglingCalls | 延迟(回到前台时) |
💡 iOS 的取消检测是即时的——用户点击"取消"按钮的瞬间就能收到回调。Android 和 OpenHarmony 需要等用户切回 App 才能检测到取消。这是 ASWebAuthenticationSession 的一个明显优势。
5.3 对 OpenHarmony 的启示
OpenHarmony 目前没有类似 ASWebAuthenticationSession 的统一 API。如果未来 HarmonyOS 提供了专门的 Web 认证 API,可以像 iOS 一样实现即时取消检测。
六、错误处理
6.1 iOS 端的错误类型
enum ASWebAuthenticationSessionError: Int {
case canceledLogin = 1
case presentationContextNotProvided = 2
case presentationContextInvalid = 3
}
| 错误 | 含义 | 处理 |
|---|---|---|
| canceledLogin | 用户取消 | 返回 CANCELED 错误 |
| presentationContextNotProvided | 没有设置窗口锚定 | 代码错误,不应发生 |
| presentationContextInvalid | 窗口锚定无效 | 窗口已销毁 |
6.2 映射到 Dart 层
try {
final result = await FlutterWebAuth.authenticate(...);
} on PlatformException catch (e) {
if (e.code == 'CANCELED') {
// 用户取消了认证
}
}
所有平台的取消错误都统一为 CANCELED 错误码,Dart 层不需要区分平台。
七、三平台实现总结
7.1 综合对比
| 维度 | iOS/macOS | Android | OpenHarmony |
|---|---|---|---|
| 浏览器方案 | ASWebAuthenticationSession | Chrome Custom Tabs | openLink + startAbility |
| 回调机制 | 闭包自动回调 | CallbackActivity | onNewWant |
| 取消检测 | 即时 | 延迟 | 延迟 |
| Ephemeral | ✅ | ✅ | ❌ |
| 配置负担 | 无 | AndroidManifest | module.json5 + EntryAbility |
| 代码复杂度 | 低 | 中 | 中高 |
7.2 OpenHarmony 适配的参考价值
| 从 iOS 学到的 | 从 Android 学到的 |
|---|---|
| 统一 API 的简洁性 | static callbacks 的设计 |
| 即时取消检测的理想 | dangling calls 清理机制 |
| 错误码统一 | Intent Filter → skills 映射 |
总结
本文分析了 iOS/macOS 端的 ASWebAuthenticationSession 实现:
- ASWebAuthenticationSession:一个 API 完成浏览器打开和回调接收
- prefersEphemeralWebBrowserSession:隐私浏览模式,OpenHarmony 暂不支持
- 即时取消检测:iOS 的优势,Android/OpenHarmony 需要延迟检测
- 窗口锚定:iOS/macOS 特有,OpenHarmony 不需要
- 错误码统一:所有平台的取消都映射为 CANCELED
下一篇我们正式进入 OpenHarmony 适配——从插件工程搭建开始。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐
所有评论(0)