Migrar Adapty Flutter SDK a v. 4.0

Adapty Flutter SDK 4.0 introduce flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente — no se requieren cambios de configuración en el Adapty Dashboard.

Referencia rápida

v3v4
Adapty().getPaywall(placementId: id)Adapty().getFlow(placementId: id)
Adapty().getPaywallForDefaultAudience(placementId: id)Adapty().getFlowForDefaultAudience(placementId: id)
Adapty().getPaywallProducts(paywall: paywall)Adapty().getPaywallProducts(flow: flow)
Adapty().logShowPaywall(paywall: paywall)Adapty().logShowFlow(flow: flow)
AdaptyPaywall (tipo)AdaptyFlow
AdaptyPaywallFetchPolicy (tipo)AdaptyFlowFetchPolicy
AdaptyUI().createPaywallView(paywall: paywall)AdaptyUI().createFlowView(flow: flow)
AdaptyUIPaywallView (tipo)AdaptyUIFlowView
AdaptyUIPaywallPlatformView (widget)AdaptyUIFlowPlatformView
AdaptyUI().presentPaywallView(view) / dismissPaywallView(view)AdaptyUI().presentFlowView(view) / dismissFlowView(view)
AdaptyUIPaywallsEventsObserverAdaptyUIFlowsEventsObserver
AdaptyUI().setPaywallsEventsObserver(observer)AdaptyUI().setFlowsEventsObserver(observer)
callbacks paywallViewDid*callbacks flowViewDid*
paywallViewDidFailRenderingflowViewDidReceiveError
AdaptyPaywallProduct mantiene su nombre — los productos siguen perteneciendo a un flow, y getPaywallProducts ahora recibe un AdaptyFlow. Ya no se pasa un locale al recuperar un flow. Las APIs de compra y perfil (makePurchase, restorePurchases, getProfile, identify, etc.) no han cambiado, y tampoco los métodos de vista present, dismiss y showDialog. Algunos comportamientos por defecto han cambiado — consulta Cambios en el comportamiento por defecto.

Versiones mínimas

El SDK de Adapty para Flutter 4.0 eleva los requisitos mínimos:

  • iOS 15.0 — el objetivo de despliegue mínimo para iOS, aumentado desde iOS 13.0.
  • Xcode 26 o superior — el SDK nativo de iOS usa Swift tools 6.2.
  • Flutter 3.32.0 (Dart 3.8.0) o superior.

Instalación

Actualizar el paquete

El paquete que instales depende de si tu app usa el Modo Infantil.

Para la mayoría de las apps, actualiza adapty_flutter a la v4.0 en tu pubspec.yaml:

dependencies:
  adapty_flutter: 4.0.0

Si tu app usa el Modo Infantil, especifica adapty_flutter_kids en su lugar:

dependencies:
  adapty_flutter_kids: 4.0.0

Este paquete autónomo elimina el código de IDFA y seguimiento de anuncios para cumplir con los requisitos del App Store. Actualiza la ruta de importación de Dart a package:adapty_flutter_kids/adapty_flutter.dart. Por lo demás, la migración es exactamente igual que la del paquete normal.

El modo Kids también requiere que desactives la recopilación de direcciones IP en el Adapty Dashboard — consulta Kids Mode para ver la configuración completa.

iOS: los SDKs nativos ahora se distribuyen a través de Swift Package Manager

El repositorio de specs de CocoaPods pasará a ser de solo lectura en diciembre de 2026, por lo que a partir de la v4 el SDK nativo de iOS ya no se distribuye a través de CocoaPods — el plugin lo obtiene únicamente a través de Swift Package Manager.

Si usas Flutter 3.32–3.43, activa el soporte de Swift Package Manager una sola vez:

flutter config --enable-swift-package-manager

Flutter 3.44 y versiones posteriores activan Swift Package Manager por defecto, así que no es necesario hacer nada en ese caso.

Obtener flows

getPaywall → getFlow

El tipo devuelto cambia de AdaptyPaywall a AdaptyFlow, y ya no se pasa un locale — cuando renderizas un flow, la localización se resuelve automáticamente; para paywalls personalizados, todos los idiomas configurados se devuelven en flow.remoteConfigs:

