Skip to content

2.7.7#380

Merged
ianrumac merged 8 commits intomainfrom
develop
Mar 10, 2026
Merged

2.7.7#380
ianrumac merged 8 commits intomainfrom
develop

Conversation

@ianrumac
Copy link
Collaborator

@ianrumac ianrumac commented Mar 10, 2026

2.7.7

Enhancements

  • Adds support for local resource loading in paywalls via Superwall.instance.localResources

Fixes

  • Fix issues with stripe period types failing to deserialize

Checklist

  • All unit tests pass.
  • All UI tests pass.
  • Demo project builds and runs.
  • I added/updated tests or detailed why my change isn't tested.
  • I added an entry to the CHANGELOG.md for any breaking changes, enhancements, or bug fixes.
  • I have run ktlint in the main directory and fixed any issues.
  • I have updated the SDK documentation as well as the online docs.
  • I have reviewed the contributing guide

Greptile Summary

This PR releases version 2.7.7, delivering two changes: (1) a new local resource loading system for paywall WebViews via swlocal:// custom URLs, and (2) a serialization fix for Stripe subscription period/state types that were always deserializing to UNKNOWN.

Key changes:

  • LocalResourceHandler (new): intercepts swlocal:// URLs in shouldInterceptRequest and serves assets from either a file:///content:// Uri or an Android resource ID (R.raw.*, R.drawable.*). Includes CORS headers, proper MIME type resolution, and structured error responses (400/404/500).
  • Superwall.localResources (new public API): a Map<String, PaywallResource> that developers populate to register local assets by ID. The WebView lazily creates the handler and reads this map at request time.
  • LatestPeriodType / LatestSubscriptionState: the old custom KSerializer used case-insensitive matching against enum names (e.g. "GRACE_PERIOD"), but the API sends lowercase snake_case ("grace_period"), so every value was silently falling back to UNKNOWN. Both enums are now annotated with lowercase @SerialName values that match the actual API contract. coerceInputValues = true is added to SubscriptionService as a forward-compatibility safety net.
  • Two new LatestPeriodType variants (CODE, WINBACK) and their string mappings in ReceiptManager.determinePeriodType().
  • Comprehensive LocalResourceHandlerTest covering all response code paths, MIME type fallback, and CORS header presence.

Confidence Score: 4/5

  • This PR is safe to merge; the serialization fix is correct and the local resource feature is well-tested with only minor style improvements possible.
  • The serialization fix is a genuine bug fix (the old serializer was always returning UNKNOWN for all values). The new LocalResourceHandler is well-structured with proper error handling and a solid Robolectric test suite. Two minor style issues exist in LocalResourceHandler: the MIME type extraction uses a slightly fragile path through MimeTypeMap.getFileExtensionFromUrl for resource entry names, and the success response passes null encoding. Neither is a runtime blocker given the primary binary use-case (images/videos). No breaking changes to existing public APIs.
  • No files require special attention — LocalResourceHandler.kt has two minor style suggestions worth addressing before merge.

Important Files Changed

Filename Overview
superwall/src/main/java/com/superwall/sdk/paywall/view/webview/LocalResourceHandler.kt New file implementing the swlocal:// URL interception and local resource serving. Well-structured with proper error responses (400/404/500). Two minor style issues: extension is redundantly re-extracted via MimeTypeMap.getFileExtensionFromUrl, and the success response passes null encoding which could affect text resources.
superwall/src/main/java/com/superwall/sdk/paywall/view/webview/DefaultWebviewClient.kt Adds shouldInterceptRequest override that delegates swlocal:// URLs to LocalResourceHandler while passing all other requests to the parent. Integration is clean and correct.
superwall/src/main/java/com/superwall/sdk/store/abstractions/product/receipt/LatestPeriodType.kt Fixes deserialization by changing @SerialName values from uppercase (TRIAL/SUBSCRIPTION/etc.) to lowercase snake_case matching the actual API values. Adds two new variants: CODE and WINBACK.
superwall/src/main/java/com/superwall/sdk/store/abstractions/product/receipt/LatestSubscriptionState.kt Replaces a custom KSerializer (which used case-insensitive .name matching, effectively always returning UNKNOWN for lowercase API values) with standard @SerialName annotations mapping to the actual lowercase strings the API sends. Correct fix for the deserialization bug.
superwall/src/main/java/com/superwall/sdk/network/SubscriptionService.kt Adds coerceInputValues = true to the JSON parser as a safety net for future unknown enum values. Correctly complements the @SerialName refactoring in the receipt models.
superwall/src/main/java/com/superwall/sdk/paywall/view/webview/SWWebView.kt Lazily initialises LocalResourceHandler and passes it to both DefaultWebviewClient and WebviewFallbackClient. The lazy delegate ensures the handler is created only when the WebView is first used. Clean integration.
superwall/src/main/java/com/superwall/sdk/Superwall.kt Adds the public localResources: Map<String, PaywallResource> property with KDoc and usage example. Property is a simple var defaulting to emptyMap(), safe for concurrent read access.
superwall/src/test/java/com/superwall/sdk/paywall/view/webview/LocalResourceHandlerTest.kt Comprehensive Robolectric test suite covering all key paths: scheme detection, 400/404/500 error responses, valid URI and resource ID handling, unknown MIME type fallback, and CORS header presence. Good coverage.
superwall/src/main/java/com/superwall/sdk/store/abstractions/product/receipt/ReceiptManager.kt Adds CODE and WINBACK cases to determinePeriodType() matching the two new LatestPeriodType variants. No issues.
superwall/src/main/java/com/superwall/sdk/paywall/view/webview/WebviewFallbackClient.kt Adds localResourceHandler parameter and forwards it to the DefaultWebviewClient superclass. Parameter ordering matches the parent constructor correctly.

Sequence Diagram

sequenceDiagram
    participant PW as Paywall HTML
    participant WV as SWWebView
    participant DWC as DefaultWebviewClient
    participant LRH as LocalResourceHandler
    participant SW as Superwall.localResources
    participant CR as ContentResolver / Resources

    PW->>WV: GET swlocal://hero-video
    WV->>DWC: shouldInterceptRequest(url)
    DWC->>LRH: isLocalResourceUrl(url) → true
    DWC->>LRH: handleRequest(url)
    LRH->>SW: localResources()[resourceId]
    SW-->>LRH: PaywallResource.FromUri(uri) or FromResources(resId)
    alt FromUri
        LRH->>CR: contentResolver.openInputStream(uri)
        CR-->>LRH: InputStream
    else FromResources
        LRH->>CR: resources.openRawResource(resId)
        CR-->>LRH: InputStream
    end
    LRH-->>DWC: WebResourceResponse(200, mimeType, CORS headers, stream)
    DWC-->>WV: WebResourceResponse
    WV-->>PW: Asset data
Loading

Last reviewed commit: a15c74a

Greptile also left 2 inline comments on this PR.

anglinb and others added 8 commits March 9, 2026 16:57
Replace @SerialName-based serialization with a custom case-insensitive
serializer so both lowercase Stripe values ("trial") and uppercase Play
Store values ("TRIAL") deserialize correctly. Add missing CODE and
WINBACK variants to match iOS OfferType parity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sensitive-serializer

Fix LatestPeriodType case-insensitive deserialization for Stripe
@ianrumac ianrumac merged commit 78f1af9 into main Mar 10, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants