Migrate Adapty Flutter SDK to v4.1

Adapty Flutter SDK 4.1 changes how Adapty Attribution is enabled, renames the external attribution APIs, and changes the fallback file format. It also hands App Store promoted in-app purchases to your app, and adds a way to keep a flow view alive after dismissing it.

Warning

The renamed APIs are a hard break. The old names are removed outright — there are no deprecated aliases to bridge them. Code that compiles against 4.0.x fails on 4.1 until you rename every call site listed below.

If you’re still on 3.x, start with Migrate to v4.0 and then follow this guide.

Quick reference

v4.0v4.1
Adapty Attribution enabled automaticallyAdapty Attribution disabled by default; opt in with withAdaptyAttributionEnabled(true)
Adapty().updateAttribution(attribution, source: source)Adapty().updateExternalAttribution(attribution, provider: provider)
AdaptyAttributionSourceAdaptyExternalAttributionProvider, with a new custom value
AdaptyProfile.appliedAttributionSourcesAdaptyProfile.appliedExternalAttributionProviders
Fallback file downloaded for 4.0New fallback file format; download the file again
Promoted in-app purchases completed on their ownYour app completes them from didReceivePromotedPurchaseStream
dismissFlowView(view) always releases the viewdestroy: false keeps the view alive to present it again

The purchase, profile, and flow-presentation APIs are otherwise unchanged.

Installation

Update adapty_flutter to v4.1 in your pubspec.yaml:

dependencies:
  adapty_flutter: 4.1.0

If your app uses Kids Mode, specify adapty_flutter_kids instead:

dependencies:
  adapty_flutter_kids: 4.1.0

The requirements are unchanged from 4.0: Flutter 3.32.0 (Dart 3.8.0) and iOS 15.0. See Install Adapty SDK for the full setup.

4.1 pins the native iOS SDK to 4.1.3 and the native Android SDK to 4.1.1. The iOS release also fixes numeric parameters of flow analytic events: before it, every 0 and 1 reached flowViewDidReceiveAnalyticEvent as false and true.

⚠️ Adapty Attribution is disabled by default

Warning

If you update to SDK 4.1 and don’t opt in, Adapty Attribution breaks silently — installs stop registering, and nothing warns you.

In 4.0 and earlier, the SDK registered installs for Adapty Attribution automatically. Starting from 4.1, this is off by default: the SDK doesn’t register installs, onUpdateInstallationDetailsSuccessStream and onUpdateInstallationDetailsFailStream never emit, and getCurrentInstallationStatus returns AdaptyInstallationStatusNotAvailable.

If you use Adapty Attribution, enable it when configuring the SDK:

  await Adapty().activate(
-   configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY'),
+   configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
+     ..withAdaptyAttributionEnabled(true),
  );

If you don’t use Adapty Attribution, no changes are needed.

Renamed external attribution APIs

The APIs that pass attribution data from an external provider (Adjust, AppsFlyer, Branch, Tenjin, or a custom one) are renamed to match the native SDKs.

updateAttribution → updateExternalAttribution

The method is renamed and its source parameter is renamed to provider. The parameter now takes an AdaptyExternalAttributionProvider instead of a string, and attribution data is still a map:

- await Adapty().updateAttribution(attribution, source: 'adjust');
+ await Adapty().updateExternalAttribution(attribution, provider: AdaptyExternalAttributionProvider.adjust);

AdaptyAttributionSource → AdaptyExternalAttributionProvider

The provider type is renamed. It stays an open wrapper over a string — the predefined values are appleAds, adjust, appsflyer, branch, tenjin, and a new custom for providers Adapty doesn’t integrate with directly. You can construct one from any other string, so a provider Adapty adds later works without an SDK update:

final provider = AdaptyExternalAttributionProvider('my_provider');

AdaptyProfile.appliedAttributionSources → appliedExternalAttributionProviders

The profile property that lists the attribution providers applied to the profile is renamed, and its element type changes accordingly:

- if (profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) {
+ if (profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.appleAds)) {
      // Apple Ads attribution has been applied
  }

The serialized profile field keeps the name applied_attribution_sources, so a backend that reads the raw profile needs no changes. Code that reads the property does — see Show an Apple Ads targeted paywall.

Fallback files

The fallback file format changed in SDK 4.1. Download the file again from Placements > Fallbacks and bundle it in your app, even if you already downloaded one for 4.0.

Warning

This step produces no build error. If you skip it, the SDK rejects the outdated file and every placement loses its fallback.

Warning

This is a behavior change, not a new feature to adopt when convenient. On 4.0, an in-app purchase promoted on your App Store product page completed on its own. On 4.1, it completes only if your app listens for it. Ship 4.1 without the code below and those purchases stop happening — the App Store hands the product to your app, and nothing else occurs.

On 4.0, Adapty recorded a promoted purchase like any other transaction, and your app had no way to intercept it. 4.1 gives your app that control, and with it the responsibility to finish the purchase.

Subscribe to didReceivePromotedPurchaseStream and pass the product to makePromotedPurchase:

Adapty().didReceivePromotedPurchaseStream.listen((product) async {
  try {
    final result = await Adapty().makePromotedPurchase(product: product);
    // process the purchase result
  } on AdaptyError catch (e) {
    // handle the error
  }
});

Subscribe before a promoted purchase can arrive — during app startup, right after activate. The stream is a broadcast stream that doesn’t replay: a product delivered while nothing is listening is dropped, and the purchase is lost with it.

makePromotedPurchase takes no purchase parameters, because a promoted product comes from the App Store rather than a paywall and carries no paywall context. It returns the same AdaptyPurchaseResult as makePurchase.

Warning

The stream is built on StoreKit 2 and requires iOS 16.4 or later. Below iOS 16.4, and on Android, it never emits.

If the promoted product carries a subscription offer, the SDK applies it at purchase automatically. The offer is read from the App Store purchase intent, which exposes it on iOS 18.0 and later. On iOS 16.4–17.x, the purchase goes through at the base price.

Keep a flow view alive after dismissing it

AdaptyUI().dismissFlowView and AdaptyUIFlowView.dismiss accept a destroy flag:

await AdaptyUI().dismissFlowView(view, destroy: false);

It defaults to true, which releases the view as before. With destroy: false the view stays alive, so you can present it again and the user returns to the screen they left, with the state the flow had built up.

A view kept this way is held until you dismiss it with destroy: true. Presenting a released view fails, so call createFlowView again to show that flow once more.

hasViewConfiguration

AdaptyFlow.hasViewConfiguration now also requires the flow to carry a UI schema, so it reports true only for a flow AdaptyUI can render. A flow that reached your app without its schema now reports false where 4.0 reported true. See Fetch the view configuration.