feat(paywalls): add web_view JavaScript bridge (PWENG-98)#3655
feat(paywalls): add web_view JavaScript bridge (PWENG-98)#3655alexrepty wants to merge 5 commits into
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
e9af9f9 to
1704224
Compare
21899a1 to
276280e
Compare
1704224 to
e63218e
Compare
7769f56 to
716657f
Compare
e63218e to
aab1540
Compare
716657f to
27bcaa4
Compare
aab1540 to
8483042
Compare
27bcaa4 to
c009f2d
Compare
7b32cdc to
b712772
Compare
c009f2d to
3ca2b9e
Compare
b712772 to
9627fbf
Compare
9c03cae to
c73e87b
Compare
9627fbf to
5fcb286
Compare
c73e87b to
cf8f802
Compare
5fcb286 to
6b3546c
Compare
b7e4c63 to
35d1a2c
Compare
cf8f802 to
f341b57
Compare
f341b57 to
4fcc3b7
Compare
35d1a2c to
39fe849
Compare
4fcc3b7 to
7298c01
Compare
39fe849 to
28307d9
Compare
Adds a bidirectional JS<->native bridge for the Paywalls V2 `web_view` component: a document-start `window.RevenueCatWebView` shim, message parsing/validation (`WebViewMessageParser`, `WebViewMessageType`), the public `PaywallWebViewMessage` / `PaywallWebViewValue` / `PaywallWebViewMessageHandler` / `PaywallWebViewController` surface, and an SDK-managed variables provider (locale, color scheme, custom variables). Apps opt in via `PaywallOptions.setWebViewMessageHandler(...)`, threaded through `PaywallState` / `OfferingToStateMapper`. Regenerates ui/revenuecatui/api.txt for the new public API. Recommended labels: pr:feat, pr:RevenueCatUI, feat:Paywalls_V2
7298c01 to
e94849b
Compare
28307d9 to
26368d7
Compare
| // origin: an explicit default port and an omitted one must not cause spurious message drops. | ||
| val effectivePort = if (port == -1) defaultPort else port | ||
| val portSuffix = if (effectivePort == -1) "" else ":$effectivePort" | ||
| return "$protocol://$host$portSuffix" |
There was a problem hiding this comment.
Case-sensitive origin host matching
Medium Severity
toOriginOrNull builds an origin string with the host exactly as java.net.URL returns it, and isCurrentOriginExpected compares that to an origin parsed from webView.url using plain string equality. Hostnames are case-insensitive per URL rules, and Android’s WebView often lowercases the host in getUrl() after load. A paywall URL whose template keeps mixed-case ASCII in the host can make every inbound and outbound bridge message look like a cross-origin mismatch and be dropped.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 26368d7. Configure here.
📸 Snapshot Test593 unchanged
🛸 Powered by Emerge Tools |
Generated by 🚫 Danger |
|
@BugBot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 3 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8063d3f. Configure here.
| componentId = componentId, | ||
| type = type, | ||
| payload = variables.toJsonObject(), | ||
| ) |
There was a problem hiding this comment.
postMessage payload omits variables key
Medium Severity
PaywallWebViewController.postMessage documents that app data is sent under a variables field, but the bridge sets the transport payload to the flat map from variables.toJsonObject(). Web content expecting payload.variables will not see app-provided fields for custom message types.
Reviewed by Cursor Bugbot for commit 8063d3f. Configure here.
| ) { | ||
| if (request.isForMainFrame && errorResponse.statusCode >= HTTP_ERROR_STATUS_MIN) { | ||
| onMainFrameLoadFailed() | ||
| } |
There was a problem hiding this comment.
Main-frame errors always trigger fallback
Medium Severity
New WebViewClient error handlers set loadFailed on any main-frame onReceivedError or HTTP status ≥ 400, with no check for benign codes like ERROR_CANCELLED. Once loadFailed is true and a schema fallback exists, the web view is replaced permanently even if the page actually loaded.
Reviewed by Cursor Bugbot for commit 8063d3f. Configure here.
The native host will use declared component size only; drop bridge fit messages and resize handling.



Checklist
purchases-iosand hybridsMotivation
Provides the live JS↔native bridge that powers
web_viewbidirectional messaging, built on the message model and variables provider.Part of PWENG-98.
Description
WebViewJavaScriptBridge: installs a document-startwindow.RevenueCatWebViewshim, validates and dispatches inbound messages (origin-checked, on the main thread), and delivers native→web messages viawindow.__revenueCatReceiveMessage.{ "type", "component_id", "variables" }envelope (payload nested undervariables), matching the other RevenueCat SDK platforms. Onrc:request-variablesthe SDK auto-replies with its system variables, then invokes the app handler.WebViewJavaScriptBridgeTest.iOS parity: mirrors
purchases-ios(web-view-bridge-wiring), including the{ type, component_id, variables }envelope.Stack (merge bottom-up): schema → rendering → CSP → value types → message model → variables provider → JS bridge → wiring.
Note
High Risk
Introduces a JavaScript interface on WebView with origin validation and CSP; mistakes could affect paywall security or hosted web flows, though the change includes explicit origin checks and extensive tests.
Overview
Adds bidirectional JS↔native messaging for Paywalls V2
web_view, aligned withworkflow-web-components-sdk(rc-web-componentschannel,connect/inithandshake,message/request/responseframes) viawindow.rcWebComponentsand__rcWebComponentsReceive—replacing a flat postMessage shape and document-start shim.WebViewJavaScriptBridgehandles handshake, origin checks, payload limits, auto-reply torc:request-variables,fit/resizefor fit sizing, and lifecycle on the main thread.WebViewMessageParserandWebViewEnvelopeparse the new wire format; schema gains optionalfallbackstack.WebViewComponentViewinstalls the bridge whencomponentIdis set, detects main-frame load failures (HTTP ≥400), renders the fallback stack, and adjusts layout from content-reported CSS size. Style factory passescomponentIdand fallback intoWebViewComponentStyle;ComponentViewforwards click/interaction callbacks to the web view path.Coverage:
WebViewJavaScriptBridgeTestand updatedWebViewMessageParserTest.Reviewed by Cursor Bugbot for commit 8063d3f. Bugbot is set up for automated code reviews on this repo. Configure here.