Skip to content

fix(paywalls): arbitrate web_view drag gestures with paywall scroll on iOS#7283

Open
ajpallares wants to merge 14 commits into
mainfrom
pallares/webview-gesture-arbitration
Open

fix(paywalls): arbitrate web_view drag gestures with paywall scroll on iOS#7283
ajpallares wants to merge 14 commits into
mainfrom
pallares/webview-gesture-arbitration

Conversation

@ajpallares

@ajpallares ajpallares commented Jul 24, 2026

Copy link
Copy Markdown
Member

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-android and hybrids

Motivation

A web_view whose content pans via JavaScript — a touch-action map, an inner overflow: auto scroller — is invisible to iOS nested-scroll arbitration, so a drag both pans the content and scrolls the enclosing paywall ("double scroll").

Description

Mirrors RevenueCat/purchases-android#3823. A document-start probe reports, per touch, whether the touched element consumes the drag; a custom recognizer on the web view then claims the gesture from the paywall scroll only when it does, otherwise deferring to native root scrollability. iOS-only (touch-based).


Note

Medium Risk
Touches core paywall scroll/gesture behavior on every iOS web_view; mis-arbitration could block paywall scrolling or leave double-scroll, though logic is scoped to ancestor scroll views and covered by tests mirroring Android.

Overview
Fixes double scroll on iOS when a Paywalls V2 web_view sits inside a scrollable paywall and page content pans via JavaScript (e.g. touch-action, inner overflow scrollers) that UIKit cannot arbitrate on its own.

Adds iOS-only nested-scroll arbitration aligned with Android: a document-start WebViewGestureProbe user script posts own/release per touchstart, and WebViewScrollOwnershipRecognizer on the WKWebView claims the drag only when the probe or the web view’s scroll offsets say the content should own it—otherwise ancestor paywall UIScrollView pans win via shouldBeRequiredToFailBy. Touches are not cancelled so taps and in-page panning still work.

WebViewRepresentable installs the probe, handler, and recognizer before the first load and removes the probe message handler in dismantle. Unit tests cover shouldWebViewOwnGesture, recognizer delegate wiring, and probe script shape.

Reviewed by Cursor Bugbot for commit d5d7373. Bugbot is set up for automated code reviews on this repo. Configure here.

ajpallares and others added 3 commits July 23, 2026 17:56
Enable the WKWebView scroll view so fill/fixed-height web_view components
whose content overflows the frame can scroll. Fit-height components are
unaffected: their frame grows to the measured content height, leaving no
scrollable overflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
…n iOS

Adds a document-start ownership probe and a custom gesture recognizer so a
web_view whose content pans via JavaScript (touch-action maps, inner overflow
scrollers) claims the drag from the enclosing paywall scroll instead of
double-scrolling. iOS-only; mirrors purchases-android #3823.

Co-authored-by: Cursor <cursoragent@cursor.com>
@emerge-tools

emerge-tools Bot commented Jul 24, 2026

Copy link
Copy Markdown

4 builds increased size

