Skip to content

[webview_flutter] Register the iOS platform view with the hit-test gesture blocking policy - #12496

Open
burakJs wants to merge 1 commit into
flutter:mainfrom
burakJs:webview-hittest-gesture-policy
Open

[webview_flutter] Register the iOS platform view with the hit-test gesture blocking policy#12496
burakJs wants to merge 1 commit into
flutter:mainfrom
burakJs:webview-hittest-gesture-policy

Conversation

@burakJs

@burakJs burakJs commented Aug 18, 2026

Copy link
Copy Markdown

Registers the iOS platform view with FlutterPlatformViewGestureRecognizersBlockingPolicyDoNotBlockGesture instead of relying on the default eager policy.

eager blocks the platform view's gesture recognizers through Flutter's gesture arena, which is stateful. If that state is stranded the web view stops receiving touches for the rest of its lifetime. The engine used to recover from this in ForwardingGestureRecognizer.forceResetStateIfNeeded, but that reset returns early on iOS 26 and above (see flutter/flutter#179907), so on iOS 26 there is nothing left to recover it.

doNotBlockGesture derives the same blocking decision from hitTest rather than the arena, and does not install the delaying recognizer at all — so there is no recognizer state to strand. Blocking behaviour itself is preserved: FlutterTouchInterceptingView.hitTest still consults platformViewShouldAcceptTouchAtTouchBeganLocation: and returns itself when a Flutter widget is on top, and the forwarding recognizer is still installed so Flutter's arena keeps seeing the touches.

Verified on iOS 26.3 simulator, iOS 26.4 simulator and an iOS 26.6 device: the web view is unresponsive after the first interaction without this change, and behaves correctly with it.

Fixes flutter/flutter#191267

Open question for the reviewer: this change is unconditional rather than gated behind if #available(iOS 26.0, *). I went that way because it is not iOS-26-specific in principle — the arena state can be stranded on any version, iOS 26 just removed the net that used to hide it — and because it matches the direction described in flutter/flutter#175099 ("help prevent regressions even if this WebKit bug happens again"). Happy to add a version gate instead if you would rather keep the blast radius smaller.

Pre-Review Checklist

…sture policy

The default eager policy blocks the platform view's gesture recognizers
through Flutter's stateful gesture arena. When that state is stranded the
web view stops receiving touches for the rest of its lifetime, which
reproduces on iOS 26 where the engine's stuck-state reset is disabled.

The doNotBlockGesture policy derives the same blocking decision from hit
testing, so there is no recognizer state left to strand.

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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