Skip to content

[beta] [web] Cancel touch pointers WebKit abandons mid-gesture - #190231

Merged
auto-submit[bot] merged 1 commit into
flutter:flutter-3.47-candidate.0from
flutter-zl:cherry-pick-189608-to-beta
Jul 29, 2026
Merged

auto-submit[bot] merged 1 commit into
flutter:flutter-3.47-candidate.0from
flutter-zl:cherry-pick-189608-to-beta

Conversation

@flutter-zl

@flutter-zl flutter-zl commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

This pull request cherry-picks #189608 into the beta release branch (flutter-3.47-candidate.0) so the fix ships in the next stable release.

Issue Link:

#188781

Impact Description:

P0 regression. On iOS 27, which affects every browser since they all run WebKit, a text field in a Flutter web app can become permanently unresponsive after a common gesture. When the user long-press-drags the selection caret and
lifts, WebKit abandons the touch without delivering pointerup or pointercancel, leaving the framework holding a pointer that never lifts. This wedges the tap-and-drag gesture recognizer, so every later tap is silently dropped: the field never regains focus and the keyboard never returns, and the user can no longer type. It breaks text input in shipping production web apps. iOS 26 is unaffected.

Changelog Description:

[flutter/188781] When dragging the text selection caret on iOS 27 web browsers, text fields could become permanently unresponsive to taps and never regain focus; they now recover.

Workaround:

No in-app workaround. Reloading the page temporarily restores the field, but it breaks again the next time the gesture occurs.

Risk:

The change is small and strictly gated to iOS WebKit. It only cancels touch pointers the browser has already dropped from its touches list, so it cannot affect other platforms or normal pointer handling.

  • Low
  • Medium
  • High

Test Coverage:

The fix adds 341 lines of engine unit tests in pointer_binding_test.dart covering the touch-cancel logic.

  • Yes
  • No

Validation Steps:

  1. Open a Flutter web app containing a TextField on an iOS 27 device, any browser.
  2. Tap the field to focus it and type some text.
  3. Long-press the selection caret, drag it, then lift your finger.
  4. Tap the field again, and repeat a few times.
  5. Before the fix the field becomes permanently dead: taps do nothing, no focus, no keyboard. After the fix the field keeps responding and recovers.

Demo before: https://flutter-demo-47-before.web.app
Demo after: https://flutter-demo-47-after.web.app

Fixes flutter#188781

**Problem**
On iOS 27, WebKit stops dispatching pointer events for a touch it
promotes to a native gesture, such as dragging the caret in a text
field, and delivers neither `pointerup` nor `pointercancel`. The
framework is left holding a pointer that never lifts, which wedges
`BaseTapAndDragGestureRecognizer` so every later tap is silently
dropped: the field never regains focus and the keyboard never returns.
Affects every iOS 27 browser, since they all run WebKit; iOS 26 is
unaffected.

**Fix**
`_PointerAdapter` tracks which touch devices are down and, on `touchend`
and `touchcancel`, cancels any the browser no longer lists in `touches`.
Gated to iOSWebKit.

**Demo**
Before: https://flutter-demo-47-before.web.app
After:  https://flutter-demo-47-after.web.app

**Repro steps:** 
type in the field, long-press the caret and drag it, lift, then tap the
field.
Before, the field is permanently dead after a few tries. 
After, it recovers.
@flutter-zl flutter-zl added the cp: review Cherry-picks in the review queue label Jul 29, 2026
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jul 29, 2026
@flutter-dashboard

Copy link
Copy Markdown

This pull request was opened from and to a release candidate branch. This should only be done as part of the official Flutter release process. If you are attempting to make a regular contribution to the Flutter project, please close this PR and follow the instructions at Tree Hygiene for detailed instructions on contributing to Flutter.

Reviewers: Use caution before merging pull requests to release branches. Ensure the proper procedure has been followed.

@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team labels Jul 29, 2026

@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 introduces a mechanism to detect and cancel abandoned touch pointers on iOS WebKit by reconciling tracked down touch devices against the active touches reported on the surface during touchend and touchcancel events. It also adds helper methods to flush the click debouncer queue before sending synthetic cancel events, along with comprehensive unit tests. The reviewer suggests also registering the _cancelAbandonedTouches safety net on touchstart events to clean up any stale pointers at the very beginning of a subsequent touch interaction.

Comment on lines +1206 to +1213
// Safety net for touches the browser abandons without a `pointerup` or a
// `pointercancel`. See [_cancelAbandonedTouches].
addEventListener(_globalTarget, 'touchend', (DomEvent event) {
_cancelAbandonedTouches(event as DomTouchEvent);
});
addEventListener(_globalTarget, 'touchcancel', (DomEvent event) {
_cancelAbandonedTouches(event as DomTouchEvent);
});

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

Currently, _cancelAbandonedTouches is only registered for touchend and touchcancel events. If a touch is abandoned and its touchend is dropped by the browser, the abandoned pointer will remain active in the framework during the entire active phase of the next touch gesture (until its touchend fires). This can interfere with gesture recognition for the new gesture (e.g., interpreting a single-finger drag as a multi-finger gesture).

Registering _cancelAbandonedTouches on touchstart as well allows cleaning up the abandoned pointer at the very beginning of the next touch interaction, before the new pointer's pointerdown event is dispatched to the framework.

    // Safety net for touches the browser abandons without a `pointerup` or a
    // `pointercancel`. See [_cancelAbandonedTouches].
    addEventListener(_globalTarget, 'touchstart', (DomEvent event) {
      _cancelAbandonedTouches(event as DomTouchEvent);
    });
    addEventListener(_globalTarget, 'touchend', (DomEvent event) {
      _cancelAbandonedTouches(event as DomTouchEvent);
    });
    addEventListener(_globalTarget, 'touchcancel', (DomEvent event) {
      _cancelAbandonedTouches(event as DomTouchEvent);
    });

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

LGTM

@camsim99 camsim99 added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 29, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 29, 2026
@auto-submit

auto-submit Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/190231, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@camsim99 camsim99 added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 29, 2026
@auto-submit
auto-submit Bot merged commit effb186 into flutter:flutter-3.47-candidate.0 Jul 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD cp: review Cherry-picks in the review queue engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants