From 9144ecc968875a61c3ad2bd168fedee183886f75 Mon Sep 17 00:00:00 2001 From: Lever Bot Date: Wed, 15 Apr 2026 16:08:32 +0000 Subject: [PATCH 1/2] feat(flutter): update for 2.4.12 --- content/docs/flutter/changelog.mdx | 9 +++++++++ content/docs/flutter/index.mdx | 2 +- content/docs/flutter/sdk-reference/PaywallOptions.mdx | 8 ++++++++ content/docs/flutter/sdk-reference/index.mdx | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/content/docs/flutter/changelog.mdx b/content/docs/flutter/changelog.mdx index 327c7751..e93b9e49 100644 --- a/content/docs/flutter/changelog.mdx +++ b/content/docs/flutter/changelog.mdx @@ -7,6 +7,15 @@ description: "Release notes for the Superwall Flutter SDK" The changelog for `Superwall`. Also see the [releases](https://github.com/superwall/Superwall-Flutter/releases) on GitHub. +## 2.4.12 + +### Enhancements +- Updates Android SDK to 2.7.11 [View Android SDK release notes](https://github.com/superwall/Superwall-Android/releases/tag/2.7.11). +- Updates iOS SDK to 4.14.2 [View iOS SDK release notes](https://github.com/superwall/Superwall-iOS/releases/tag/4.14.2). +- Adds `preloadDeviceOverrides` option to `PaywallOptions` to override `shouldPreload` per device tier (Android only) +- Exports `PresentationResult`, `StoreTransaction`, `TransactionProduct` from the public package +- Fixes `PurchaserInfo.storeIdentifiers` leaking the internal Pigeon type instead of the public `StoreIdentifiers` sealed class + ## 2.4.11 ### Enhancements diff --git a/content/docs/flutter/index.mdx b/content/docs/flutter/index.mdx index ef361056..c83db906 100644 --- a/content/docs/flutter/index.mdx +++ b/content/docs/flutter/index.mdx @@ -34,4 +34,4 @@ If you have feedback on any of our docs, please leave a rating and message at th If you have any issues with the SDK, please [open an issue on GitHub](https://github.com/superwall/superwall-flutter/issues). - \ No newline at end of file + \ No newline at end of file diff --git a/content/docs/flutter/sdk-reference/PaywallOptions.mdx b/content/docs/flutter/sdk-reference/PaywallOptions.mdx index 4f29c3c2..618de70d 100644 --- a/content/docs/flutter/sdk-reference/PaywallOptions.mdx +++ b/content/docs/flutter/sdk-reference/PaywallOptions.mdx @@ -17,6 +17,7 @@ class PaywallOptions { RestoreFailed restoreFailed = RestoreFailed(); bool shouldShowPurchaseFailureAlert = true; bool shouldPreload = true; + Map preloadDeviceOverrides = const {}; bool automaticallyDismiss = true; TransactionBackgroundView transactionBackgroundView = TransactionBackgroundView.spinner; bool shouldShowWebRestorationAlert = true; @@ -32,6 +33,8 @@ class RestoreFailed { } enum TransactionBackgroundView { spinner, none } + +enum DeviceTier { ultraLow, low, mid, high, ultraHigh, unknown } ``` ## Parameters @@ -72,6 +75,11 @@ enum TransactionBackgroundView { spinner, none } description: "Preloads and caches trigger paywalls and products during SDK initialization.", default: "true", }, + preloadDeviceOverrides: { + type: "Map", + description: "Android only. Per-device-tier overrides for `shouldPreload`. Only the tiers you specify are overridden; the rest fall back to `shouldPreload`. Use this to disable preloading on low-end devices while keeping it enabled on mid/high-end devices.", + default: "const {}", + }, automaticallyDismiss: { type: "bool", description: "Automatically dismisses the paywall on successful purchase or restore.", diff --git a/content/docs/flutter/sdk-reference/index.mdx b/content/docs/flutter/sdk-reference/index.mdx index 9ff64d81..a2c2a991 100644 --- a/content/docs/flutter/sdk-reference/index.mdx +++ b/content/docs/flutter/sdk-reference/index.mdx @@ -15,4 +15,4 @@ If you have feedback on any of our docs, please leave a rating and message at th If you have any issues with the SDK, please [open an issue on GitHub](https://github.com/superwall/superwall-flutter/issues). - \ No newline at end of file + \ No newline at end of file From 70700f868c0eb170dd8b4584e79dbaa8ebabaf79 Mon Sep 17 00:00:00 2001 From: Duncan Crawbuck Date: Wed, 15 Apr 2026 18:56:21 -0700 Subject: [PATCH 2/2] feat(flutter): update for 2.4.12 --- .../linking-membership-to-iOS-app.mdx | 4 +- .../post-checkout-redirecting.mdx | 46 +++--- .../guides/web-checkout/using-revenuecat.mdx | 34 ++++- content/docs/flutter/meta.json | 6 +- content/docs/flutter/quickstart/install.mdx | 4 +- .../sdk-reference/RedemptionResult.mdx | 137 ++++++++++++++++++ .../sdk-reference/StoreIdentifiers.mdx | 88 +++++++++++ .../sdk-reference/StoreTransaction.mdx | 108 ++++++++++++++ .../sdk-reference/TransactionProduct.mdx | 36 +++++ content/shared/using-superwall-delegate.mdx | 2 +- 10 files changed, 434 insertions(+), 31 deletions(-) create mode 100644 content/docs/flutter/sdk-reference/RedemptionResult.mdx create mode 100644 content/docs/flutter/sdk-reference/StoreIdentifiers.mdx create mode 100644 content/docs/flutter/sdk-reference/StoreTransaction.mdx create mode 100644 content/docs/flutter/sdk-reference/TransactionProduct.mdx diff --git a/content/docs/flutter/guides/web-checkout/linking-membership-to-iOS-app.mdx b/content/docs/flutter/guides/web-checkout/linking-membership-to-iOS-app.mdx index 88efebb8..73afb865 100644 --- a/content/docs/flutter/guides/web-checkout/linking-membership-to-iOS-app.mdx +++ b/content/docs/flutter/guides/web-checkout/linking-membership-to-iOS-app.mdx @@ -18,7 +18,7 @@ If you're using a custom PurchaseController (with either iOS StoreKit or Android Here's an example of how you might do this: ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; Future syncSubscriptionStatus() async { // Get the device entitlements from your purchase controller @@ -69,7 +69,7 @@ Future> getDeviceEntitlements() async { In addition to syncing the subscription status when purchasing and restoring, you'll need to sync it whenever `didRedeemLink(result)` is called: ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; class MySuperwallDelegate extends SuperwallDelegate { @override diff --git a/content/docs/flutter/guides/web-checkout/post-checkout-redirecting.mdx b/content/docs/flutter/guides/web-checkout/post-checkout-redirecting.mdx index 8d4272c2..283e4421 100644 --- a/content/docs/flutter/guides/web-checkout/post-checkout-redirecting.mdx +++ b/content/docs/flutter/guides/web-checkout/post-checkout-redirecting.mdx @@ -71,7 +71,7 @@ When your app opens via the deep link, we will call the delegate method `willRed At this point, you might wish to display a loading indicator in your app so the user knows that the purchase is being redeemed. ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; import 'package:flutter/material.dart'; class MySuperwallDelegate extends SuperwallDelegate { @@ -88,20 +88,20 @@ You can manually dismiss the paywall at this point if needed, but note that the ### didRedeemLink -After receiving a response from the network, we will call `didRedeemLink(result)` with the result of redeeming the code. The result is a `RedemptionResult` which can be one of: +After receiving a response from the network, we will call `didRedeemLink(result)` with the result of redeeming the code. The result is a `RedemptionResult` subclass, which can be one of: -- `RedemptionResult` with `type: RedemptionResultType.success`: The redemption succeeded and contains information about the redeemed code. -- `RedemptionResult` with `type: RedemptionResultType.error`: An error occurred while redeeming. You can check the error message via the error parameter. -- `RedemptionResult` with `type: RedemptionResultType.expiredCode`: The code expired and contains information about whether a redemption email has been resent and an optional obfuscated email address. -- `RedemptionResult` with `type: RedemptionResultType.invalidCode`: The code that was redeemed was invalid. -- `RedemptionResult` with `type: RedemptionResultType.expiredSubscription`: The subscription that the code redeemed has expired. +- `RedemptionResultSuccess`: The redemption succeeded and contains information about the redeemed code. +- `RedemptionResultError`: An error occurred while redeeming. You can check the error message via the error parameter. +- `RedemptionResultExpiredCode`: The code expired and contains information about whether a redemption email has been resent and an optional obfuscated email address. +- `RedemptionResultInvalidCode`: The code that was redeemed was invalid. +- `RedemptionResultExpiredSubscription`: The subscription that the code redeemed has expired. -On network failure, the SDK will retry up to 6 times before returning an `error` `RedemptionResult` in `didRedeemLink(result)`. +On network failure, the SDK will retry up to 6 times before returning a `RedemptionResultError` in `didRedeemLink(result)`. Here, you should remove any loading UI you added in `willRedeemLink` and show a message to the user based on the result. If a paywall is presented, it will be dismissed automatically. ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; import 'package:flutter/material.dart'; class MySuperwallDelegate extends SuperwallDelegate { @@ -111,35 +111,45 @@ class MySuperwallDelegate extends SuperwallDelegate { @override void didRedeemLink(RedemptionResult result) { - switch (result.type) { - case RedemptionResultType.expiredCode: + switch (result) { + case RedemptionResultExpiredCode(): _showMessage('Expired Link'); - print('[!] code expired: ${result.code}, ${result.expiredInfo}'); + print('[!] code expired: ${result.code}, ${result.info}'); break; - case RedemptionResultType.error: - _showMessage(result.error?.message ?? 'An error occurred'); + case RedemptionResultError(): + _showMessage(result.error.message); print('[!] error: ${result.code}, ${result.error}'); break; - case RedemptionResultType.expiredSubscription: + case RedemptionResultExpiredSubscription(): _showMessage('Expired Subscription'); print('[!] expired subscription: ${result.code}, ${result.redemptionInfo}'); break; - case RedemptionResultType.invalidCode: + case RedemptionResultInvalidCode(): _showMessage('Invalid Link'); print('[!] invalid code: ${result.code}'); break; - case RedemptionResultType.success: - final email = result.redemptionInfo?.purchaserInfo?.email; + case RedemptionResultSuccess(): + final purchaserInfo = result.redemptionInfo.purchaserInfo; + final email = purchaserInfo.email; if (email != null) { Superwall.shared.setUserAttributes({'email': email}); _showMessage('Welcome, $email!'); } else { _showMessage('Welcome!'); } + + switch (purchaserInfo.storeIdentifiers) { + case StripeStoreIdentifiers(subscriptionIds: final ids): + print('[!] redeemed Stripe subscriptions: $ids'); + case PaddleStoreIdentifiers(subscriptionIds: final ids): + print('[!] redeemed Paddle subscriptions: $ids'); + case UnknownStoreIdentifiers(store: final store): + print('[!] redeemed purchase from $store'); + } break; } } diff --git a/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx b/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx index 19eb70d1..39c136f1 100644 --- a/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx +++ b/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx @@ -20,7 +20,7 @@ associate the RevenueCat customer with the Stripe subscription IDs returned from by using the `didRedeemLink()` delegate method: ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; import 'package:purchases_flutter/purchases_flutter.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; @@ -39,9 +39,18 @@ class MySuperwallDelegate extends SuperwallDelegate { print('[!] didRedeemLink: $result'); // Send Stripe IDs to RevenueCat to link purchases to the customer - // Get a list of subscription ids tied to the customer - final stripeSubscriptionIds = result.stripeSubscriptionIds; - if (stripeSubscriptionIds == null || stripeSubscriptionIds.isEmpty) { + if (result is! RedemptionResultSuccess) { + return; + } + + final storeIdentifiers = result.redemptionInfo.purchaserInfo.storeIdentifiers; + if (storeIdentifiers is! StripeStoreIdentifiers) { + return; + } + + // Get a list of Stripe subscription ids tied to the customer + final stripeSubscriptionIds = storeIdentifiers.subscriptionIds; + if (stripeSubscriptionIds.isEmpty) { return; } @@ -152,8 +161,19 @@ class MySuperwallDelegate extends SuperwallDelegate { } Future _handleRedemption(RedemptionResult result) async { - final stripeSubscriptionIds = result.stripeSubscriptionIds; - if (stripeSubscriptionIds == null || stripeSubscriptionIds.isEmpty) { + if (result is! RedemptionResultSuccess) { + print('[!] Redemption did not succeed'); + return; + } + + final storeIdentifiers = result.redemptionInfo.purchaserInfo.storeIdentifiers; + if (storeIdentifiers is! StripeStoreIdentifiers) { + print('[!] Redemption did not come from Stripe'); + return; + } + + final stripeSubscriptionIds = storeIdentifiers.subscriptionIds; + if (stripeSubscriptionIds.isEmpty) { print('[!] No Stripe subscription IDs found'); return; } @@ -222,5 +242,5 @@ Remember to add the `http` package to your `pubspec.yaml`: dependencies: http: ^1.1.0 purchases_flutter: ^6.0.0 - superwall_flutter: ^1.0.0 + superwallkit_flutter: ^2.4.12 ``` diff --git a/content/docs/flutter/meta.json b/content/docs/flutter/meta.json index 722313c3..18ee0308 100644 --- a/content/docs/flutter/meta.json +++ b/content/docs/flutter/meta.json @@ -45,6 +45,10 @@ "sdk-reference/PaywallOptions", "sdk-reference/PurchaseController", "sdk-reference/PresentationResult", + "sdk-reference/RedemptionResult", + "sdk-reference/StoreIdentifiers", + "sdk-reference/StoreTransaction", + "sdk-reference/TransactionProduct", "sdk-reference/CustomerInfo", "sdk-reference/SubscriptionTransaction", "sdk-reference/NonSubscriptionTransaction", @@ -65,4 +69,4 @@ "[Troubleshooting](https://support.superwall.com/articles/6999598520-troubleshooting-flutter-sdk)", "[Example App](https://github.com/superwall/Superwall-Flutter/tree/main/example)" ] -} \ No newline at end of file +} diff --git a/content/docs/flutter/quickstart/install.mdx b/content/docs/flutter/quickstart/install.mdx index 30510ada..4ec88aca 100644 --- a/content/docs/flutter/quickstart/install.mdx +++ b/content/docs/flutter/quickstart/install.mdx @@ -12,7 +12,7 @@ To use Superwall in your Flutter project, add `superwallkit_flutter` as a depend ```yaml dependencies: - superwallkit_flutter: ^2.0.5 + superwallkit_flutter: ^2.4.12 ``` After adding the dependency, run `dart pub get` in your terminal to fetch the package. @@ -83,4 +83,4 @@ plugins { To find the latest compatible versions, you can always check the [Gradle Plugin Release Notes](https://developer.android.com/build/releases/gradle-plugin). -**And you're done!** Now you're ready to configure the SDK 👇 \ No newline at end of file +**And you're done!** Now you're ready to configure the SDK 👇 diff --git a/content/docs/flutter/sdk-reference/RedemptionResult.mdx b/content/docs/flutter/sdk-reference/RedemptionResult.mdx new file mode 100644 index 00000000..c276fb1e --- /dev/null +++ b/content/docs/flutter/sdk-reference/RedemptionResult.mdx @@ -0,0 +1,137 @@ +--- +title: "RedemptionResult" +description: "Result types returned when the Flutter SDK redeems a web checkout link." +--- + +## Purpose + +Represents the result passed to [`didRedeemLink()`](/flutter/sdk-reference/SuperwallDelegate) after the SDK handles a web checkout redemption link. + +## Signature + +```dart +sealed class RedemptionResult {} + +class RedemptionResultSuccess extends RedemptionResult { + final String code; + final RedemptionInfo redemptionInfo; +} + +class RedemptionResultError extends RedemptionResult { + final String code; + final ErrorInfo error; +} + +class RedemptionResultExpiredCode extends RedemptionResult { + final String code; + final ExpiredCodeInfo info; +} + +class RedemptionResultInvalidCode extends RedemptionResult { + final String code; +} + +class RedemptionResultExpiredSubscription extends RedemptionResult { + final String code; + final RedemptionInfo redemptionInfo; +} +``` + +## Types + + + +## Success Data + +", + description: "Entitlements granted by the redeemed purchase.", + required: true, + }, + "PurchaserInfo.appUserId": { + type: "String", + description: "The app user ID of the purchaser.", + required: true, + }, + "PurchaserInfo.email": { + type: "String?", + description: "The purchaser email address, when available.", + }, + "PurchaserInfo.storeIdentifiers": { + type: "StoreIdentifiers", + typeDescriptionLink: "/flutter/sdk-reference/StoreIdentifiers", + description: "Public store identifier details for the redeemed purchase.", + required: true, + }, + }} +/> + +## Usage + +```dart +void didRedeemLink(RedemptionResult result) { + switch (result) { + case RedemptionResultSuccess(redemptionInfo: final info): + final purchaser = info.purchaserInfo; + print('Redeemed for ${purchaser.appUserId}'); + break; + case RedemptionResultError(error: final error): + print('Redemption failed: ${error.message}'); + break; + case RedemptionResultExpiredCode(info: final info): + print('Code expired; resent email: ${info.resent}'); + break; + case RedemptionResultInvalidCode(): + print('Invalid code'); + break; + case RedemptionResultExpiredSubscription(): + print('Expired subscription'); + break; + } +} +``` + +## Related + +- [`StoreIdentifiers`](/flutter/sdk-reference/StoreIdentifiers) +- [`SuperwallDelegate`](/flutter/sdk-reference/SuperwallDelegate) +- [Post-Checkout Redirecting](/flutter/guides/web-checkout/post-checkout-redirecting) diff --git a/content/docs/flutter/sdk-reference/StoreIdentifiers.mdx b/content/docs/flutter/sdk-reference/StoreIdentifiers.mdx new file mode 100644 index 00000000..2a0cbba7 --- /dev/null +++ b/content/docs/flutter/sdk-reference/StoreIdentifiers.mdx @@ -0,0 +1,88 @@ +--- +title: "StoreIdentifiers" +description: "Store-specific identifiers returned with successful Flutter web checkout redemptions." +--- + +## Purpose + +Identifies the store that fulfilled a redeemed web checkout purchase. Access this from `RedemptionResultSuccess.redemptionInfo.purchaserInfo.storeIdentifiers`. + +## Signature + +```dart +sealed class StoreIdentifiers {} + +class StripeStoreIdentifiers extends StoreIdentifiers { + final String customerId; + final List subscriptionIds; +} + +class PaddleStoreIdentifiers extends StoreIdentifiers { + final String customerId; + final List subscriptionIds; +} + +class UnknownStoreIdentifiers extends StoreIdentifiers { + final String store; + final Map additionalInfo; +} +``` + +## Values + + + +## Usage + +```dart +void didRedeemLink(RedemptionResult result) { + if (result is! RedemptionResultSuccess) { + return; + } + + final identifiers = result.redemptionInfo.purchaserInfo.storeIdentifiers; + + switch (identifiers) { + case StripeStoreIdentifiers( + customerId: final customerId, + subscriptionIds: final subscriptionIds, + ): + print('Stripe customer: $customerId'); + print('Stripe subscriptions: $subscriptionIds'); + break; + case PaddleStoreIdentifiers( + customerId: final customerId, + subscriptionIds: final subscriptionIds, + ): + print('Paddle customer: $customerId'); + print('Paddle subscriptions: $subscriptionIds'); + break; + case UnknownStoreIdentifiers( + store: final store, + additionalInfo: final info, + ): + print('Unknown store: $store, $info'); + break; + } +} +``` + +## Related + +- [`RedemptionResult`](/flutter/sdk-reference/RedemptionResult) +- [Using RevenueCat](/flutter/guides/web-checkout/using-revenuecat) diff --git a/content/docs/flutter/sdk-reference/StoreTransaction.mdx b/content/docs/flutter/sdk-reference/StoreTransaction.mdx new file mode 100644 index 00000000..cb19bfe1 --- /dev/null +++ b/content/docs/flutter/sdk-reference/StoreTransaction.mdx @@ -0,0 +1,108 @@ +--- +title: "StoreTransaction" +description: "A public wrapper around store transaction data in Flutter SDK events." +--- + +## Purpose + +Represents store transaction metadata attached to Superwall events and restore events. + +## Signature + +```dart +class StoreTransaction { + final String configRequestId; + final String appSessionId; + final DateTime? transactionDate; + final String originalTransactionIdentifier; + final String? storeTransactionId; + final DateTime? originalTransactionDate; + final String? webOrderLineItemID; + final String? appBundleId; + final String? subscriptionGroupId; + final bool? isUpgraded; + final DateTime? expirationDate; + final String? offerId; + final DateTime? revocationDate; +} +``` + +## Properties + + + +## Usage + +```dart +void handleSuperwallEvent(SuperwallEventInfo eventInfo) { + final transaction = eventInfo.event.transaction; + if (transaction == null) { + return; + } + + print('Transaction: ${transaction.storeTransactionId}'); + print('Original ID: ${transaction.originalTransactionIdentifier}'); +} +``` + +## Related + +- [`SuperwallDelegate`](/flutter/sdk-reference/SuperwallDelegate) diff --git a/content/docs/flutter/sdk-reference/TransactionProduct.mdx b/content/docs/flutter/sdk-reference/TransactionProduct.mdx new file mode 100644 index 00000000..5d1c3c21 --- /dev/null +++ b/content/docs/flutter/sdk-reference/TransactionProduct.mdx @@ -0,0 +1,36 @@ +--- +title: "TransactionProduct" +description: "A public product identifier wrapper exported by the Flutter SDK." +--- + +## Purpose + +Represents a product identifier payload. The Flutter SDK exports this type from `package:superwallkit_flutter/superwallkit_flutter.dart` as of 2.4.12. + +## Signature + +```dart +class TransactionProduct { + final String id; +} +``` + +## Properties + + + +## Availability + +`TransactionProduct` is available from the public package export. + +## Related + +- [`SuperwallDelegate`](/flutter/sdk-reference/SuperwallDelegate) diff --git a/content/shared/using-superwall-delegate.mdx b/content/shared/using-superwall-delegate.mdx index c2b2a361..f026251c 100644 --- a/content/shared/using-superwall-delegate.mdx +++ b/content/shared/using-superwall-delegate.mdx @@ -45,7 +45,7 @@ Superwall.instance.delegate = SWDelegate() :::flutter ```dart -import 'package:superwall_flutter/superwall_flutter.dart'; +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; class SWDelegate extends SuperwallDelegate { // Implement delegate methods here