[webview_flutter] Add gesture blocking policy to WebKitWebViewWidgetCreationParams - #12496
[webview_flutter] Add gesture blocking policy to WebKitWebViewWidgetCreationParams#12496burakJs wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request registers the iOS platform view with the hit-test based gesture blocking policy (FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture) to prevent web views from becoming unresponsive to touches. It also adds a corresponding unit test and bumps the package version to 3.26.1. Feedback suggests using the more idiomatic Swift enum case .doNotBlockGesture instead of the verbose Objective-C name in both the plugin registration and the test file.
| registrar.register( | ||
| viewFactory, withId: "plugins.flutter.io/webview", | ||
| gestureRecognizersBlockingPolicy: | ||
| FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture) |
There was a problem hiding this comment.
In Swift, Objective-C enums are imported with shortened, idiomatic names. You can use .doNotBlockGesture instead of the verbose FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture to make the code cleaner and more idiomatic.
registrar.register(
viewFactory, withId: "plugins.flutter.io/webview",
gestureRecognizersBlockingPolicy: .doNotBlockGesture)There was a problem hiding this comment.
.doNotBlockGesture does not compile here. The policy is declared in FlutterPlugin.h as a plain C enum:
typedef enum {
FlutterPlatformViewGestureRecognizersBlockingPolicyEager,
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded,
FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture,
} FlutterPlatformViewGestureRecognizersBlockingPolicy;Because it is not declared with NS_ENUM, the Swift importer does not shorten the case names. Building an app against Flutter 3.47.0 with the shortened form fails with:
Swift Compiler Error: Type 'FlutterPlatformViewGestureRecognizersBlockingPolicy' has no member 'doNotBlockGesture'
So the fully qualified constant is intentional. Happy to switch if the enum is ever annotated for Swift.
There was a problem hiding this comment.
We should pass in the policy from the dart side instead: https://github.com/flutter/flutter/blob/f6061d0003a7a9e0cb30a45379c4c4bec0412c40/packages/flutter/lib/src/services/platform_views.dart#L1630
I'm glad that the new doNotBlockGesture policy works for you. However, this policy is designed as the last resort to deal with bugs of the platform view itself (e.g. WKWebView).
So it would be great if you can provide a reproducible project so we can look further.
There was a problem hiding this comment.
Thanks for the review, and understood on doNotBlockGesture being a last resort rather than a default.
I'm still actively on this and will follow up on both points:
- Reproducible project — I'll put together a minimal app that shows the web view going unresponsive after the first interaction on iOS 26 and link it here, so the underlying platform-view/WebKit behaviour can be investigated properly instead of just being worked around at the registration site.
- Passing the policy from the Dart side — that makes sense; hardcoding it in
WebViewFlutterPlugintakes the decision away from the app. I'll look into plumbing it through the plugin's Dart layer so it's opt-in per web view, and rework this PR in that shape if you'd prefer that over the unconditional change.
I'd rather land the right fix than the convenient one, so I'll hold this PR until the repro is up. Please leave it open in the meantime — I'll ping you here once both are ready.
There was a problem hiding this comment.
Done — the policy now comes from the Dart side and the plugin registration is back to what it was on main.
WebKitWebViewWidgetCreationParams.gestureBlockingPolicy is forwarded to UiKitView.gestureBlockingPolicy, defaulting to fallbackToPluginDefault. So nothing changes for existing apps, and doNotBlockGesture stays an explicit opt-in rather than a new default — which matches your point about it being a last resort.
One consequence worth flagging: UiKitView.gestureBlockingPolicy first shipped in stable 3.47.0, so the package's minimum Flutter had to move to >=3.47.0 (and Dart to ^3.13.0 for consistency, making this 3.27.0). That also needed a getDartSdkForFlutterSdk entry for 3.47.0 in script/tool, and it changes dart format output for some already-checked-in files — that reformat is isolated in the second commit so the API change stays readable.
Still working on the repro project; I'll link it here rather than hold the code change for it. One data point while I put it together: flutter_inappwebview also registers its iOS platform view through the two-argument registrar.register(_:withId:), i.e. eager, and shows the same symptom on iOS 26 in the same app. Two independent plugins with the same default and the same failure suggests this is not webview_flutter-specific, which may help narrow down where the arena state is getting stranded.
There was a problem hiding this comment.
Two independent plugins with the same default and the same failure suggests this is not webview_flutter-specific, which may help narrow down where the arena state is getting stranded.
This is likely a bug in WKWebView, which is used by both this package & flutter_inappwebview, so it happens on both.
There was a problem hiding this comment.
That's fair — I was reading the shared eager default as the common factor, but WKWebView itself is just as good an explanation for the same data, and I don't have anything that distinguishes the two yet. So I've taken the causal wording out of the README and the doc comment; I'll leave the cause open until there's a repro that actually shows one.
Still putting the minimal project together and I'll link it here.
(Also force-pushed the branch: the commits carried a co-author trailer that was failing the CLA check. Only the commit messages and the two doc changes above differ from what you reviewed.)
| #expect( | ||
| registrar.registeredGestureRecognizersBlockingPolicy | ||
| == FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture) |
There was a problem hiding this comment.
Same reason as the other comment: the enum is declared as a plain C typedef enum rather than NS_ENUM, so the Swift importer keeps the full constant names and .doNotBlockGesture fails to compile.
| registrar.register( | ||
| viewFactory, withId: "plugins.flutter.io/webview", | ||
| gestureRecognizersBlockingPolicy: | ||
| FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture) |
There was a problem hiding this comment.
We should pass in the policy from the dart side instead: https://github.com/flutter/flutter/blob/f6061d0003a7a9e0cb30a45379c4c4bec0412c40/packages/flutter/lib/src/services/platform_views.dart#L1630
I'm glad that the new doNotBlockGesture policy works for you. However, this policy is designed as the last resort to deal with bugs of the platform view itself (e.g. WKWebView).
So it would be great if you can provide a reproducible project so we can look further.
e28f33a to
0d92961
Compare
|
|
||
| By default the plugin lets the engine block the web view's gesture recognizers through Flutter's | ||
| gesture arena. If a web view stops responding to touches after the first interaction, the arena | ||
| state has been stranded (see [flutter/flutter#175099][3]). Deriving the blocking decision from hit |
There was a problem hiding this comment.
I would avoid this description, since we don't know what's happening yet.
There was a problem hiding this comment.
Thanks — done. The README no longer claims the arena state is stranded; it just describes the symptom and what the policy does instead:
By default the plugin lets the engine block the web view's gesture recognizers through Flutter's gesture arena. If a web view stops responding to touches after the first interaction, deriving the blocking decision from hit testing instead can work around it:
The flutter/flutter#175099 link reference is removed along with it.
| /// * https://github.com/flutter/flutter/issues/175099, which tracks the | ||
| /// stranded gesture recognizer state. | ||
| /// * https://github.com/flutter/flutter/issues/179907, which describes why | ||
| /// the engine no longer recovers from it on iOS 26 and above. |
There was a problem hiding this comment.
I'd delete these 2 since we are not 100% sure this is indeed the cause yet.
There was a problem hiding this comment.
Thanks — removed. Both bullets and the See also: block are gone, and so is the paragraph above them that made the same claim about stranded arena state. What's left only describes the behaviour and the trade-off:
/// Setting this to [UiKitViewGestureBlockingPolicy.doNotBlockGesture]
/// derives the blocking decision from hit testing instead of Flutter's
/// gesture arena, which can work around a web view that stops responding to
/// touches, at the cost of the web view potentially recognizing a gesture
/// that should have been blocked.…reationParams Exposes the iOS platform view gesture blocking policy through `WebKitWebViewWidgetCreationParams.gestureBlockingPolicy`, forwarding it to `UiKitView`, so apps can opt into `doNotBlockGesture` when a `WKWebView` stops responding to touches. The default is `fallbackToPluginDefault`, so behaviour is unchanged unless an app opts in. `UiKitView.gestureBlockingPolicy` first shipped in Flutter 3.47.0, so the minimum supported Flutter version is bumped accordingly, along with the tool's Flutter-to-Dart SDK version map.
Mechanical `dart format` output only. Raising the package's minimum Dart SDK to 3.13.0 raises its language version, which changes the formatter's output for these already-checked-in files.
0d92961 to
ba04a2a
Compare
Reworked per review feedback: the policy is now passed from the Dart side instead of being hardcoded in the plugin registration.
Adds
WebKitWebViewWidgetCreationParams.gestureBlockingPolicy, forwarded toUiKitView.gestureBlockingPolicy. It defaults toUiKitViewGestureBlockingPolicy.fallbackToPluginDefault, so behaviour is unchanged unless an app opts in —doNotBlockGesturestays a last resort the app chooses, not a new default.The previous revision of this PR registered the platform view with
doNotBlockGestureunconditionally; that change is fully reverted here, soWebViewFlutterPlugin.swiftis untouched.Why the minimum Flutter version is bumped
UiKitView.gestureBlockingPolicylanded in flutter/flutter#185126 and first shipped in stable 3.47.0 (it is not present in 3.44.x), soflutter: ">=3.47.0"is required to reference it at all.validateenforces a matching Dart lower bound, hencesdk: ^3.13.0, and that made this a minor version bump (3.27.0) rather than a patch.Two follow-on consequences, both mechanical:
script/tool'sgetDartSdkForFlutterSdkmap had no entry for Flutter 3.47.0, sovalidatefailed until one was added.dart formatoutput for files that were already checked in. That reformat is isolated in the second commit (Reformat for the Dart 3.13 language version) so the API change stays readable in the first.Repro
Still owed, and I'm working on it — a standalone minimal project rather than the closed-source app this surfaced in. I'll link it in the review thread. One data point in the meantime:
flutter_inappwebviewalso registers its iOS platform view via the two-argumentregistrar.register(_:withId:)(so,eager), and shows the same symptom on iOS 26 in the same app — which suggests the underlying issue is not specific towebview_flutter.Verified locally with Flutter 3.47.0:
validate,federation-safety-check,flutter analyze(package + example) andflutter test(157 tests) all pass.Related: flutter/flutter#175099, flutter/flutter#179907
Fixes flutter/flutter#191267
Pre-Review Checklist
[shared_preferences]///).