前段时间 #175099 又提出了一个 iOS 18 的问题,大概就是 webview_flutter 的点击事件又出现了'点不动'或'点了不触发'的情况,源头还是 WKWebView(WebKit)内部的手势识别器与 Flutter 在 Engine 里用于'阻止/延迟'手势的 recognizer 之间的冲突。
针对这个问题,去年 iOS 18.2 beta 里有出现类似情况,而那时候在 Engine 里,可以通过 #56804 这个 PR,临时移除并再添加 delayingRecognizer 的实现来暂时绕过问题,主要是通过刷新 WebKit 的内部状态从而临时修复,但这个绕过在 iOS 18 上造成了另一个严重回归(overlay 的手势阻止失效、触摸穿透底下的 WebView),因此在最近被针对 iOS 18 的条件下回退(revert)了该提交。

另外也是因为 Flutter 团队发现这是 Apple / WebKit 的 bug,所以也已经同步上报请求和 Apple 协作。
问题最开始出现在 iOS 18.2 beta 版本上,当页面上先触发了某些 Flutter widget(或者 overlay,比如 context menu / Drawer)后,WKWebView 内的点击(链接、按钮)不再响应(可高亮,但不会激活),需要重新加载 WebView 才恢复。
而具体原因在于,Flutter 在 iOS 的 PlatformView(例如承载 WKWebView 的视图)上实现了一套'手势拦截/延迟'机制:在需要时会把一个 FlutterDelayingGestureRecognizer(delayingRecognizer)切到某些状态(possible, ended, failed 等)来告诉 UIKit 或者其他 recognizers 是否应该阻止/允许手势传递。
而 UIKit 的手势识别器有自己的状态机(possible → recognized/failed / ended),不同 recognizer 相互之间会有阻塞/依赖关系:

这里需要简单介绍一个背景知识:Flutter + iOS 平台视图的手势处理机制,在 iOS 上当你把一个原生控件(比如 WKWebView)嵌进 Flutter 时,实际上会经历以下层级:
[FlutterView] ← 整个 Flutter 渲染层(Dart UI 层)
├─ Flutter widgets
│ ↑
│ │
│ 手势事件由 Flutter framework(Dart)处理
│ └─ PlatformView (e.g. WKWebView)
│ ↑
│ 手势事件由 UIKit / WebKit 内部 recognizer 处理
Flutter 和 UIKit 都各自有手势识别系统(GestureRecognizer),为了防止互相抢事件,Flutter engine 在 iOS 上加入了一个'delaying gesture recognizer'(延迟识别器):





