Skip to content

Bump Android SDK to 2.8.7 - #16

Closed
github-actions[bot] wants to merge 1 commit into
mainfrom
native-sdk/android-2.8.7
Closed

github-actions[bot] wants to merge 1 commit into
mainfrom
native-sdk/android-2.8.7

Conversation

@github-actions

Copy link
Copy Markdown

Bumps the Android SDK from 2.7.23 to 2.8.7. The package version is unchanged; the note is under [Unreleased].

Opened automatically by native-sdk-bump.yml after superwall/Superwall-Android 2.8.7 was released. An agent then checks the release notes below for public API changes and pushes any integration work onto this PR.

Android release notes (2.7.23 → 2.8.7)

2.8.7

Fixes

  • Fix prioritized preloading having no effect. The first preload batch contained every paywall the device was assigned to instead of only the prioritized campaign's paywalls, so those paywalls loaded alongside everything else at launch. The first batch now holds only the prioritized campaign's paywalls, and the batch that follows holds only the rest.

2.8.6

Enhancements

  • Adds PaywallOptions.presentationHost. Set it to PresentationHost.IN_WINDOW to show paywalls as an overlay in the presenting activity's own window instead of launching SuperwallPaywallActivity. Fullscreen, Drawer, Modal, Popup and Push styles, back handling, surveys, trial reminder notifications, permission requests and web checkout all work in this mode. It is meant for hosts that stop running while another activity covers them, such as Unity games, where a purchase controller written in the game's code could otherwise never answer. The default stays PresentationHost.ACTIVITY.

2.8.5

Enhancements

  • Adds the Customer Center, a self-service screen where users can view and restore their purchases, cancel or change a Google Play subscription, request a refund, manage a web subscription and contact support. Present it with Superwall.instance.presentCustomerCenter(), dismiss it with Superwall.instance.dismissCustomerCenter(), and configure it with SuperwallOptions.customerCenter.
  • Adds CustomerCenterDelegate and the customerCenter_open, customerCenter_close, customerCenter_action, customerCenter_surveyResponse and customerCenter_refundRequest events.

Fixes

  • Fix subscribers with an unexpired subscription being reported as inactive when Google Play fails to answer a purchase query, for example when the billing client isn't ready at launch. A query that succeeds and reports no purchases still deactivates straight away.
  • Fix subscribers being reported as inactive when Google Play returns an active purchase whose product no longer maps to an entitlement in config. A lost mapping is no longer treated as the subscription ending.
  • Fix purchases being refunded by Google Play for not being acknowledged when they did not complete through the billing flow callback, for example a pending purchase that settled while the app was closed, the app being killed mid-purchase, or a Play Store promo code. The AutomaticPurchaseController now acknowledges any unacknowledged purchase whenever it syncs the subscription status, including on launch, and retries acknowledgements that fail.
  • Fix register() never calling its handler, and every later placement stalling behind it, when a Google Play product query at launch was dropped. A request that found the billing client disconnected between being queued and running was discarded without a callback, leaving its products loading forever. Such requests are now re-queued until the client reconnects, a product query that Google Play never answers times out after 15 seconds, a disconnect with queued requests reconnects, and a second startConnection is no longer issued while one is in flight.
  • A paywall whose webview can't load, because every URL and retry has been used up or paywalls.timeoutAfter passed, is now dismissed as declined with the webViewFailedToLoad close reason, matching iOS. The register handler gets onDismiss and then the feature block for a non-gated placement, or onError for a gated one. Previously the paywall stayed on screen, and with timeoutAfter set the handler received onPresent followed by a bare onError while the paywall was still showing. A paywall that fails to load off-screen, for example during preload, reloads the next time it is presented.

2.8.4

