Skip to content

Bump Android SDK to 2.10.0, iOS SDK to 4.19.1, release 0.4.1 - #22

Merged
ianrumac merged 7 commits into
native-sdk/android-2.9.0from
native-sdk/android-2.10.0
Nov 6, 2026
Merged

ianrumac merged 7 commits into
native-sdk/android-2.9.0from
native-sdk/android-2.10.0

Conversation

@github-actions

@github-actions github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

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

Opened automatically by native-sdk-bump.yml after superwall/Superwall-Android 2.10.0 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.8.7 → 2.10.0)

2.10.0

Breaking changes

  • The constructors of SDK-internal classes are now internal, because Superwall.configure builds them: AutomaticPurchaseController, TransactionManager, StoreManager, DeviceHelper, IdentityManager, LocalStorage, AppSessionManager, PaywallRequestManager, DeepLinkRouter, DebugManager, DebugView, TestMode and SWWebView. The public overload of SurveyManager.presentSurveyIfAvailable is removed, and ApiFactory.track no longer has a default body. None of these were documented API; configure the SDK with Superwall.configure and use Superwall.instance.

Enhancements

  • Adds LogScope.billing for the SDK's Google Play Billing logs. LogScope.storeKitManager is deprecated; setting it in SuperwallOptions.logging.scopes still enables the billing logs.

Fixes

  • Fixes purchases of custom store products from a paywall doing nothing. The paywall was never told the custom products' ids, so its purchase message had no product identifier and the SDK dropped it. Custom products are now sent to the paywall with their product identifier, and a purchase message without an identifier is resolved from the product's name on the paywall. A paywall message the SDK can't parse no longer drops the other messages sent with it.
  • Fixes the entitlements of a custom store product purchase (StoreProduct.isCustomProduct) not reaching the app until its next launch. After a successful custom purchase the SDK now asks Superwall for the user's entitlements in the background, as it already does after a Google Play purchase, so the entitlements your server reported for the purchase are picked up. It doesn't delay the purchase result or the paywall's dismissal. A background entitlements request whose user changed while it was in flight, after identify or reset, is now discarded instead of being applied to the new user.
  • Fixes transaction events for custom store products (StoreProduct.isCustomProduct) reporting store: "PLAY_STORE". They now report CUSTOM, so analytics no longer count purchases made through your own checkout as Google Play revenue.
  • Fixes no paywall opening for the rest of the session, with every register() failing with "Paywall Already Presented", after the paywall activity was finished while it was in the background. This happened when the app's task was cleared while the paywall was stopped, for example by opening a singleTask root activity from a deep link or notification. The paywall is now dismissed when its activity is finished in the background, and the handler gets onDismiss.
  • Fixes a misleading Error Evaluating JS error log, with java.lang.Exception: null, after every message the SDK posts to a paywall, such as a custom callback's result. Android reports a script's return value, and these scripts return nothing, so the log appeared even when the message was delivered. It is no longer logged in that case.
  • Fixes observer-mode purchases going untracked when SuperwallOptions.shouldObservePurchases is on and only one purchase is in progress. A completed purchase now tracks transaction_complete and refreshes the receipt, and a cancelled one tracks transaction_abandon; before, both were dropped with an error log. Observer-mode charts can show more transactions after this release.
  • Fixes observer-mode tracking stopping for the rest of the session when SuperwallOptions.shouldObservePurchases is on and Play reported a cancelled or failed purchase while no purchase was being observed. The purchase listener crashed on it; such results are now ignored.
  • Fixes trial reminders and other paywall notifications never being scheduled for a paywall embedded in the app's own Activity, such as one shown with PaywallComposable. Notifications were only scheduled when the paywall was shown in a SuperwallPaywallActivity or in-window; the SDK now asks the embedding Activity for the notification permission and schedules them there.
  • Fixes preloaded paywalls continuing to animate while off screen. A cached paywall's webview reported its page as visible, so its animations (Lottie, CSS, requestAnimationFrame) kept running unseen on the renderer thread every webview in the app shares, slowing the paywall on screen and the host app. A paywall is now paused once it has loaded while off screen, and resumed when it is presented.
  • Fixes CustomerInfo and entitlements naming the first configured base plan, with an expiry based on that plan's period, when a Google Play subscription has several base plans. The SDK now saves the product that was bought against its purchase token. When it can't know the plan, such as after a reinstall or for a purchase made before this fix, productId and latestProductId are the Play subscription ID and the expiry dates are null. Those users keep their access, and a plan that was recorded now also decides which entitlements the purchase unlocks.

