fix(paywalls): arbitrate web_view drag gestures with paywall scroll on iOS#7283
fix(paywalls): arbitrate web_view drag gestures with paywall scroll on iOS#7283ajpallares wants to merge 14 commits into
Conversation
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>
4 builds increased size
RevenueCat 1.0 (1)
|
| 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 |
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 |
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 |
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 |
🛸 Powered by Emerge Tools
Comment trigger: Size diff threshold of 100.00kB exceeded
…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>
…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>
544d49c to
a7ed568
Compare
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>
…esture-arbitration




Checklist
purchases-androidand hybridsMotivation
A
web_viewwhose content pans via JavaScript — atouch-actionmap, an inneroverflow: autoscroller — 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_viewsits 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
WebViewGestureProbeuser script postsown/releasepertouchstart, andWebViewScrollOwnershipRecognizeron theWKWebViewclaims the drag only when the probe or the web view’s scroll offsets say the content should own it—otherwise ancestor paywallUIScrollViewpans win viashouldBeRequiredToFailBy. Touches are not cancelled so taps and in-page panning still work.WebViewRepresentableinstalls the probe, handler, and recognizer before the first load and removes the probe message handler indismantle. Unit tests covershouldWebViewOwnGesture, 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.