Skip to content

[webview_flutter] Add gesture blocking policy to WebKitWebViewWidgetCreationParams - #12496

Open
burakJs wants to merge 2 commits into
flutter:mainfrom
burakJs:webview-hittest-gesture-policy
Open

[webview_flutter] Add gesture blocking policy to WebKitWebViewWidgetCreationParams#12496
burakJs wants to merge 2 commits into
flutter:mainfrom
burakJs:webview-hittest-gesture-policy

Conversation

@burakJs

@burakJs burakJs commented Aug 18, 2026

Copy link
Copy Markdown

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 to UiKitView.gestureBlockingPolicy. It defaults to UiKitViewGestureBlockingPolicy.fallbackToPluginDefault, so behaviour is unchanged unless an app opts in — doNotBlockGesture stays a last resort the app chooses, not a new default.

The previous revision of this PR registered the platform view with doNotBlockGesture unconditionally; that change is fully reverted here, so WebViewFlutterPlugin.swift is untouched.

Why the minimum Flutter version is bumped

UiKitView.gestureBlockingPolicy landed in flutter/flutter#185126 and first shipped in stable 3.47.0 (it is not present in 3.44.x), so flutter: ">=3.47.0" is required to reference it at all. validate enforces a matching Dart lower bound, hence sdk: ^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's getDartSdkForFlutterSdk map had no entry for Flutter 3.47.0, so validate failed until one was added.
  • Raising the package's language version to Dart 3.13 changes dart format output 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_inappwebview also registers its iOS platform view via the two-argument registrar.register(_:withId:) (so, eager), and shows the same symptom on iOS 26 in the same app — which suggests the underlying issue is not specific to webview_flutter.

Verified locally with Flutter 3.47.0: validate, federation-safety-check, flutter analyze (package + example) and flutter test (157 tests) all pass.

Related: flutter/flutter#175099, flutter/flutter#179907
Fixes flutter/flutter#191267

Pre-Review Checklist

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +44 to +47
registrar.register(
viewFactory, withId: "plugins.flutter.io/webview",
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. 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.
  2. Passing the policy from the Dart side — that makes sense; hardcoding it in WebViewFlutterPlugin takes 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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Comment on lines +93 to +95
#expect(
registrar.registeredGestureRecognizersBlockingPolicy
== FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the idiomatic Swift enum case .doNotBlockGesture simplifies the assertion and improves readability.

      #expect(registrar.registeredGestureRecognizersBlockingPolicy == .doNotBlockGesture)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@stuartmorgan-g stuartmorgan-g added the triage-ios Should be looked at in iOS triage label Aug 18, 2026
Comment on lines +44 to +47
registrar.register(
viewFactory, withId: "plugins.flutter.io/webview",
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@burakJs
burakJs force-pushed the webview-hittest-gesture-policy branch from e28f33a to 0d92961 Compare August 19, 2026 19:23
@burakJs burakJs changed the title [webview_flutter] Register the iOS platform view with the hit-test gesture blocking policy [webview_flutter] Add gesture blocking policy to WebKitWebViewWidgetCreationParams Aug 19, 2026

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid this description, since we don't know what's happening yet.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd delete these 2 since we are not 100% sure this is indeed the cause yet.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@burakJs
burakJs force-pushed the webview-hittest-gesture-policy branch from 0d92961 to ba04a2a Compare August 19, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p: webview_flutter platform-ios triage-ios Should be looked at in iOS triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[webview_flutter][iOS] Platform view stops receiving touches after the first interaction on iOS 26

3 participants