Deprecations

  • Deprecates LogScope.storeKitManager in favour of LogScope.billing. Billing logs are now reported with the scope billing, so a SuperwallDelegate.handleLog implementation that matches the scope string "storeKitManager" should match "billing" instead.
  • Deprecates the unused iOS-port types com.superwall.sdk.billing.StoreProductType, StoreKit, StoreKitManagerInterface, ProductPurchaser, TransactionRestorer, Purchasing and TransactionVerifierFactory. They will be removed in a future release. GetProductsResponse is unchanged.

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_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.
  • Adds Superwall.instance.setPushToken(token) to register the device's Firebase Cloud Messaging token with Superwall, so Superwall can send it push notifications. Call it from your FirebaseMessagingService.onNewToken and with FirebaseMessaging.getInstance().token at startup, after Superwall.configure: Superwall.instance throws before it, so if onNewToken can run before your app configures Superwall, keep the token and pass it in once you have. It's safe to call on every launch: an unchanged token is only sent again once a day. The SDK has no Firebase dependency and doesn't request notification permission itself. Along with the token, Superwall receives whether the app can post notifications, which is checked again whenever the app comes to the foreground. The token only travels to Superwall's servers: it doesn't appear in SuperwallDelegate.handleSuperwallEvent, SuperwallDelegate.handleLog, user attributes or audience filters. Nothing is sent until Superwall notifications are turned on for your app, and nothing is sent while eventTrackingBehavior is NONE.
  • Adds Superwall.instance.optOutOfNotifications() and optInToNotifications() to stop and resume Superwall push notifications for the device. The choice is remembered across launches, reset() and identify(userId).
  • Adds Superwall.instance.handleNotificationOpen(intent) and handleNotificationOpen(data) to measure opens of the notifications Superwall sends. Call them only when the user taps a notification, never from onMessageReceived for a delivery, which would count deliveries as opens. Pass the intent that opened your activity from the tap, or the tapped notification's data map; notifications Superwall didn't send are ignored. The intent works as is for notifications FCM displays itself, whose tap intent carries the data keys as extras; if your app builds the notification in onMessageReceived, copy the sw data value into the extras of the tap PendingIntent.