Fixes

  • Fix bug where experiment ID would be stale among paywalls sharing experiments
  • Fix presentation_id changing mid-presentation when getPaywall() is called for a paywall that is already on screen. The id now rotates when a cached paywall is presented again, so every event between one paywall_open and the next carries the same id.
  • Fix trial reminder notifications being scheduled after a paywall purchase that did not start a free trial (for example a user who already used their trial and was charged immediately). Reminders are now only scheduled when a trial actually started, and the paywall receives the freeTrial_start message for every started trial, even when it has no trial reminders configured.

2.8.3

Fixes

  • Web purchase redemption now exposes the full checkout product in didRedeemLink, tracks freeTrial_start once per code, and schedules the active paywall's trial reminders from the checkout timestamp. Notification permission waits no longer block access or drop a late grant; ambiguous or already-elapsed reminders are skipped.
  • Fix multi-page paywalls only reporting the entry page view. paywall_open now waits for an in-flight template_variables send, so the runtime does not treat a late template payload as a fresh load and drop later page_views.
  • Fix an active paywall not being reopened after its webview process crashes and is recreated. Recovery cancels template work for the old document and sends the open after the replacement loads, only if the same presentation is still active.
  • Fix prices not showing when product/offers are fetched from cache
  • Fix video loading and playing in the background on preloaded paywalls
  • Fix a JSON null in placement parameters or user attributes reaching audience filters as the text "null", so a filter checking whether a field is null never matched.

2.8.2

Enhancements

  • Significantly improves paywall loading times, reducing memory and CPU footprint when preloading
  • Implicit placements that map to no campaign (e.g. app_launch, session_start) no longer occupy the presentation queue ahead of register() calls while waiting for entitlements.
  • Config refreshes now diff paywalls by cache key and only evict changed ones from the request cache, so unchanged preloaded paywalls stay warm across refreshes.
  • The loading shimmer no longer forces a software layer
  • Logs are now delivered on a dedicated background thread

Fixes

  • The popup presentation style's entrance animation no longer stretches to the paywall's configured loading delay, and the delay no longer postpones hiding the spinner after a purchase completes.
  • paywall_resourceLoad_fail events now report the failing resource's URL.
  • A SuperwallDelegate.handleLog implementation that throws no longer propagates the exception into whatever SDK code produced the log.

Potentially Breaking Changes

  • SuperwallDelegate.handleLog is now always called on a background thread. It could previously be called on any thread, including main, so implementations that touch UI directly must now dispatch to the main thread themselves.

2.8.1

Fixes

  • Paywalls with translations now render in the user's language on first paint instead of briefly showing the default language.
  • Paywall analytics events (paywall_open, paywall_page_view, paywall_close, etc.) now include a presentation_id, a unique identifier minted for each paywall presentation. Adds the previously-missing close_reason, cache_key, and build_id fields to these events, matching the data already sent by the iOS SDK.

2.8.0

Enhancements

  • ⚠️ Updates Google Play Billing Library from 8.0.0 to 9.1.0. See the Play Billing Library 9 migration guide for the full list of changes. ⚠️
  • Adds support for custom store products. Products configured on a custom store in the Superwall dashboard (e.g. Stripe or your own payment backend) can now be attached to paywalls: their metadata (price, subscription period, trial) is fetched from the Superwall API instead of Google Play and templated into the paywall like any other product. Purchases are routed through your PurchaseController, bypassing Google Play Billing entirely — check product.isCustomProduct to fulfill them via your own payment flow, and grant their entitlements with Superwall.instance.setSubscriptionStatus(...) on success. Requires configuring the SDK with a PurchaseController.
  • Adds a unified PurchaseController.purchase(activity, product: StoreProduct, basePlanId, offerId) method that handles both Google Play and custom store products. For Play products, the underlying ProductDetails are available via product.rawStoreProduct.
  • Custom purchases produce full transaction analytics (transaction_start/transaction_complete, subscriptionStart/freeTrialStart) with an SDK-generated transaction identifier exposed as StoreProduct.customTransactionId, and free-trial eligibility for custom products is derived from the customer's entitlement history.
  • Adds ApiStoreProduct, a product backed by Superwall API data, used for custom store products.