Name Version Download Change Install Change Approval
RevenueCat
com.revenuecat.PaywallsTester
1.0 (1) 19.3 MB ⬆️ 20.0 kB (0.1%) 70.0 MB ⬆️ 101.2 kB (0.15%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.local-source
1.0 (1) 4.5 MB ⬆️ 3.6 kB (0.08%) 13.5 MB ⬆️ 6.2 kB (0.05%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.cocoapods
1.0 (1) 6.8 MB ⬆️ 4.6 kB (0.07%) 29.6 MB ⬆️ 18.6 kB (0.06%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.spm
1.0 (1) 4.6 MB ⬆️ 1.8 kB (0.04%) 11.7 MB ⬆️ 5.8 kB (0.05%) N/A

RevenueCat 1.0 (1)
com.revenuecat.PaywallsTester

⚖️ Compare build
⏱️ Analyze build performance

Total install size change: ⬆️ 101.2 kB (0.15%)
Total download size change: ⬆️ 20.0 kB (0.1%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 54.0 kB
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.Objc Metadata ⬆️ 10.3 kB
Code Signature ⬆️ 2.4 kB
DYLD.Exports ⬆️ 1.7 kB
Strings.Unmapped ⬆️ 1.1 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.local-source

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 6.2 kB (0.05%)
Total download size change: ⬆️ 3.6 kB (0.08%)

Largest size changes

Item Install Size Change
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.Objc Metadata ⬆️ 937 B
DYLD.String Table ⬆️ 736 B
📝 __C.Set ⬆️ 632 B
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.touchesMoved(with) ⬆️ 624 B
Other ⬆️ 3.3 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.cocoapods

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 18.6 kB (0.06%)
Total download size change: ⬆️ 4.6 kB (0.07%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 4.9 kB
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.Objc Metadata ⬆️ 837 B
📝 __C.Set ⬆️ 668 B
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.touchesMoved(with) ⬆️ 624 B
Other ⬆️ 11.5 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.spm

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 5.8 kB (0.05%)
Total download size change: ⬆️ 1.8 kB (0.04%)

Largest size changes

Item Install Size Change
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.Objc Metadata ⬆️ 937 B
📝 RevenueCatUI.WebViewScrollOwnershipRecognizer.touchesMoved(with) ⬆️ 612 B
__C.Set ⬆️ 596 B
Other ⬆️ 3.6 kB
View Treemap

Image of diff


🛸 Powered by Emerge Tools

Comment trigger: Size diff threshold of 100.00kB exceeded

ajpallares and others added 4 commits July 24, 2026 11:21
…deproj

Danger flagged the new file as missing from the Xcode project. Add it to the
RevenueCatUI target alongside the sibling WebView sources.

Co-authored-by: Cursor <cursoragent@cursor.com>
Ports purchases-android DragGestureArbitrationTest for the shouldWebViewOwnGesture
decision function, and adds tests for the recognizer's ancestor-scroll
failure-requirement wiring and the document-start probe script config.

Co-authored-by: Cursor <cursoragent@cursor.com>
…t.xcodeproj

Danger flagged the new test file as missing from the Xcode project. Add it to
the PaywallsV2 test group alongside the sibling WebView tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
…re probe

Self-documents the element-node checks in the web_view gesture probe script.

Co-authored-by: Cursor <cursoragent@cursor.com>
Base automatically changed from pallares/webview-enable-scroll to main July 24, 2026 11:02
ajpallares and others added 2 commits July 24, 2026 13:20
…guard

Reword the arbitration comments to cover any drag axis (not just vertical),
describe the direction convention in iOS terms, and short-circuit on the
`decided` guard before computing the probe verdict.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ajpallares
ajpallares marked this pull request as ready for review July 24, 2026 11:54
@ajpallares
ajpallares requested review from a team as code owners July 24, 2026 11:54
@ajpallares
ajpallares requested review from a team and AlvaroBrey July 24, 2026 11:55
@ajpallares
ajpallares changed the base branch from main to pallares/create-local-xcconfig-when-missing July 24, 2026 12:16
@ajpallares
ajpallares force-pushed the pallares/webview-gesture-arbitration branch from 544d49c to a7ed568 Compare July 24, 2026 14:23
@ajpallares
ajpallares changed the base branch from pallares/create-local-xcconfig-when-missing to main July 24, 2026 14:23
ajpallares and others added 4 commits July 24, 2026 17:40
Enable rubber-banding on the web view's scroll view so overflowing content
(Fill/Fixed height) feels native at its top/bottom edges.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ajpallares
ajpallares changed the base branch from main to pallares/webview-scroll-bounce July 24, 2026 17:00
Base automatically changed from pallares/webview-scroll-bounce to main July 24, 2026 18:28
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.

2 participants