- final paywall = await Adapty().getPaywall(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');

getPaywallForDefaultAudience se renombra de la misma manera:

- final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID');

El tipo de política de obtención cambia su nombre de AdaptyPaywallFetchPolicy a AdaptyFlowFetchPolicy; sus opciones (reloadRevalidatingCacheData, returnCacheDataElseLoad, returnCacheDataIfNotExpiredElseLoad) no cambian.

getPaywallProducts(paywall) → getPaywallProducts(flow)

getPaywallProducts mantiene su nombre pero ahora recibe un AdaptyFlow mediante el parámetro flow:

- final products = await Adapty().getPaywallProducts(paywall: paywall);
+ final products = await Adapty().getPaywallProducts(flow: flow);

Modelo de datos

getFlow devuelve un AdaptyFlow en lugar de un AdaptyPaywall, y la estructura del objeto ha cambiado:

Miembro de AdaptyPaywall v3Miembro de AdaptyFlow v4Acción
remoteConfig (único, nullable)remoteConfigs (lista)Un flow lleva un Remote Config por idioma configurado. El getter remoteConfig sigue existiendo y devuelve la primera entrada; para seleccionar un idioma concreto, busca en remoteConfigs por su locale.
productIdentifiersproductIdentifiersSe conserva, pero ahora se recopila en todas las variaciones de paywall del flow. Los identificadores por variación están en flow.paywalls[i].productIdentifiers.
hasViewConfigurationhasViewConfigurationSin cambios.
placementId (obsoleto)eliminadoUsa flow.placement.id.
revision (obsoleto)eliminadoUsa flow.placement.revision.
vendorProductIds (obsoleto)eliminadoUsa productIdentifiers.
(nuevo)paywalls (lista de AdaptyFlowPaywall)Cada entrada es una variación de paywall en el flow, con su propio name, variationId y productIdentifiers.
AdaptyPaywallViewConfiguration ya no está expuesto — la configuración de la vista ahora es opaca. Elimina cualquier referencia a este tipo.

Métodos de paywall web

openWebPaywall y createWebPaywallUrl mantienen sus nombres, pero el parámetro paywall ahora recibe un AdaptyFlowPaywall (una variante de flow) en lugar de un AdaptyPaywall. También puedes seguir pasando un AdaptyPaywallProduct.

  final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
- await Adapty().openWebPaywall(paywall: paywall);
+ if (flow.paywalls.isNotEmpty) {
+   await Adapty().openWebPaywall(paywall: flow.paywalls[0]);
+ }

Seguimiento de vistas de flows

logShowPaywall → logShowFlow

logShowPaywall ha pasado a llamarse logShowFlow y ahora recibe un AdaptyFlow. El evento sigue registrándose contra la misma variación, por lo que las métricas de embudo y prueba A/B existentes siguen funcionando sin cambios en el dashboard.

- await Adapty().logShowPaywall(paywall: paywall);
+ await Adapty().logShowFlow(flow: flow);

Al igual que en v3, no es necesario llamar a este método cuando se muestran flows o paywalls renderizados por el Flow Builder o el Paywall Builder — Adapty registra esas vistas automáticamente.

Mostrar flows

createPaywallView → createFlowView

Renombra el método y pasa el AdaptyFlow mediante el parámetro flow. El resto de parámetros (loadTimeout, preloadProducts, customTags, customTimers, customAssets, productPurchaseParams) no cambian, ni tampoco los métodos de la vista present, dismiss y showDialog:

- final view = await AdaptyUI().createPaywallView(paywall: paywall);
+ final view = await AdaptyUI().createFlowView(flow: flow);
  await view.present();

AdaptyUIPaywallView → AdaptyUIFlowView

El tipo de vista ha sido renombrado. Su propiedad paywallVariationId (obsoleta) ha sido eliminada — usa variationId en su lugar:

- void flowViewDidAppear(AdaptyUIPaywallView view) {
+ void flowViewDidAppear(AdaptyUIFlowView view) {

AdaptyUIPaywallPlatformView → AdaptyUIFlowPlatformView

Si incrustas la vista como un widget en tu árbol de widgets, renómbrala y pasa el parámetro flow. Los callbacks de eventos (onDidAppear, onDidFinishPurchase, etc.) conservan sus nombres:

- AdaptyUIPaywallPlatformView(
-   paywall: paywall,
+ AdaptyUIFlowPlatformView(
+   flow: flow,
    onDidFinishPurchase: (view, product, purchaseResult) { /* … */ },
  )

Una vista de flow creada con createFlowView es de un solo uso: tras llamar a dismiss(), la vista se libera de la memoria y no se puede volver a mostrar — llama a createFlowView de nuevo para presentar el flow otra vez.

Manejo de eventos

La clase de observador se renombra de AdaptyUIPaywallsEventsObserver a AdaptyUIFlowsEventsObserver, su método de registro de setPaywallsEventsObserver a setFlowsEventsObserver, y todos los callbacks paywallViewDid* pasan a llamarse flowViewDid*:

- class MyObserver extends AdaptyUIPaywallsEventsObserver {
+ class MyObserver extends AdaptyUIFlowsEventsObserver {
    @override
-   void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) {
+   void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) {
      // …
    }
  }

- AdaptyUI().setPaywallsEventsObserver(this);
+ AdaptyUI().setFlowsEventsObserver(this);

Ahora hay tres callbacks obligatorios — tu observer no compilará sin ellos:

  • flowViewDidFinishPurchase: Era opcional en v3, donde el comportamiento por defecto era cerrar la vista tras una compra. Ahora decides qué ocurre: continuar el flow o llamar a view.dismiss().
  • flowViewDidFinishRestore: Obligatorio, igual que en v3.
  • flowViewDidReceiveError: Reemplaza a paywallViewDidFailRendering y ahora también recibe otros errores de la vista.

Dos cambios menores:

  • setFlowsEventsObserver (y setOnboardingsEventsObserver) ahora aceptan null para desasociar un observador previamente configurado, por lo que el SDK ya no lo retiene.
  • El nuevo callback opcional flowViewDidReceiveAnalyticEvent está reservado para eventos analíticos personalizados de un flow. Los flows aún no emiten estos eventos a tu código, por lo que no necesitas implementarlo.

La v4 también añade funcionalidades opcionales a las que puedes suscribirte:

  • AdaptyUI().setObserverModeResolver(...) con un AdaptyUIObserverModeResolver — gestiona las compras y restauraciones iniciadas desde flows cuando el SDK funciona en modo Observer. Anteriormente, esto solo estaba disponible en los SDKs nativos de iOS y Android. Consulta Presentar flows en modo Observer.
  • AdaptyUI().setSystemRequestsHandler(...) con un AdaptyUISystemRequestsHandler — reservado para solicitudes del sistema desde un flow (permisos del SO y solicitudes de valoración en el App Store). Los flows aún no activan estas solicitudes, por lo que no es necesario registrar un handler.

APIs eliminadas

Estos símbolos fueron declarados obsoletos en la versión 3.x y se eliminan en la v4:

setFallbackPaywalls → setFallback

- await Adapty().setFallbackPaywalls(assetId);
+ await Adapty().setFallback(assetId);

withIdfaCollectionDisabled → withAppleIdfaCollectionDisabled

  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
-   ..withIdfaCollectionDisabled(true),
+   ..withAppleIdfaCollectionDisabled(true),

Otros miembros eliminados

  • AdaptyPurchaseResultSuccess.jwsTransaction: Usa appleJwsTransaction.
  • AdaptyUIFlowView.paywallVariationId: Usa variationId.
  • AdaptyUIObserver y AdaptyUI().setObserver(...): Usa AdaptyUIFlowsEventsObserver y setFlowsEventsObserver(...).

Cambios en el comportamiento predeterminado

Estos cambios no causan errores de compilación, así que pruébalos en tiempo de ejecución:

  • Compra exitosa: En v3, el comportamiento predeterminado de paywallViewDidFinishPurchase cerraba la vista. En v4, flowViewDidFinishPurchase es obligatorio y no tiene comportamiento predeterminado — cierra la vista tú mismo si eso es lo que quieres.
  • Botón Atrás del sistema Android: Ya no cierra un flow de forma predeterminada. La acción se entrega a flowViewDidPerformAction como AndroidSystemBackAction — gestiónala ahí si quieres que el botón Atrás cierre el flow.
  • Apertura de URLs: El comportamiento predeterminado de flowViewDidPerformAction ahora gestiona OpenUrlAction abriendo la URL de forma nativa (respetando la configuración de navegador interno o externo del dashboard), además de cerrar la vista con CloseAction. Sobreescribe el callback para gestionar las URLs tú mismo.
  • Errores de vista: flowViewDidReceiveError es obligatorio, y el cierre depende de tu implementación. Si tu integración de v3 dependía del cierre automático de la vista al producirse errores de renderizado, llama a view.dismiss() en este callback.
  • Ciclo de vida de la vista: Cerrar una vista de flow u onboarding la libera de la memoria. Una vista cerrada no puede volver a mostrarse — crea una nueva en su lugar.

Obsolescencia de la API de onboarding

La API de onboarding heredada está obsoleta en v4.0 en favor del Flow Builder. Sigue funcionando, y tu IDE marca los símbolos obsoletos mediante sus anotaciones @Deprecated — no hay advertencias en tiempo de ejecución. Estos símbolos se eliminarán en una versión futura, así que planifica la migración de tus onboardings al Flow Builder. Símbolos obsoletos: getOnboarding, getOnboardingForDefaultAudience, createOnboardingView, presentOnboardingView, dismissOnboardingView, setOnboardingsEventsObserver, AdaptyOnboarding, AdaptyUIOnboardingView, AdaptyUIOnboardingPlatformView, AdaptyUIOnboardingsEventsObserver, y los modelos de estado, entrada y analíticas de onboarding.