Breaking Changes

  • System back presses are now forwarded into the paywall as a back_button_input message instead of dismissing it directly: multi-page flows navigate back one page, and paywalls with nowhere to go back (root page, single page) close themselves through the standard manual-close path (Declined/ManualClose) — so single-page paywalls dismiss the same as before, from the app's perspective. When reroute_back_button is enabled in Paywall settings, the PaywallOptions.onBackPressed app callback keeps first refusal before the press is forwarded. Paywalls built on runtimes that predate back_button_input will ignore the press; this means that previously existing Multi-page paywalls, if republished, will now navigate back inside the paywall once republished.

  • Removes the deprecated SuperwallBillingFlowParams.Builder.setSkuDetails(SkuDetails). Billing Library 9 removes SkuDetails entirely, so this method can no longer exist. Use setProductDetailsParamsList(...) with ProductDetails instead.

  • Removes the unused internal com.superwall.sdk.billing.SWProduct, which wrapped the now-removed SkuDetails.

  • Internal purchase-history queries now resolve current purchases via QueryPurchasesParams — Billing Library 9 removes the purchase-history APIs (queryPurchaseHistoryAsync, QueryPurchaseHistoryParams).

  • Impact: if your app still calls the removed Billing Library APIs (SkuDetails, SkuDetailsParams, querySkuDetailsAsync, queryPurchaseHistoryAsync, BillingClient.SkuType, or the no-arg enablePendingPurchases()), it will no longer compile once it picks up Billing 9 through this SDK. Migrate those call sites to the ProductDetails APIs before upgrading; the migration guide has a mapping of every removed API to its replacement.

  • Please test your billing and purchasing flows before shipping this upgrade. Because the Billing Library is resolved to a single version across your app, upgrading Superwall also upgrades Billing for everything else that depends on it. If you use Google Play Billing directly, or another subscription provider such as RevenueCat, Adapty or Purchasely, make sure that provider's SDK supports Billing 9 and run through purchase, restore and subscription-status flows end to end.

  • If you use other subscription management libraries (RC, Purchasely, Adapty) and they do not support Play Billing 9: you can pin the Billing Client version to 8 in the following way.

    Add this to your app module's build.gradle.kts, outside the android { } block:

    configurations.all {
        resolutionStrategy.force("com.android.billingclient:billing:8.3.0")
    }

    Or in Groovy (build.gradle):

    configurations.all {
        resolutionStrategy.force 'com.android.billingclient:billing:8.3.0'
    }

    You can confirm which version you end up with via ./gradlew :app:dependencies --configuration releaseRuntimeClasspath — look for com.android.billingclient:billing:9.1.0 -> 8.3.0. Billing 8 still satisfies Google's August 31, 2026 requirement, so this is a safe interim state, and no Superwall functionality is lost: the SDK works on both 8.x and 9.x.

    Note that a -dontwarn com.android.billingclient.api.QueryPurchaseHistoryParams ProGuard rule is not a fix. It silences the R8 error and lets the build through, but then throws at runtime.

⚠️ Minimum SDK version raised to 23

Google Play Billing Library 9 requires Android 6.0 (API 23), so the SDK's minSdk is now 23 (previously 21). If your app's minSdk is below 23, you'll need to raise it to pick up this release — devices on Android 5.x will no longer receive app updates that include this SDK version.

Deprecations

  • Deprecates PurchaseController.purchase(activity, productDetails, basePlanId, offerId) in favor of the StoreProduct-based method above. Existing implementations keep working unchanged — the new method's default implementation routes Google Play purchases to the deprecated one — but purchasing custom store products requires implementing the new method.

@github-actions

Copy link
Copy Markdown
Author

The integration agent failed (run). This PR only contains the version bump — check the release notes above for public API changes by hand before merging.

@ianrumac ianrumac closed this Oct 20, 2026
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.

1 participant