Fixes

  • Fix a failed /events request logging every queued event's parameters to SuperwallDelegate.handleLog. It now logs the event count and names only. A cache entry that can't be decoded no longer logs its stored contents either.
  • 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.
  • Fixes reset() and switching users deleting every top-level file in the host app's cache directory. Reset now only clears Superwall's own user-scoped storage.
  • Fixes the previous user's experiment assignments, paywall view counts, customer info, transaction history and survey assignment carrying over to the next user after reset() or identify() with a different user. The cached config and enrichment are kept.
  • Fixes storage writes not being atomic: a process kill mid-write could empty a stored value (e.g. the user's alias or seed). Writes now go through AtomicFile, and the in-memory cache is thread-safe.
  • Fixes config retries waiting forever on devices connected over Ethernet, a VPN or any network other than Wi-Fi or cellular. Any network with internet access now counts, and the wait is capped at 30 seconds.
  • Fixes one product ID that Google Play doesn't return (e.g. not live yet) making every later product load fail until the app was restarted. Missing products are left out of the result and asked for again after 5 minutes.
  • Fixes renewing subscribers being reported with an EXPIRED latestSubscriptionState and a wrong expiry date (the first period's end) after their first renewal. Google Play doesn't give the client an expiry date, grace period or account hold, so the device no longer guesses them: a purchased subscription is SUBSCRIBED, and a pending purchase is no longer reported as revoked or in a grace period.
  • Fixes observer mode dropping successful purchases and, after a cancelled or failed purchase it wasn't tracking, ignoring every later purchase. Each observed purchase is handled once, whether it's reported by Google Play or through Superwall.instance.observe.
  • Fixes a failed Google Play read (e.g. billing still connecting at launch) being treated as "no purchases": stored receipts and customer info are no longer overwritten, and latestSubscriptionState is no longer set to EXPIRED. Play subscribers stay active through a failed read for up to one subscription period after Play last confirmed their purchase.
  • After reset() or switching users, the new user's purchase history and device customer info are rebuilt from Google Play straight away instead of staying empty until the next purchase or restore.
  • Fixes the SDK connecting two Google Play billing clients when no PurchaseController is set, which processed every purchase twice. AutomaticPurchaseController now uses the SDK's single billing connection.
  • Fixes a blank screen when the app's process is recreated with a paywall on top and Superwall is configured after Application.onCreate. The paywall activity now closes.
  • Fixes PaywallComposable not loading a new paywall when its placement changes, and crashing when it isn't hosted in an Activity.
  • The restore-failed alert and PaywallComposable's default error are now localized. Text you set on PaywallOptions.restoreFailed is shown as is.

Deprecations

  • Deprecates PaywallOptions.useCachedTemplates. It has no effect: on-device caching is configured per paywall in the Superwall dashboard. It will be removed in the next major version.

Breaking changes

  • AutomaticPurchaseController's constructor now takes the SDK's Billing instead of a Context and a billing client factory. Apps that don't construct it themselves are unaffected.

2.8.8

Enhancements

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

claude and others added 2 commits November 6, 2026 11:21
SuperwallKit presents a paywall in a window of its own, whose root allowed
every orientation, so Screen.autorotateTo* was never consulted while a
paywall was up. superwall/Superwall-iOS#568 makes that window follow the
app's own view controller. Require 4.19.1, the first release it can ship
in, so games get the fix without pinning it themselves.

Podfiles kept by an Append build are moved off any requirement an earlier
version of this package wrote, not just `~> 4.0`. Those are listed by
their version part only, so native-sdk-bump.yml's rewrite of the current
pod line leaves them alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CR7gAmtFzGVaH1B6Mxxrga
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor 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.

Require the SuperwallKit that keeps paywalls to the game's orientations
@ianrumac
ianrumac changed the base branch from main to native-sdk/android-2.9.0 November 6, 2026 19:37
…ase 0.4.1

The iOS harness now builds against exactly SuperwallKit 4.19.1, matching the
Podfile's >= 4.19.1 requirement. superwall-android 2.10.0 deprecates
LogScope.storeKitManager in favour of LogScope.billing, so the bridge maps to
the new scope.
@ianrumac ianrumac changed the title Bump Android SDK to 2.10.0 Bump Android SDK to 2.10.0, iOS SDK to 4.19.1, release 0.4.1 Nov 6, 2026
@ianrumac

ianrumac commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

Added on top of the bot bump (the integration agent failed, so I went through the 2.8.7 → 2.10.0 notes by hand):

  • Merged main, which already requires SuperwallKit >= 4.19.1, < 5.0 in the Podfile.
  • iOS: ci~/ios-harness/Package.swift now pins Superwall-iOS to exactly 4.19.1 (was from: 4.12.10). The bridge builds against it locally with xcodebuild.
  • Android: storekitmanager now maps to LogScope.billing because 2.10.0 deprecates LogScope.storeKitManager. Nothing else the bridge calls changed. It doesn't construct AutomaticPurchaseController or any of the classes that became internal. Gradle isn't installed locally, so CI is the first Android compile.
  • Package version is 0.4.1 and [Unreleased] is cut to [0.4.1].

SuperwallKit 4.18 raised its deployment target to iOS 15, so a game targeting
a lower version failed pod install. The Podfile now uses at least iOS 15 and
the build warns. EventType gains the teleport and customer center events the
native SDKs now send.
…ative-sdk/android-2.10.0

# Conflicts:
#	CHANGELOG.md
#	Plugins/Android/SuperwallSDK.androidlib/build.gradle
@ianrumac
ianrumac merged commit 12df495 into native-sdk/android-2.9.0 Nov 6, 2026
3 of 4 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