Repository navigation
Releases: superwall/Superwall-Android
Releases · superwall/Superwall-Android
Release list
2.9.0
Enhancements
- Adds install attribution matching. If the app has performance marketing integrations set up on the Superwall dashboard, the SDK matches the install to the ad click that led to it and tracks an
attribution_matchevent. The resultingacquisition_*attributes are added to user attributes, so they can be used as breakdowns and filters in charts and audiences, and they carry over to new users afteridentifyorreset. The match runs once per install, within 7 days of install, only when the dashboard has turned it on for the app, and never blocks startup. It uses the Play install referrer's click id when present. It is skipped whileeventTrackingBehaviorisNONEand runs if tracking is turned back on. On the first launch, a paywall whose audiences useacquisition_*attributes waits up to 2 seconds for a match that's still running. - Adds best-effort public IPv4 and IPv6 device attributes for apps using the Superwall MMP, and the IPv4 attribute for apps that set an AppsFlyer ID. Apps that use the MMP or set an AppsFlyer ID should declare IP address collection in their Play Console data safety form.
- Adds
SuperwallOptions.adConsentandSuperwall.instance.adConsentfor reporting the user's ad measurement consent (AdConsent.Custom(adUserData, adPersonalization), each anAdConsentStatusofGrantedorDenied). It is sent as theadUserDataConsentandadPersonalizationConsentdevice attributes and forwarded with the conversions Superwall uploads to Google Ads and Meta. WhileadConsentisAdConsent.Unspecified, the default, the SDK uses the consent stored by an IAB TCF consent banner when GDPR applies, and otherwise defaults to granted; apps with users in the EEA, UK or Switzerland that don't use a TCF banner should set it from their consent flow. Where the values came from is reported in the newadConsentSourcedevice attribute (developer,tcfordefault). Both are reported as denied wheneventTrackingBehaviorisNONE. - Adds subscription replacement. When a paywall's Purchase action is set to replace an existing subscription, the purchase upgrades, downgrades or switches the user's active Google Play subscription that shares an entitlement with the new product, instead of buying a second one. The replacement mode (store default, charge the prorated difference now, or charge the full price now) maps to Google Play's
SubscriptionUpdateParams. Users without such a subscription make a normal purchase. - Adds
PurchaseController.purchase(activity, product, basePlanId, offerId, replacement). ItsProductReplacementcarries the mode and the old product's ID and purchase token, so a customPurchaseControllercan perform the replacement. The default implementation ignores it and calls the existingpurchasemethod.
Fixes
- Fix web checkout codes passed through the Play install referrer never being redeemed. A code is now redeemed once, on the first launch after install.
- Fixes a band of the host window showing beside the display cutout around a Fullscreen, Push or no-animation paywall shown with
PresentationHost.IN_WINDOW. The in-window host padded the paywall for the cutout as well as the system bars; it now pads for the system bars only, asSuperwallPaywallActivitydoes, and the paywall clears the cutout with its CSS safe-area insets. - Fixes paywalls not running post-purchase actions (e.g. navigating to a thank-you page) after a one-time product purchase, because
transaction_completewas only sent to the paywall for subscriptions. - Fixes
getProducts()(and other network-backed suspend APIs) not being main-safe: network requests now always run onDispatchers.IO, so the/productsfallback no longer fails withNetworkOnMainThreadExceptionwhen called from the main thread.
2.8.8
Enhancements
- Adds
AIRBRIDGE_IDas anAttributionProvider(airbridgeId), for the Airbridge Device ID fromAirbridge.fetchDeviceUUID.
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 toPresentationHost.IN_WINDOWto show paywalls as an overlay in the presenting activity's own window instead of launchingSuperwallPaywallActivity. 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 staysPresentationHost.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 withSuperwall.instance.dismissCustomerCenter(), and configure it withSuperwallOptions.customerCenter. - Adds
CustomerCenterDelegateand thecustomerCenter_open,customerCenter_close,customerCenter_action,customerCenter_surveyResponseandcustomerCenter_refundRequestevents.
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
AutomaticPurchaseControllernow 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 secondstartConnectionis 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.timeoutAfterpassed, is now dismissed as declined with thewebViewFailedToLoadclose reason, matching iOS. The register handler getsonDismissand then the feature block for a non-gated placement, oronErrorfor a gated one. Previously the paywall stayed on screen, and withtimeoutAfterset the handler receivedonPresentfollowed by a bareonErrorwhile 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_idchanging mid-presentation whengetPaywall()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 onepaywall_openand 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_startmessage 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, tracksfreeTrial_startonce 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_opennow waits for an in-flighttemplate_variablessend, so the runtime does not treat a late template payload as a fresh load and drop laterpage_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 ofregister()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_failevents now report the failing resource's URL.- A
SuperwallDelegate.handleLogimplementation that throws no longer propagates the exception into whatever SDK code produced the log.
Potentially Breaking Changes
SuperwallDelegate.handleLogis 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 apresentation_id, a unique identifier minted for each paywall presentation. Adds the previously-missingclose_reason,cache_key, andbuild_idfields to these events, matching the data already sent by the iOS SDK.
2.7.24
2.7.24
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 apresentation_id, a unique identifier minted for each paywall presentation. Previously this field was always empty on Android, which broke dashboard funnels that correlate a paywall's page views into a single session. Also adds the previously-missingclose_reason,cache_key, andbuild_idfields to these events, matching the data already sent by the iOS SDK.