Skip to content

feat(paywalls): enable web_view component (8)#3787

Open
JZDesign wants to merge 6 commits into
mainfrom
webview/8-activate
Open

feat(paywalls): enable web_view component (8)#3787
JZDesign wants to merge 6 commits into
mainfrom
webview/8-activate

Conversation

@JZDesign

@JZDesign JZDesign commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Checklist

  • If applicable, unit tests

Motivation

Final part of the web_view series (splitting #3757). This is the activation PR: the only change that alters runtime behavior, so reverting it alone turns the web_view feature off. All downstack parts (schema, transport envelope, navigation policy, JS bridge, Compose view, kotlinx transport refactor, WebView profile isolation) are merged; this now sits standalone on main.

Description

  • Register "web_view" in the PaywallComponent deserializer
  • Replace the StyleFactory stub (Result.Success(null)) with createWebViewComponentStyle
  • Add WebViewComponent.SUPPORTED_PROTOCOL_VERSION as the single source of truth for the supported version; the runtime handshake in :ui:revenuecatui derives from it, so the decode-time gate and the handshake cannot disagree
  • Absent, malformed, or unsupported protocol_version renders the component fallback (same path as an unknown component), gated on the raw value before decode for forward compatibility
  • Tests: WebViewComponentTests decode and version-gate cases, StyleFactoryTests, and e2e WebViewOfferingToStateTest (a config with web_view produces a WebViewComponentStyle in the paywall state)

Submodule

No web_view preview fixtures on the resources submodule; pointer left untouched.

Verified locally: WebViewComponentTests, StyleFactoryTests, webview.* (incl. e2e), detektAll.

Labels: pr:feat, pr:RevenueCatUI, feat:Paywalls_V2

After merge

Close #3757 as superseded (do not merge it).


Note

Medium Risk
Enables hosted WebView content in paywalls (new attack/rendering surface), though unsupported protocol versions and missing fallbacks are gated; misconfigured paywalls without fallbacks can still fail deserialization.

Overview
Turns on Paywalls V2 web_view end-to-end: configs with type: "web_view" now deserialize through PaywallComponent and map to WebViewComponentStyle instead of being dropped by the StyleFactory stub.

Decoding: "web_view" is registered in PaywallComponentSerializer. protocol_version is checked on the raw JSON before decoding the body; only version 1 (WebViewComponent.SUPPORTED_PROTOCOL_VERSION) becomes a WebViewComponent. Missing, malformed, or unsupported versions use the same fallback path as unknown components (including forward-incompatible future payloads), with a shared decodeFallback helper.

Runtime alignment: WebViewEnvelope.DEFAULT_PROTOCOL_VERSION now derives from WebViewComponent.SUPPORTED_PROTOCOL_VERSION so the schema gate and JS bridge handshake stay in sync.

Tests: Polymorphic decode and version-gate cases in WebViewComponentTests, StyleFactory coverage, and WebViewOfferingToStateTest (config → paywall state includes WebViewComponentStyle).

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

AlvaroBrey commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 80.44%. Comparing base (ca2c344) to head (346e2c8).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
.../purchases/paywalls/components/PaywallComponent.kt 92.30% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3787      +/-   ##
==========================================
+ Coverage   80.43%   80.44%   +0.01%     
==========================================
  Files         408      408              
  Lines       16890    16900      +10     
  Branches     2467     2469       +2     
==========================================
+ Hits        13586    13596      +10     
  Misses       2342     2342              
  Partials      962      962              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch from a77cdfd to 34f2544 Compare July 20, 2026 10:19
@AlvaroBrey AlvaroBrey changed the title feat(paywalls): enable web_view component (9/9) feat(paywalls): enable web_view component (8) Jul 20, 2026
@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch from 34f2544 to eed8e96 Compare July 20, 2026 15:14
@emerge-tools

emerge-tools Bot commented Jul 20, 2026

Copy link
Copy Markdown

📸 Snapshot Test

621 unchanged

Name Added Removed Modified Renamed Unchanged Errored Approval
TestPurchasesUIAndroidCompatibility
com.revenuecat.testpurchasesuiandroidcompatibility
0 0 0 0 339 0 N/A
TestPurchasesUIAndroidCompatibility Paparazzi
com.revenuecat.testpurchasesuiandroidcompatibility.paparazzi
0 0 0 0 282 0 N/A

🛸 Powered by Emerge Tools

@AlvaroBrey
AlvaroBrey force-pushed the webview/9-kotlinx-envelope branch from 8c11c73 to e168877 Compare July 22, 2026 08:19
@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch from ee57f61 to 87ec64a Compare July 22, 2026 08:19
@AlvaroBrey
AlvaroBrey changed the base branch from webview/9-kotlinx-envelope to graphite-base/3787 July 22, 2026 09:17
@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch from 87ec64a to 59b9d72 Compare July 22, 2026 09:17
@AlvaroBrey
AlvaroBrey force-pushed the graphite-base/3787 branch from e168877 to c331b16 Compare July 22, 2026 09:17
@AlvaroBrey
AlvaroBrey changed the base branch from graphite-base/3787 to webview/10-profile-isolation July 22, 2026 09:17
@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch 2 times, most recently from a0926f5 to 3f17314 Compare July 22, 2026 09:35
@AlvaroBrey
AlvaroBrey force-pushed the webview/10-profile-isolation branch from 658facd to 89c8a8e Compare July 22, 2026 09:54
@AlvaroBrey
AlvaroBrey force-pushed the webview/8-activate branch 2 times, most recently from 0709292 to 12112d7 Compare July 22, 2026 10:11
@AlvaroBrey
AlvaroBrey force-pushed the webview/10-profile-isolation branch from 89c8a8e to 6d0ed10 Compare July 22, 2026 10:11
@AlvaroBrey

Copy link
Copy Markdown
Contributor

@cursor review

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 12112d7. Configure here.

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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 ec6fa0b. Configure here.

AlvaroBrey and others added 6 commits July 24, 2026 17:07
Avoids the pre-first-frame play-button placeholder Android WebView paints
over an autoplay <video>. Hides video[autoplay] until it emits 'playing',
with a 5s fallback reveal so a video that never plays can't stay hidden.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Jacob Rakidzich <Jacob@JacobZivanDesign.com>
When a web_view component declares a protocol_version this SDK does not
implement, treat it like an unrecognized component and render the author's
`fallback` (throwing if none), instead of rendering a web view whose bridge
handshake would just be rejected at runtime. Mirrors purchases-js and the
generic unknown-component fallback path. Backend already rejects != 1 at
publish time; this is client-side defense in depth.
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