Migrar el SDK de Kotlin Multiplatform de Adapty a v4.1
El SDK de Kotlin Multiplatform de Adapty 4.1 es la primera versión estable de la línea 4.x — la 4.0 se publicó solo como beta, así que si estás en la 3.x, migra directamente a la 4.1. Esta guía cubre la migración completa: los flows introducidos en la 4.0 y los cambios de la 4.1 sobre ellos.
La línea 4.x introduce flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el Flow & Paywall Builder como con el antiguo Paywall Builder — no se requieren cambios de configuración en el Adapty Dashboard. Además, la versión 4.1 hace que Adapty Attribution sea opcional (opt-in), renombra las APIs de atribución externa y el tipo de suscripción del producto, y añade las compras in-app promocionadas de App Store.
¿Vienes de la beta 4.0? Actualiza la versión y solo aplican cinco secciones: La atribución de Adapty está desactivada por defecto, las APIs de atribución externa renombradas, AdaptyPaywallProductSubscription → AdaptyProductSubscription, compras in-app promocionadas en App Store y elegir un layout específico. hasViewConfiguration también vuelve al modelo de flow.
Referencia rápida
| v3 | v4.1 |
|---|---|
| Adapty Attribution habilitado automáticamente | deshabilitado por defecto — actívalo con .withAdaptyAttributionEnabled(true) |
Adapty.getPaywall(placementId, locale) | Adapty.getFlow(placementId) |
Adapty.getPaywallForDefaultAudience(placementId, locale) | Adapty.getFlowForDefaultAudience(placementId) |
Adapty.getPaywallProducts(paywall) | Adapty.getPaywallProducts(flow) |
Adapty.logShowPaywall(paywall) | Adapty.logShowFlow(flow) |
AdaptyPaywall | AdaptyFlow |
AdaptyUI.createPaywallView(paywall, ...) | AdaptyUI.createFlowView(flow, ...) |
AdaptyUI.createNativePaywallView(...) → AdaptyNativePaywallView | AdaptyUI.createNativeFlowView(...) → AdaptyNativeFlowView |
AdaptyUIPaywallView | AdaptyUIFlowView |
AdaptyUI.presentPaywallView(view) / dismissPaywallView(view) | AdaptyUI.presentFlowView(view) / dismissFlowView(view) |
AdaptyUI.setPaywallsEventsObserver(observer) | AdaptyUI.setFlowsEventsObserver(observer) |
AdaptyUI.registerPaywallEventsListener / unregisterPaywallEventsListener | AdaptyUI.registerFlowEventsListener / unregisterFlowEventsListener |
AdaptyUIPaywallsEventsObserver | AdaptyUIFlowsEventsObserver |
AdaptyUIPaywallPlatformView(paywall, ...) | AdaptyUIFlowPlatformView(flow, ...) |
paywallViewDidPerformAction, paywallViewDidAppear y otros callbacks paywallView... | flowViewDidPerformAction, flowViewDidAppear y otros callbacks flowView... |
paywallViewDidFailRendering | flowViewDidReceiveError |
Adapty.updateAttribution(attribution, source) con una fuente de tipo String | Adapty.updateExternalAttribution(attribution, provider) con un AdaptyExternalAttributionProvider |
proveedor pasado como string, por ejemplo "adjust" | AdaptyExternalAttributionProvider, por ejemplo AdaptyExternalAttributionProvider.ADJUST |
AdaptyProfile.appliedAttributionSources: List<String> | AdaptyProfile.appliedExternalAttributionProviders: List<AdaptyExternalAttributionProvider> |
AdaptyPaywallProductSubscription | AdaptyProductSubscription |
| Las compras in-app promocionadas se completaban automáticamente, sin posibilidad de interceptarlas | OnPromotedPurchaseListener y Adapty.makePromotedPurchase(product) delegan la finalización a tu app |
AdaptyPaywallProduct mantiene su nombre — los productos siguen perteneciendo a un flow, y getPaywallProducts también mantiene su nombre, ahora aceptando un AdaptyFlow. Los métodos getFlow y getFlowForDefaultAudience ya no aceptan un parámetro locale — pásalo a createFlowView en su lugar. Las APIs de compra y perfil (makePurchase, restorePurchases, getProfile, identify, updateProfile) y setFallback mantienen las mismas firmas, pero el propio archivo de respaldo debe volver a descargarse — consulta Archivos de respaldo. Los métodos de onboarding siguen funcionando pero están obsoletos — consulta Obsolescencia de la API de onboarding. Algunos comportamientos predeterminados han cambiado — consulta Cambios en el comportamiento predeterminado.
Instalación
Actualiza la versión y sincroniza el proyecto:
[versions]
adapty-kmp = "<the latest SDK version>"
[libraries]
adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" }
adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" }
El módulo adapty-kmp-ui solo es necesario si renderizas flows y paywalls con la capa de Compose Multiplatform (view.present()). Consulta Instalar el SDK de Adapty para la configuración completa.
Los SDKs nativos de Adapty subyacentes se han actualizado a sus versiones 4.x en ambas plataformas y se resuelven automáticamente — no se necesitan cambios en la compilación. El target de despliegue de iOS sigue siendo 15.0, sin cambios en esta versión.
⚠️ La atribución de Adapty está desactivada por defecto
Si usas Atribución de Adapty y actualizas al SDK 4.1 sin activarla explícitamente, fallará en silencio: las instalaciones dejarán de registrarse y no recibirás ningún aviso.
En versiones anteriores, el SDK registraba instalaciones para Atribución de Adapty automáticamente. A partir de la versión 4.1 del SDK, esto está desactivado por defecto: el SDK no registra instalaciones, el listener configurado con setOnInstallationDetailsListener nunca se activa, y getCurrentInstallationStatus devuelve AdaptyInstallationStatus.Determined.NotAvailable.
Si usas la Atribución de Adapty, actívala al inicializar el SDK:
val config = AdaptyConfig
.Builder("PUBLIC_SDK_KEY")
+ .withAdaptyAttributionEnabled(true)
.build()
Adapty.activate(configuration = config)
Si no usas Adapty Attribution, no es necesario hacer ningún cambio.
Obtener flows
getPaywall → getFlow
El tipo devuelto cambia de AdaptyPaywall a AdaptyFlow, y el parámetro locale se mueve de la llamada de obtención a createFlowView; para paywalls personalizados, todos los locales se devuelven en flow.remoteConfigs:
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en")
- .onSuccess { paywall ->
- // use the paywall
+ Adapty.getFlow("YOUR_PLACEMENT_ID")
+ .onSuccess { flow ->
+ AdaptyUI.createFlowView(flow = flow, locale = "en")
}
.onError { error ->
// handle the error
}
locale sigue siendo opcional en createFlowView: omítelo y la vista se renderizará en en, o en la localización predeterminada del flow cuando este no tenga en. Consulta Localizaciones y códigos de idioma.
getPaywallForDefaultAudience se renombra de la misma forma:
- Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en")
+ Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID")
getPaywallProducts(paywall) → getPaywallProducts(flow)
getPaywallProducts mantiene su nombre pero ahora recibe un AdaptyFlow:
- Adapty.getPaywallProducts(paywall)
+ Adapty.getPaywallProducts(flow)
.onSuccess { products ->
// use the products
}
Archivos de respaldo
El formato del archivo de respaldo cambió en la versión 4 del SDK. Descarga el nuevo archivo desde Placements > Fallbacks y agrégalo a tu app.
Modelo de datos
getFlow devuelve un AdaptyFlow en lugar de un AdaptyPaywall, y la estructura del objeto ha cambiado:
Propiedad v3 AdaptyPaywall | Propiedad v4 AdaptyFlow | Acción |
|---|---|---|
remoteConfig: AdaptyRemoteConfig? (única) | remoteConfigs: List<AdaptyRemoteConfig> | Un flow lleva un Remote Config por idioma configurado. Lee el que corresponda al usuario: flow.remoteConfigs.firstOrNull { it.locale == "en" }. |
| (nuevo) | paywalls: List<AdaptyFlowPaywall> | Cada entrada es una variación de paywall en el flow, con su propio name, variationId e productIdentifiers. Los métodos de paywall web reciben un AdaptyFlowPaywall — consulta Métodos de paywall web. |
productIdentifiers | movido | Los identificadores de producto ahora están en cada variación: flow.paywalls[i].productIdentifiers. Para obtener productos, sigue llamando a getPaywallProducts(flow). |
hasViewConfiguration | mantenido | Indica si el flow incluye un layout que AdaptyUI puede renderizar. Estaba ausente en la beta 4.0 y ha vuelto en 4.1: si eliminaste tus comprobaciones para la beta, puedes volver a usarlo. false significa que el flow no lleva layout, así que trátalo como solo Remote Config. También puedes llamar a createFlowView y gestionar el error (consulta Mostrar flows). |
hasViewConfiguration también está disponible en AdaptyOnboarding, sin cambios.
Métodos de Web paywall
openWebPaywall y createWebPaywallUrl mantienen sus nombres, pero el parámetro paywall se reemplaza por un parámetro flowPaywall que recibe un AdaptyFlowPaywall — una de las variantes en flow.paywalls. También puedes seguir pasando un AdaptyPaywallProduct:
- Adapty.openWebPaywall(paywall = paywall)
+ flow.paywalls.firstOrNull()?.let { flowPaywall ->
+ Adapty.openWebPaywall(flowPaywall = flowPaywall)
+ }
Seguimiento de visualizaciones 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 las pruebas A/B existentes siguen funcionando sin cambios en el dashboard.
- Adapty.logShowPaywall(paywall)
+ Adapty.logShowFlow(flow)
Al igual que en v3, no es necesario llamar a este método cuando se muestran flows o paywalls renderizados por Adapty — Adapty registra esas vistas automáticamente.
Mostrando flows
createPaywallView → createFlowView
Renombra el método de fábrica y pasa el AdaptyFlow. El tipo de vista devuelto cambia de AdaptyUIPaywallView a AdaptyUIFlowView, pero sus métodos (present, dismiss) y los parámetros opcionales (loadTimeout, preloadProducts, customTags, customTimers, customAssets, productPurchaseParams) no cambian. Hay un nuevo parámetro opcional: locale, que reemplaza el locale que antes pasabas a getPaywall — consulta Obtención de flows.
customTimers sigue existiendo, pero solo afecta a los paywalls del Paywall Builder heredado. El temporizador de cuenta atrás de un flow se ejecuta según el comportamiento configurado en el Flow & Paywall Builder, por lo que un flow ignora lo que pases aquí.
- AdaptyUI.createPaywallView(paywall)
+ AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// handle the error
}
Si no usas Compose Multiplatform, el método de fábrica nativo se renombra de la misma manera:
- AdaptyUI.createNativePaywallView(paywall)
+ AdaptyUI.createNativeFlowView(flow)
createFlowView devuelve un AdaptyResult.Error si el flow no tiene ninguna vista configurada, así que puedes eliminar la comprobación hasViewConfiguration de v3 y gestionar el error en su lugar:
- if (paywall.hasViewConfiguration) {
- AdaptyUI.createPaywallView(paywall)
- .onSuccess { view -> view.present() }
- }
+ AdaptyUI.createFlowView(flow)
+ .onSuccess { view -> view.present() }
+ .onError { error ->
+ // the flow has no view configured, or view creation failed
+ }
Una vista de flow es de un solo uso: después de llamar a dismiss(), la vista se destruye, por lo que debes llamar a createFlowView de nuevo para mostrar el flow otra vez.
Gestión de eventos
El observador de eventos cambia de nombre de AdaptyUIPaywallsEventsObserver a AdaptyUIFlowsEventsObserver, y sus callbacks reemplazan el prefijo paywallView por flowView. El cuerpo de los handlers existentes no necesita cambios en el código — solo hay que renombrar el tipo y las sobreescrituras:
- AdaptyUI.setPaywallsEventsObserver(object : AdaptyUIPaywallsEventsObserver {
- override fun paywallViewDidFinishPurchase(
- view: AdaptyUIPaywallView,
+ AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
+ override fun flowViewDidFinishPurchase(
+ view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
// custom logic after purchase
}
})
Un callback también ha sido renombrado: paywallViewDidFailRendering pasa a llamarse flowViewDidReceiveError. Se activa para los mismos errores de renderizado que antes, además de otros errores en tiempo de ejecución no relacionados con compras:
- override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {}
+ override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {}
Consulta Gestionar eventos de flow y paywall para ver la lista completa de callbacks.
Vista de plataforma de Compose
Si integras vistas con el composable de Compose Multiplatform, AdaptyUIPaywallPlatformView(paywall, ...) pasa a llamarse AdaptyUIFlowPlatformView(flow, ...). Los callbacks de eventos mantienen sus nombres onDid..., excepto onDidFailRendering, que se convierte en onDidReceiveError:
- AdaptyUIPaywallPlatformView(
- paywall = paywall,
+ AdaptyUIFlowPlatformView(
+ flow = flow,
onDidFinishPurchase = { view, product, result -> /* ... */ },
)
Al igual que en la v3, los callbacks que pasas aquí (y cualquier observador registrado mediante registerFlowEventsListener) se ejecutan además del observador global, no en lugar de él — tu callback observa un evento, no reemplaza el comportamiento global predeterminado. Ten en cuenta los cambios en los valores predeterminados: por ejemplo, el comportamiento global predeterminado ya no cierra la vista tras una compra.
Nuevas APIs
AdaptyUI.setObserverModeResolver(...)con unAdaptyUIObserverModeResolver— gestiona compras y restauraciones iniciadas desde flows mientras el SDK funciona en modo Observer. Antes esto solo estaba disponible en los SDKs nativos de iOS y Android. Consulta Presentar flows en modo Observer.AdaptyUI.setSystemRequestsHandler(...)con unAdaptyUISystemRequestsHandler— reservado para solicitudes del sistema desde un flow (solicitudes de permisos del SO y peticiones de valoración de la app). Los flows aún no activan estas solicitudes, por lo que no es necesario registrar un handler.- El nuevo callback opcional
flowViewDidReceiveAnalyticEventreporta eventos de analítica desde un flow, comenzando con una vista de pantalla por cada pantalla que abre el usuario. Consulta Rastrear vistas de pantalla de flows. AdaptyUI.openWebUrl(url, openIn)yAdaptyUI.requestAppReview()— son la base del manejo predeterminado deOpenUrlActiony delhandleAppReviewRequestpredeterminado, por lo que las URLs y las solicitudes de valoración de la app se gestionan de forma nativa sin configuración adicional. Llámalos directamente solo si sobreescribes esos comportamientos predeterminados.AdaptyUIFlowView.locale— informa la localización con la que se construyó la vista, para que puedas saber cuál ve realmente el usuario.AdaptyConfig.ServerCluster.CN— una nueva opción de clúster de servidor junto aDEFAULTyEU, para conectar tu app a los servidores de Adapty en China.
API de atribución externa renombradas
A partir de la versión 4.1 del SDK, las API que envían datos de atribución desde un proveedor externo (Adjust, AppsFlyer, Branch, Tenjin, Apple Ads o uno personalizado) se han renombrado para coincidir con los SDK nativos, y el proveedor pasa de ser una cadena de texto a un tipo. No existen alias deprecados, por lo que los sitios de llamada existentes dejarán de compilar hasta que los actualices.
updateAttribution → updateExternalAttribution
El método ha sido renombrado, su parámetro source pasa a llamarse provider, y ahora acepta un AdaptyExternalAttributionProvider en lugar de un String:
- Adapty.updateAttribution(attribution, "adjust")
+ Adapty.updateExternalAttribution(attribution, AdaptyExternalAttributionProvider.ADJUST)
Los datos de atribución siguen siendo un Map<String, Any>.
La llamada retorna en cuanto el backend acepta los datos para procesarlos de forma asíncrona. Un resultado exitoso no significa que los datos ya se hayan aplicado al perfil.
AdaptyExternalAttributionProvider
El proveedor es ahora un tipo con valores predefinidos: APPLE_ADS, ADJUST, APPSFLYER, BRANCH, TENJIN y CUSTOM. Para cualquier otro proveedor, constrúyelo a partir de su identificador:
AdaptyExternalAttributionProvider("your_provider")
Construirlo directamente también cubre los proveedores que Adapty añada después de esta versión del SDK — el identificador llega al backend sin modificaciones en lugar de colapsar en un valor desconocido. Los espacios en blanco circundantes se eliminan automáticamente.
Cada valor predefinido encapsula el mismo identificador que pasaste a updateAttribution anteriormente: AdaptyExternalAttributionProvider.APPLE_ADS.value es apple_search_ads, y el resto son sus propios nombres en minúsculas.
AdaptyProfile.appliedAttributionSources → appliedExternalAttributionProviders
La propiedad del perfil que lista los proveedores de atribución aplicados al perfil se renombra, y el tipo de sus elementos cambia en consecuencia:
- if (profile.appliedAttributionSources.contains("apple_search_ads")) {
+ if (profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.APPLE_ADS)) {
// Apple Ads attribution has been applied
}
AdaptyPaywallProductSubscription → AdaptyProductSubscription
El tipo de detalles de suscripción se renombra porque los productos promocionados ahora comparten el mismo tipo. Solo cambia el nombre — cada propiedad mantiene su nombre y tipo:
- val subscription: AdaptyPaywallProductSubscription? = product.subscription
+ val subscription: AdaptyProductSubscription? = product.subscription
Compras in-app promocionadas en el App Store
SDK 4.1 entrega compras in-app promocionadas en la página de tu producto en el App Store a tu app en iOS. Las versiones anteriores completaban este tipo de compra automáticamente, sin que tu app pudiera interceptarla. A partir de la 4.1, la compra espera a que tu código la gestione, por lo que es necesario actuar aunque nunca hayas trabajado con compras promocionadas.
Para admitir compras promocionadas, registra un OnPromotedPurchaseListener y completa la compra pasando el producto a Adapty.makePromotedPurchase. Sin un listener registrado, la compra queda pendiente en lugar de completarse: el usuario pulsa Buy en tu página de App Store y no ocurre nada en tu app. Registra el listener lo antes posible — consulta Compras in-app desde el App Store para ver el momento adecuado y el ejemplo completo.
Elegir un layout específico
createFlowView, createNativeFlowView y AdaptyUIFlowPlatformView aceptan un nuevo parámetro opcional customLayoutId. Úsalo para renderizar un layout concreto de la configuración de layouts del flow en lugar del que el SDK selecciona automáticamente según el tipo de dispositivo y el tamaño de pantalla. El Flow & Paywall Builder aún no asigna IDs de layout personalizados, así que deja este parámetro sin definir:
AdaptyUI.createFlowView(flow, customLayoutId = "tablet_landscape")
Si ningún layout coincide con el ID, el flow se carga sin una configuración de vista. El parámetro es opcional y su valor predeterminado es null, por lo que las llamadas existentes no se ven afectadas.
Cambios en el comportamiento predeterminado
Estos cambios no provocan errores de compilación, así que pruébalos en tiempo de ejecución:
- Finalización de compra: En v3, el
paywallViewDidFinishPurchasepredeterminado cerraba la vista tras cualquier resultado de compra que no fueraAdaptyPurchaseResult.UserCanceled. En v4, elflowViewDidFinishPurchasepredeterminado no hace nada, por lo que un flow permanece abierto tras una compra hasta que lo cierres tú — igual que en iOS. Si dependías de ese cierre automático, llama aview.dismiss()cuando finalice la compra. - Botón atrás de Android: En v3, el
paywallViewDidPerformActionpredeterminado cerraba la vista tanto conCloseActioncomo conAndroidSystemBackAction. En v4, el comportamiento predeterminado solo gestionaCloseAction— el botón atrás del sistema ya no cierra un flow por sí solo, igual que en iOS, donde un flow no puede cerrarse con un gesto del sistema. Ofrece a los usuarios una salida explícita (un botón Close o una acciónon_device_back), o cierra la vista tú mismo enflowViewDidPerformAction. - Errores de vista: En v3, el
paywallViewDidFailRenderingpredeterminado no hacía nada. En v4, elflowViewDidReceiveErrorpredeterminado cierra la vista — sobreescríbelo si quieres mantenerla abierta o gestionar el error de otra manera. - Las vistas son de un solo uso: Tras llamar a
dismiss(), la vista se destruye. Llama acreateFlowViewde nuevo para mostrar el flow otra vez.
Desaprobación de la API de onboarding
La API de onboarding heredada está desaprobada en v4 en favor del Flow & Paywall Builder. Sigue funcionando, pero se eliminará en una versión futura, así que planifica la migración de tus onboardings al Flow & Paywall Builder.
Símbolos desaprobados: getOnboarding, getOnboardingForDefaultAudience, AdaptyUI.createOnboardingView, AdaptyUI.createNativeOnboardingView, y AdaptyUIOnboardingsEventsObserver.