Skip to content

Releases: superwall/Superwall-Android

2.9.0

Choose a tag to compare

@github-actions github-actions released this 29 Oct 18:11
5e8ef2f

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_match event. The resulting acquisition_* 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 after identify or reset. 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 while eventTrackingBehavior is NONE and runs if tracking is turned back on. On the first launch, a paywall whose audiences use acquisition_* 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.adConsent and Superwall.instance.adConsent for reporting the user's ad measurement consent (AdConsent.Custom(adUserData, adPersonalization), each an AdConsentStatus of Granted or Denied). It is sent as the adUserDataConsent and adPersonalizationConsent device attributes and forwarded with the conversions Superwall uploads to Google Ads and Meta. While adConsent is AdConsent.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 new adConsentSource device attribute (developer, tcf or default). Both are reported as denied when eventTrackingBehavior is NONE.
  • 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). Its ProductReplacement carries the mode and the old product's ID and purchase token, so a custom PurchaseController can perform the replacement. The default implementation ignores it and calls the existing purchase method.

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, as SuperwallPaywallActivity does, 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_complete was only sent to the paywall for subscriptions.
  • Fixes getProducts() (and other network-backed suspend APIs) not being main-safe: network requests now always run on Dispatchers.IO, so the /products fallback no longer fails with NetworkOnMainThreadException when called from the main thread.

2.8.8

Choose a tag to compare

@github-actions github-actions released this 22 Oct 21:20
2e87185

Enhancements

  • Adds AIRBRIDGE_ID as an AttributionProvider (airbridgeId), for the Airbridge Device ID from Airbridge.fetchDeviceUUID.

2.8.7

Choose a tag to compare

@github-actions github-actions released this 19 Oct 16:43
60698df

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

Choose a tag to compare

@github-actions github-actions released this 19 Oct 14:25
15dd511

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

Choose a tag to compare

@github-actions github-actions released this 09 Oct 07:09
f70cb31

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

Choose a tag to compare

@github-actions github-actions released this 22 Sep 11:58
281a862

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

Choose a tag to compare

@github-actions github-actions released this 11 Sep 17:07
0322ce9

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

Choose a tag to compare

@github-actions github-actions released this 31 Aug 13:50
c473e3c

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

Choose a tag to compare

@github-actions github-actions released this 11 Aug 15:37
2f32966

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.7.24

Choose a tag to compare

@ianrumac ianrumac released this 11 Aug 13:51
cee210e

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 a presentation_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-missing close_reason, cache_key, and build_id fields to these events, matching the data already sent by the iOS SDK.