# UNITY - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: es Generated on: 2026-05-22T06:52:52.487Z Total files: 40 --- # File: sdk-installation-unity --- --- title: "Instalar y configurar el SDK de Unity" description: "Guía paso a paso para instalar Adapty SDK en Unity para apps basadas en suscripciones." --- El SDK de Adapty incluye dos módulos clave para una integración fluida en tu app de Unity: - **Core Adapty**: Este SDK esencial es necesario para que Adapty funcione correctamente en tu app. - **AdaptyUI**: Este módulo es necesario si usas el [Adapty Paywall Builder](adapty-paywall-builder), una herramienta visual sin código para crear paywalls multiplataforma fácilmente. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Consulta nuestra [app de ejemplo](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets), que muestra la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Requisitos \{#requirements\} El SDK de Adapty es compatible con iOS 13.0+, pero requiere iOS 15.0+ para trabajar con paywalls creados en el paywall builder. :::info Adapty es compatible con Google Play Billing Library hasta la versión 8.x. Por defecto, Adapty usa Google Play Billing Library v7.0.0. Para usar una versión más reciente, [sobreescribe la dependencia de Billing](https://developer.android.com/google/play/billing/integrate#dependency) en tu build de Android. ::: --- no_index: true --- import Callout from '../../../components/Callout.astro'; Instalar el SDK es el paso 5 de la configuración de Adapty. Para que las compras funcionen en tu app, también necesitas conectar tu app a los stores, y luego crear productos, un paywall y un placement en el Adapty Dashboard. La [guía de inicio rápido](quickstart) explica todos los pasos necesarios. ## Instalar el SDK de Adapty \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Unity.svg?style=flat&logo=unity)](https://github.com/adaptyteam/AdaptySDK-Unity/releases) 1. Descarga el [`adapty-unity-plugin-*.unitypackage`](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Releases) desde GitHub e impórtalo en tu proyecto. 2. Descarga e importa el [plugin External Dependency Manager](https://github.com/googlesamples/unity-jar-resolver). 3. El SDK usa el plugin "External Dependency Manager" para gestionar las dependencias de iOS Cocoapods y las dependencias de Android gradle. Tras la instalación, puede que necesites invocar el gestor de dependencias: `Assets -> External Dependency Manager -> Android Resolver -> Force Resolve` y `Assets -> External Dependency Manager -> iOS Resolver -> Install Cocoapods` 4. Al compilar tu proyecto de Unity para iOS, obtendrás el archivo `Unity-iPhone.xcworkspace`, que debes abrir en lugar de `Unity-iPhone.xcodeproj`; de lo contrario, las dependencias de Cocoapods no se usarán. ## Activar el módulo Adapty del SDK de Adapty \{#activate-adapty-module-of-adapty-sdk\} Activa el SDK de Adapty en el código de tu app. :::note El SDK de Adapty solo necesita activarse una vez en tu app. ::: Para obtener tu **Public SDK Key**: 1. Ve al Adapty Dashboard y navega a [**App settings → General**](https://app.adapty.io/settings/general). 2. En la sección **Api keys**, copia la **Public SDK Key** (NO la Secret Key). 3. Reemplaza `"YOUR_PUBLIC_SDK_KEY"` en el código. :::important - Asegúrate de usar la **Public SDK key** para inicializar Adapty; la **Secret key** solo debe usarse para la [API del servidor](getting-started-with-server-side-api). - Las **SDK keys** son únicas para cada app, así que si tienes varias apps asegúrate de elegir la correcta. ::: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` :::important Espera al callback de finalización de `Activate` antes de llamar a cualquier otro método del SDK de Adapty. Consulta [Orden de llamadas en el SDK de Unity](unity-sdk-call-order) para ver la secuencia completa. ::: ## Configurar la escucha de eventos \{#set-up-event-listening\} Crea un script para escuchar los eventos de Adapty. Nómbralo `AdaptyListener` en tu escena. Te recomendamos usar el método `DontDestroyOnLoad` para este objeto, de modo que persista durante toda la vida útil de la aplicación. Adapty usa el namespace `AdaptySDK`. Al principio de los archivos de script que usen el SDK de Adapty, puedes añadir: ```csharp showLineNumbers title="C#" using AdaptySDK; ``` Suscríbete a los eventos de Adapty: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle updated profile data } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` Te recomendamos ajustar el Script Execution Order para colocar el AdaptyListener antes de Default Time. Esto garantiza que Adapty se inicialice lo antes posible. ## Añadir el plugin de Kotlin a tu proyecto \{#add-kotlin-plugin-to-your-project\} :::warning Este paso es obligatorio. Si lo omites, tu app móvil puede fallar cuando se muestre el paywall. ::: 1. En **Player Settings**, asegúrate de que las opciones **Custom Launcher Gradle Template** y **Custom Base Gradle Template** estén seleccionadas. 2. Añade la siguiente línea a `/Assets/Plugins/Android/launcherTemplate.gradle`: ```groovy showLineNumbers apply plugin: 'com.android.application' // highlight-next-line apply plugin: 'kotlin-android' apply from: 'setupSymbols.gradle' apply from: '../shared/keepUnitySymbols.gradle' ``` 3. Añade la siguiente línea a `/Assets/Plugins/Android/baseProjectTemplate.gradle`: ```groovy showLineNumbers plugins { // If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity // See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html // See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle // To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version id 'com.android.application' version '8.3.0' apply false id 'com.android.library' version '8.3.0' apply false // highlight-next-line id 'org.jetbrains.kotlin.android' version '1.8.0' apply false **BUILD_SCRIPT_DEPS** } ``` Ahora configura los paywalls en tu app: - Si usas el [Adapty Paywall Builder](adapty-paywall-builder), primero [activa el módulo AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) a continuación y luego sigue la [guía de inicio rápido del Paywall Builder](unity-quickstart-paywalls). - Si construyes tu propia UI de paywall, consulta la [guía de inicio rápido para paywalls personalizados](unity-quickstart-manual). ## Activar el módulo AdaptyUI del SDK de Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si planeas usar el [Paywall Builder](adapty-paywall-builder) y has instalado el módulo AdaptyUI, necesitas que AdaptyUI esté activo. Puedes activarlo durante la configuración: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetActivateUI(true); ``` ## Configuración opcional \{#optional-setup\} ### Registro de logs \{#logging\} #### Configurar el sistema de logs \{#set-up-the-logging-system\} Adapty registra errores y otra información importante para ayudarte a entender qué ocurre. Estos son los niveles disponibles: | Nivel | Descripción | | ---------- | ------------------------------------------------------------ | | `error` | Solo se registrarán los errores | | `warn` | Se registrarán los errores y los mensajes del SDK que no causan errores críticos pero merecen atención | | `info` | Se registrarán los errores, advertencias y varios mensajes informativos | | `verbose` | Se registrará cualquier información adicional que pueda ser útil durante la depuración, como llamadas a funciones, consultas a la API, etc. | Puedes establecer el nivel de log en tu app durante la configuración de Adapty: ```csharp showLineNumbers title="C#" // 'verbose' is recommended for development and the first production release var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY"); builder.LogLevel = AdaptyLogLevel.Verbose; ``` También puedes cambiar el nivel de log en tiempo de ejecución: ```csharp showLineNumbers title="C#" Adapty.SetLogLevel(AdaptyLogLevel.Verbose, (error) => { // handle result }); ``` ### Políticas de datos \{#data-policies\} Adapty no almacena datos personales de tus usuarios a menos que los envíes explícitamente, pero puedes implementar políticas adicionales de seguridad de datos para cumplir con las directrices del store o del país. #### Deshabilitar la recopilación y el uso compartido de la dirección IP \{#disable-ip-address-collection-and-sharing\} Al activar el módulo Adapty, establece `SetIPAddressCollectionDisabled` en `true` para deshabilitar la recopilación y el uso compartido de la dirección IP del usuario. El valor predeterminado es `false`. Usa este parámetro para mejorar la privacidad del usuario, cumplir con las regulaciones regionales de protección de datos (como el RGPD o la CCPA), o reducir la recopilación de datos innecesaria cuando las funciones basadas en IP no son necesarias para tu app. ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetIPAddressCollectionDisabled(true); ``` #### Deshabilitar la recopilación y el uso compartido del ID publicitario \{#disable-advertising-id-collection-and-sharing\} Al activar el módulo Adapty, establece `SetAppleIDFACollectionDisabled` y/o `SetGoogleAdvertisingIdCollectionDisabled` en `true` para deshabilitar la recopilación de identificadores publicitarios. El valor predeterminado es `false`. Usa este parámetro para cumplir con las políticas de App Store/Google Play, evitar activar el prompt de App Tracking Transparency, o si tu app no requiere atribución publicitaria ni analíticas basadas en IDs publicitarios. ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleIDFACollectionDisabled(true) .SetGoogleAdvertisingIdCollectionDisabled(true); ``` #### Configurar la caché de medios para AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Por defecto, AdaptyUI almacena en caché los medios (como imágenes y vídeos) para mejorar el rendimiento y reducir el uso de red. Puedes personalizar la configuración de la caché proporcionando una configuración personalizada. Usa `SetAdaptyUIMediaCache` para sobreescribir la configuración predeterminada de la caché: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAdaptyUIMediaCache( 100 * 1024 * 1024, // MemoryStorageTotalCostLimit 100MB null, // MemoryStorageCountLimit 100 * 1024 * 1024 // DiskStorageSizeLimit 100MB ); ``` Parámetros: | Parámetro | Obligatorio | Descripción | |-----------------------------|-------------|----------------------------------------------------------------------------------| | memoryStorageTotalCostLimit | opcional | Tamaño total de la caché en memoria en bytes. Por defecto, valor específico de la plataforma. | | memoryStorageCountLimit | opcional | El límite de número de elementos en el almacenamiento en memoria. Por defecto, valor específico de la plataforma. | | diskStorageSizeLimit | opcional | El límite de tamaño de archivo en disco en bytes. Por defecto, valor específico de la plataforma. | ### Habilitar niveles de acceso locales (Android) \{#enable-local-access-levels-android\} Por defecto, los [niveles de acceso locales](local-access-levels) están habilitados en iOS y deshabilitados en Android. Para habilitarlos también en Android, establece `SetGoogleLocalAccessLevelAllowed` en `true`: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetGoogleLocalAccessLevelAllowed(true); ``` ### Limpiar datos al restaurar desde copia de seguridad \{#clear-data-on-backup-restore\} Cuando `SetAppleClearDataOnBackup` se establece en `true`, el SDK detecta cuándo la app se restaura desde una copia de seguridad de iCloud y elimina todos los datos del SDK almacenados localmente, incluida la información de perfil en caché, los detalles del producto y los paywalls. El SDK se inicializa entonces con un estado limpio. El valor predeterminado es `false`. :::note Solo se elimina la caché local del SDK. El historial de transacciones con Apple y los datos de usuario en los servidores de Adapty permanecen sin cambios. ::: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleClearDataOnBackup(true); ``` ## Solución de problemas \{#troubleshooting\} #### Reglas de copia de seguridad de Android (configuración de Auto Backup) \{#android-backup-rules-auto-backup-configuration\} Algunos SDKs (incluido Adapty) incluyen su propia configuración de Android Auto Backup. Si utilizas varios SDKs que definen reglas de copia de seguridad, el fusionador de manifiestos de Android puede fallar con un error relacionado con `android:fullBackupContent`, `android:dataExtractionRules` o `android:allowBackup`. Síntomas típicos del error: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules) is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)` :::note Estos cambios deben realizarse en el directorio de la plataforma Android (normalmente en la carpeta `android/` de tu proyecto). ::: Para resolverlo, necesitas: - Indicar al fusionador de manifiestos que use los valores de tu app para los atributos relacionados con la copia de seguridad. - Crear archivos de reglas de copia de seguridad que combinen las reglas de Adapty con las de otros SDKs. #### 1. Añade el namespace `tools` a tu manifiesto \{#1-add-the-tools-namespace-to-your-manifest\} En tu archivo `AndroidManifest.xml`, asegúrate de que la etiqueta raíz `` incluya tools: ```xml ... ``` #### 2. Sobreescribe los atributos de copia de seguridad en `` \{#2-override-backup-attributes-in-application\} En el mismo archivo `AndroidManifest.xml`, actualiza la etiqueta `` para que tu app proporcione los valores definitivos e indique al fusionador de manifiestos que reemplace los valores de las librerías: ```xml ... ``` Si algún SDK también define `android:allowBackup`, inclúyelo en `tools:replace`: ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Crea los archivos de reglas de copia de seguridad combinadas \{#3-create-merged-backup-rules-files\} Crea archivos XML en el directorio `res/xml/` de tu proyecto Android que combinen las reglas de Adapty con las de otros SDKs. Android utiliza distintos formatos de reglas de copia de seguridad según la versión del sistema operativo, por lo que crear ambos archivos garantiza la compatibilidad con todas las versiones de Android que admite tu app. :::note Los ejemplos a continuación usan AppsFlyer como SDK de terceros de muestra. Reemplaza o añade reglas para cualquier otro SDK que uses en tu app. ::: **Para Android 12 y superior** (usa el nuevo formato de reglas de extracción de datos): ```xml title="sample_data_extraction_rules.xml" ``` **Para Android 11 e inferior** (usa el formato legado de contenido de copia de seguridad completa): ```xml title="sample_backup_rules.xml" :::important En Unity, aplica estos cambios en `Assets/Plugins/Android/AndroidManifest.xml` y crea los archivos de reglas de copia de seguridad en `Assets/Plugins/Android/res/xml/`. ::: #### Las compras fallan al volver desde otra app en Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si la Activity que inicia el flujo de compra usa un `launchMode` no predeterminado, Android puede recrearla o reutilizarla incorrectamente cuando el usuario regresa desde Google Play, una app bancaria o un navegador. Esto puede provocar que el resultado de la compra se pierda o se trate como cancelado. Para garantizar que las compras funcionen correctamente, usa solo los modos de lanzamiento `standard` o `singleTop` para la Activity que inicia el flujo de compra, y evita cualquier otro modo. En tu `AndroidManifest.xml`, asegúrate de que la Activity que inicia el flujo de compra esté configurada como `standard` o `singleTop`: ```xml ``` --- # File: unity-quickstart-paywalls --- --- title: "Habilitar compras usando paywalls en Unity SDK" description: "Aprende cómo presentar paywalls en tu aplicación Unity con el SDK de Adapty." --- Para habilitar las compras in-app, necesitas entender tres conceptos clave: - [**Productos**](product) – cualquier cosa que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida) - Los [**paywalls**](paywalls) son configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de recuperar productos, pero este diseño te permite modificar ofertas, precios y combinaciones de productos sin tocar el código de tu app. - Los [**placements**](placements) – dónde y cuándo muestras los paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita la ejecución de pruebas A/B y mostrar diferentes paywalls a distintos usuarios. Adapty te ofrece tres formas de habilitar compras en tu app. Selecciona una según los requisitos de tu aplicación: | Implementación | Complejidad | Cuándo usarla | |---------------------------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Adapty Paywall Builder | ✅ Fácil | [Creas un paywall completo y listo para compras en el editor sin código](quickstart-paywalls). Adapty lo renderiza automáticamente y gestiona todo el flujo de compra, la validación de recibos y la gestión de suscripciones entre bastidores. | | Paywalls creados manualmente | 🟡 Medio | Implementas la UI de tu paywall en el código de tu app, pero igualmente obtienes el objeto paywall de Adapty para mantener flexibilidad en las ofertas de productos. Consulta la [guía](unity-quickstart-manual). | | Modo observador | 🔴 Difícil | Ya tienes tu propia infraestructura de gestión de compras y quieres seguir usándola. Ten en cuenta que el modo observador tiene sus limitaciones en Adapty. Consulta el [artículo](observer-vs-full-mode). | :::important **Los pasos a continuación muestran cómo implementar un paywall creado en el Adapty Paywall Builder.** Si no quieres usar el Paywall Builder, consulta la [guía para gestionar compras en paywalls creados manualmente](unity-making-purchases). ::: Para mostrar un paywall creado en el Adapty Paywall Builder, en el código de tu app solo necesitas: 1. **Obtener el paywall**: Obtener el paywall de Adapty. 2. **Mostrar el paywall y Adapty gestionará las compras por ti**: Muestra el contenedor del paywall que obtuviste en tu app. 3. **Gestionar las acciones de los botones**: Asocia las interacciones del usuario con el paywall con la respuesta de tu app a ellas. Por ejemplo, abrir enlaces o cerrar el paywall cuando los usuarios pulsan botones. ## Antes de empezar \{#before-you-start\} Antes de empezar, completa estos pasos: 1. Conecta tu app al [App Store](initial_ios) y/o [Google Play](initial-android) en el Adapty Dashboard. 2. [Crea tus productos](create-product) en Adapty. 3. [Crea un paywall y añade productos](create-paywall). 4. [Crea un placement y añade tu paywall](create-placement). 5. [Instala y activa el SDK de Adapty](sdk-installation-unity) en el código de tu app. :::tip La forma más rápida de completar estos pasos es seguir la [guía de inicio rápido](quickstart) o crear paywalls y placements usando el [CLI para desarrolladores](developer-cli-quickstart). ::: ## 1. Obtener el paywall \{#1-get-the-paywall\} Tus paywalls están asociados a placements configurados en el dashboard. Los placements te permiten ejecutar distintos paywalls para diferentes audiencias o realizar [pruebas A/B](ab-tests). Para obtener un paywall creado en el Adapty Paywall Builder, necesitas: 1. Obtener el objeto `paywall` por el ID del [placement](placements) usando el método `GetPaywall` y comprobar si fue creado en el builder mediante la propiedad `HasViewConfiguration`. 2. Crear la vista del paywall usando el método `CreatePaywallView`. La vista contiene los elementos de UI y el estilo necesarios para mostrar el paywall. :::important Para obtener la configuración de la vista, debes activar el toggle **Show on device** en el Paywall Builder. De lo contrario, obtendrás una configuración de vista vacía y el paywall no se mostrará. ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if(error != null) { // handle the error return; } // Create paywall view parameters var parameters = new AdaptyUICreatePaywallViewParameters(); // Create the paywall view AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if(error != null) { // handle the error return; } // view - the paywall view ready to be presented }); }); ``` :::info Este inicio rápido proporciona la configuración mínima necesaria para mostrar un paywall. Para detalles de configuración avanzada, consulta nuestra [guía sobre cómo obtener paywalls](unity-get-pb-paywalls). ::: ## 2. Mostrar el paywall \{#2-display-the-paywall\} Ahora que tienes la configuración del paywall, basta con añadir unas pocas líneas para mostrarlo. Para mostrar el paywall, usa el método `view.Present()` en el `view` creado por el método `CreatePaywallView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreatePaywallView` otra vez para crear una nueva instancia de `view`. ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::info Para más detalles sobre cómo mostrar un paywall, consulta nuestra [guía](unity-present-paywalls). ::: ## 3. Gestionar las acciones de los botones \{#3-handle-button-actions\} Cuando los usuarios pulsan botones en el paywall, el SDK de Unity gestiona automáticamente las compras y la restauración. Sin embargo, otros botones tienen IDs personalizados o predefinidos y requieren gestionar las acciones en tu código. Por ejemplo, tu paywall probablemente tenga un botón de cerrar y URLs que abrir (p. ej., términos de uso y política de privacidad). Para gestionar estas acciones, tu clase debe implementar la interfaz `AdaptyPaywallsEventsListener` y registrarse como listener. :::tip Lee nuestras guías sobre cómo gestionar [acciones](unity-handle-paywall-actions) y [eventos](unity-handling-events) de botones. ::: ```csharp showLineNumbers title="Unity" public class YourClass : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { // Register this class as the paywall events listener Adapty.SetPaywallsEventsListener(this); } // AdaptyPaywallsEventsListener method - handles button actions public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: Application.OpenURL(action.Value); break; default: break; } } } ``` ## Próximos pasos \{#next-steps\} --- no_index: true --- import Callout from '../../../components/Callout.astro'; ¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte! Tu paywall está listo para mostrarse en la app. Prueba tus compras en el [sandbox del App Store](test-purchases-in-sandbox) o en [Google Play Store](testing-on-android) para asegurarte de que puedes completar una compra de prueba desde el paywall. Ahora necesitas [comprobar el nivel de acceso de los usuarios](unity-check-subscription-status) para asegurarte de que muestras un paywall o das acceso a las funciones de pago a los usuarios correctos. ## Ejemplo completo \{#full-example\} Así es como todos esos pasos pueden integrarse juntos en tu app. ```csharp showLineNumbers using System; using UnityEngine; using AdaptySDK; public class PaywallManager : MonoBehaviour, AdaptyPaywallsEventsListener { [SerializeField] private string placementId = "YOUR_PLACEMENT_ID"; private AdaptyUIPaywallView currentPaywallView; void Start() { // Register for paywall events Adapty.SetPaywallsEventsListener(this); GetAndDisplayPaywall(); } private void GetAndDisplayPaywall() { Adapty.GetPaywall(placementId, (paywall, error) => { if (error != null) { Debug.LogError("Error getting paywall: " + error.Message); return; } if (paywall.HasViewConfiguration) { CreateAndPresentPaywallView(paywall); } else { Debug.LogWarning("Paywall was not created using the builder"); } }); } private void CreateAndPresentPaywallView(AdaptyPaywall paywall) { var parameters = new AdaptyUICreatePaywallViewParameters(); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if (error != null) { Debug.LogError("Error creating paywall view: " + error.Message); return; } currentPaywallView = view; view.Present((presentError) => { if (presentError != null) { Debug.LogError("Error presenting paywall: " + presentError.Message); return; } Debug.Log("Paywall presented successfully"); }); }); } // AdaptyPaywallsEventsListener implementation public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: Debug.Log("Close button pressed"); view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: Application.OpenURL(action.Value); break; default: break; } } // Required interface methods (implement as needed) public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } public void PaywallViewDidSelectProduct(AdaptyUIPaywallView view, string productId) { } public void PaywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { } public void PaywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult) { } public void PaywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } public void PaywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { } public void PaywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } public void ShowPaywall() { GetAndDisplayPaywall(); } void OnDestroy() { if (currentPaywallView != null) { currentPaywallView.Dismiss(null); } } } ``` --- # File: unity-check-subscription-status --- --- title: "Comprobar el estado de la suscripción en el SDK de Unity" description: "Aprende cómo comprobar el estado de la suscripción en tu app de Unity con Adapty." --- Para decidir si los usuarios pueden acceder al contenido de pago o ver un paywall, necesitas comprobar su [nivel de acceso](access-level) en el perfil. Este artículo te muestra cómo acceder al estado del perfil para decidir qué necesitan ver los usuarios: si mostrarles un paywall o darles acceso a las funciones de pago. ## Obtener el estado de la suscripción \{#get-subscription-status\} Cuando decides si mostrar un paywall o contenido de pago a un usuario, compruebas su [nivel de acceso](access-level) en su perfil. Tienes dos opciones: - Llama a `GetProfile` si necesitas los datos más recientes del perfil de inmediato (como al iniciar la app) o quieres forzar una actualización. - Configura **actualizaciones automáticas del perfil** para mantener una copia local que se actualiza automáticamente cada vez que cambia el estado de la suscripción. ### Obtener el perfil \{#get-profile\} La forma más sencilla de obtener el estado de la suscripción es usar el método `GetProfile` para acceder al perfil: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` ### Escuchar actualizaciones de la suscripción \{#listen-to-subscription-updates\} Para recibir actualizaciones del perfil automáticamente en tu app: 1. Extiende `AdaptyEventListener` e implementa el método `OnLoadLatestProfile`: Adapty llamará a este método automáticamente cada vez que cambie el estado de la suscripción del usuario. 2. Almacena los datos del perfil actualizado cuando se llame a este método, para poder usarlos en toda la app sin realizar peticiones de red adicionales. ```csharp public class SubscriptionManager : MonoBehaviour, AdaptyEventListener { private AdaptyProfile currentProfile; void Start() { // Register this object as an Adapty event listener Adapty.SetEventListener(this); } // Store the profile when it updates public void OnLoadLatestProfile(AdaptyProfile profile) { currentProfile = profile; // Update UI, unlock content, etc. } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } // Use stored profile instead of calling getProfile() public bool HasAccess() { if (currentProfile?.AccessLevels != null && currentProfile.AccessLevels.ContainsKey("premium")) { return currentProfile.AccessLevels["premium"].IsActive; } return false; } } ``` :::note Adapty llama automáticamente a `OnLoadLatestProfile` cuando se inicia tu app, proporcionando datos de suscripción en caché incluso si el dispositivo está sin conexión. ::: ## Conectar el perfil con la lógica del paywall \{#connect-profile-with-paywall-logic\} Cuando necesitas tomar decisiones inmediatas sobre mostrar paywalls o dar acceso a funciones de pago, puedes comprobar el perfil del usuario directamente. Este enfoque es útil en situaciones como el inicio de la app, al entrar en secciones premium o antes de mostrar contenido específico. ```csharp private void CheckAccessLevel() { Adapty.GetProfile((profile, error) => { if (error != null) { Debug.LogError("Error checking access level: " + error.Message); // Show paywall if access check fails return; } var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; if (accessLevel == null || !accessLevel.IsActive) { // Show paywall if no access } }); } private void InitializePaywall() { LoadPaywall(); CheckAccessLevel(); } ``` ## Próximos pasos \{#next-steps\} Ahora que sabes cómo rastrear el estado de la suscripción, aprende a [trabajar con perfiles de usuario](unity-quickstart-identify) para asegurarte de que pueden acceder a lo que han pagado. --- # File: unity-quickstart-identify --- --- title: "Identificar usuarios en el SDK de Unity" description: "Guía de inicio rápido para configurar Adapty en la gestión de suscripciones in-app en Unity." --- :::important Esta guía es para ti si tienes tu propio sistema de autenticación. Aquí aprenderás a trabajar con perfiles de usuario en Adapty para que se integre con tu sistema de autenticación existente. ::: La forma en que gestionas las compras de los usuarios depende del modelo de autenticación de tu app: - Si tu app no utiliza autenticación de backend y no almacena datos de usuario, consulta la [sección sobre usuarios anónimos](#anonymous-users). - Si tu app tiene (o tendrá) autenticación de backend, consulta la [sección sobre usuarios identificados](#identified-users). **Conceptos clave**: - Los **perfiles** son las entidades necesarias para que funcione el SDK. Adapty los crea automáticamente. - Pueden ser anónimos **(sin customer user ID)** o identificados **(con customer user ID)**. - Proporcionas el **customer user ID** para cruzar los perfiles de Adapty con tu sistema de autenticación interno. Estas son las diferencias entre usuarios anónimos e identificados: | | Usuarios anónimos | Usuarios identificados | |-------------------------------|----------------------------------------------------------|-------------------------------------------------------------------------------------| | **Gestión de compras** | Restauración de compras a nivel de store | Mantienen el historial de compras en todos los dispositivos mediante su customer user ID | | **Gestión de perfiles** | Nuevos perfiles en cada reinstalación | El mismo perfil en todas las sesiones y dispositivos | | **Persistencia de datos** | Los datos de usuarios anónimos están vinculados a la instalación de la app | Los datos de usuarios identificados persisten entre instalaciones | ## Usuarios anónimos \{#anonymous-users\} Si no tienes autenticación de backend, **no necesitas gestionar la autenticación en el código de la app**: 1. Cuando el SDK se activa en el primer arranque de la app, Adapty **crea un nuevo perfil para el usuario**. 2. Cuando el usuario realiza una compra en la app, esta compra queda **asociada a su perfil de Adapty y a su cuenta del store**. 3. Cuando el usuario **reinstala** la app o la instala en un **nuevo dispositivo**, Adapty **crea un nuevo perfil anónimo en la activación**. 4. Si el usuario ya había realizado compras en tu app, por defecto, sus compras se sincronizan automáticamente desde el App Store al activar el SDK. Con usuarios anónimos se crearán nuevos perfiles en cada instalación, pero eso no es un problema porque, en las analíticas de Adapty, puedes [configurar qué se considerará una nueva instalación](general#4-installs-definition-for-analytics). Para los usuarios anónimos, debes contar las instalaciones por **IDs de dispositivo**. En este caso, cada instalación de la app en un dispositivo se cuenta como una instalación, incluidas las reinstalaciones. ## Usuarios identificados \{#identified-users\} Tienes dos opciones para identificar a los usuarios en la app: - [**Durante el inicio de sesión/registro:**](#during-loginsignup) Si los usuarios inician sesión después de que arranca tu app, llama a `identify()` con un customer user ID cuando se autentiquen. - [**Durante la activación del SDK:**](#during-the-sdk-activation) Si ya tienes un customer user ID almacenado cuando arranca la app, envíalo al llamar a `activate()`. :::important Por defecto, cuando Adapty recibe una compra de un Customer User ID que actualmente está asociado a otro Customer User ID, el nivel de acceso se comparte, de modo que ambos perfiles tienen acceso de pago. Puedes configurar este ajuste para transferir el acceso de pago de un perfil a otro o deshabilitar el uso compartido por completo. Consulta el [artículo](general#6-sharing-paid-access-between-user-accounts) para más detalles. ::: ### Durante el inicio de sesión/registro \{#during-loginsignup\} Si identificas a los usuarios después del arranque de la app (por ejemplo, después de que inicien sesión o se registren), usa el método `identify` para establecer su customer user ID. - Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual. - Si **ya has usado este customer user ID para identificar al usuario**, Adapty cambiará al perfil asociado a ese customer user ID. :::important Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo. ::: Espera el callback de finalización de `Identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes producen `#3006 profileWasChanged` o aterrizan en el perfil anónimo. Consulta [Orden de llamadas en el SDK de Unity](unity-sdk-call-order). ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Único para cada usuario if(error == null) { // identificación correcta } }); ``` ### Durante la activación del SDK \{#during-the-sdk-activation\} Si ya conoces un customer user ID cuando activas el SDK, puedes enviarlo en el método `activate` en lugar de llamar a `identify` por separado. Si conoces un customer user ID pero lo estableces solo después de la activación, eso significará que, al activarse, Adapty creará un nuevo perfil anónimo y cambiará al existente solo después de que llames a `identify`. Puedes pasar un customer user ID existente (uno que hayas usado antes) o uno nuevo. Si pasas uno nuevo, el nuevo perfil creado al activarse se vinculará automáticamente al customer user ID. :::note Por defecto, la creación de perfiles anónimos no afecta a los dashboards de analíticas, ya que las instalaciones se cuentan por IDs de dispositivo. Un ID de dispositivo representa una única instalación de la app desde el store en un dispositivo y solo se regenera tras reinstalar la app. No depende de si es una primera instalación o una reinstalación, ni de si se usa un customer user ID existente. Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app sin reinstalarla no genera eventos de instalación adicionales. Si quieres contar las instalaciones por usuarios únicos en lugar de dispositivos, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```csharp showLineNumbers using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID"); // Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo. Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` ### Cerrar sesión de usuarios \{#log-users-out\} Si tienes un botón para cerrar la sesión de los usuarios, usa el método `logout`. :::important Cerrar la sesión de los usuarios crea un nuevo perfil anónimo para el usuario. ::: ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // cierre de sesión correcto } }); ``` :::info Para volver a iniciar sesión en la app, usa el método `identify`. ::: ### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\} Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu app, debes asegurarte de que mantengan el acceso tras iniciar sesión: 1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo. 2. Cuando el usuario inicia sesión en su cuenta, Adapty cambia al perfil identificado. - Si es un nuevo customer user ID (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que se mantiene todo el historial de compras. - Si es un customer user ID existente (el customer user ID ya está vinculado a un perfil), necesitas obtener el nivel de acceso actual tras el cambio de perfil. Puedes llamar a [`getProfile`](unity-check-subscription-status) justo después de la identificación, o [escuchar las actualizaciones del perfil](unity-check-subscription-status) para que los datos se sincronicen automáticamente. ## Próximos pasos \{#next-steps\} ¡Enhorabuena! Has implementado la lógica de pago in-app en tu app. ¡Te deseamos todo el éxito con la monetización de tu app! Para sacar aún más partido a Adapty, puedes explorar estos temas: - [**Pruebas**](troubleshooting-test-purchases): Asegúrate de que todo funciona como se espera - [**Onboardings**](onboardings): Engancha a los usuarios con onboardings e impulsa la retención - [**Integraciones**](configuration): Intégrate con servicios de atribución de marketing y analíticas con solo una línea de código - [**Establecer atributos de perfil personalizados**](unity-setting-user-attributes): Añade atributos personalizados a los perfiles de usuario y crea segmentos para lanzar pruebas A/B o mostrar diferentes paywalls a distintos usuarios --- # File: adapty-cursor-unity --- --- title: "Integra Adapty en tu app de Unity con IA" description: "Una guía paso a paso para integrar Adapty en tu app de Unity usando Cursor, Context7, ChatGPT, Claude u otras herramientas de IA." --- Esta página describe dos formas de integrar Adapty en tu app de Unity. Usa la skill de integración del SDK para un flujo automatizado de extremo a extremo, o sigue el recorrido manual más abajo. ## Usa la skill de integración del SDK (beta) \{#use-the-sdk-integration-skill-beta\} La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de principio a fin: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. El recorrido manual más abajo es el plan B si tu herramienta no admite el formato Claude Skills. **Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. ### Instalación \{#install\} Elige el formato según tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill). - **Claude Code**: Ejecuta `claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill` y luego `claude plugin install adapty-sdk-integration@adapty` desde tu terminal. - **GitHub Copilot CLI**: Ejecuta `gh skill install adaptyteam/adapty-sdk-integration-skill`. - **Gemini CLI**: Ejecuta `gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill`. - **OpenAI Codex u otra herramienta**: Clona el repositorio y copia `plugins/adapty-sdk-integration/skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta. ### Ejecución \{#run\} En tu proyecto, ejecuta `/adapty-sdk-integration`. La skill detecta tu plataforma y hace algunas preguntas de configuración. Luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación, consultando la documentación de Adapty en cada etapa. :::note La skill está en beta. Si se detiene o se comporta de forma inesperada, el recorrido manual de más abajo cubre cada etapa paso a paso. ::: ## Antes de empezar: configuración del dashboard \{#before-you-start-dashboard-setup\} Adapty requiere cierta configuración en el dashboard antes de escribir código. Puedes hacerlo con una skill interactiva de LLM o manualmente desde el Dashboard. ### Con la skill (recomendado) \{#skill-approach-recommended\} La skill de la CLI de Adapty permite que tu LLM configure tu app, productos, niveles de acceso, paywalls y placements directamente, sin abrir el Dashboard en cada paso. Solo necesitas [conectar tus stores](integrate-payments) en el Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Una vez añadida la skill, ejecuta `/adapty-cli` en tu agente. Te guiará por cada paso, incluido cuándo abrir el Dashboard para conectar tus stores. ### Con el Dashboard \{#dashboard-approach\} Si prefieres configurar todo manualmente, esto es lo que necesitas antes de escribir código. Tu LLM no puede buscar los valores del dashboard por ti — tendrás que proporcionárselos. 1. **Conecta tus app stores**: En el Adapty Dashboard, ve a **App settings → General**. Conecta tanto App Store como Google Play si tu app de Unity apunta a ambas plataformas. Esto es obligatorio para que las compras funcionen. [Conectar app stores](integrate-payments) 2. **Copia tu clave pública del SDK**: En el Adapty Dashboard, ve a **App settings → General** y busca la sección **API keys**. En el código, es la cadena que pasas al constructor de configuración de Adapty. 3. **Crea al menos un producto**: En el Adapty Dashboard, ve a la página **Products**. No haces referencia a los productos directamente en el código — Adapty los entrega a través de los paywalls. [Añadir productos](quickstart-products) 4. **Crea un paywall y un placement**: En el Adapty Dashboard, crea un paywall en la página **Paywalls** y asígnalo a un placement en la página **Placements**. En el código, el ID del placement es la cadena que pasas a `Adapty.GetPaywall("YOUR_PLACEMENT_ID")`. [Crear paywall](quickstart-paywalls) 5. **Configura los niveles de acceso**: En el Adapty Dashboard, configúralos por producto en la página **Products**. En el código, la cadena que se comprueba en `profile.AccessLevels["premium"]?.IsActive`. El nivel de acceso `premium` predeterminado funciona para la mayoría de las apps. Si los usuarios de pago acceden a funciones distintas según el producto (por ejemplo, un plan `basic` frente a un plan `pro`), [crea niveles de acceso adicionales](assigning-access-level-to-a-product) antes de empezar a programar. :::tip Con estos cinco elementos listos, ya puedes escribir código. Dile a tu LLM: "Mi clave pública del SDK es X, mi ID de placement es Y" para que pueda generar el código correcto de inicialización y obtención del paywall. ::: ### Configura cuando estés listo \{#set-up-when-ready\} Estos elementos no son necesarios para empezar a programar, pero los querrás a medida que tu integración madure: - **Pruebas A/B**: Configúralas en la página **Placements**. No requieren cambios en el código. [Pruebas A/B](ab-tests) - **Paywalls y placements adicionales**: Añade más llamadas a `GetPaywall` con distintos IDs de placement. - **Integraciones de analíticas**: Configúralas en la página **Integrations**. La configuración varía según la integración. Consulta [integraciones de analíticas](analytics-integration) e [integraciones de atribución](attribution-integration). ## Proporciona la documentación de Adapty a tu LLM \{#feed-adapty-docs-to-your-llm\} ### Usa Context7 (recomendado) \{#use-context7-recommended\} [Context7](https://context7.com) es un servidor MCP que da a tu LLM acceso directo a la documentación actualizada de Adapty. El LLM obtiene automáticamente la documentación adecuada según lo que le preguntes — sin necesidad de pegar URLs manualmente. Context7 funciona con **Cursor**, **Claude Code**, **Windsurf** y otras herramientas compatibles con MCP. Para configurarlo, ejecuta: ``` npx ctx7 setup ``` Esto detecta tu editor y configura el servidor Context7. Para la configuración manual, consulta el [repositorio de Context7 en GitHub](https://github.com/upstash/context7). Una vez configurado, haz referencia a la biblioteca de Adapty en tus prompts: ``` Use the adaptyteam/adapty-docs library to look up how to install the Unity SDK ``` :::warning Aunque Context7 elimina la necesidad de pegar enlaces de documentación manualmente, el orden de implementación sigue siendo importante. Sigue el [recorrido de implementación](#implementation-walkthrough) paso a paso para asegurarte de que todo funciona correctamente. ::: ### Usa la documentación en texto plano \{#use-plain-text-docs\} Puedes acceder a cualquier artículo de Adapty en texto plano Markdown. Añade `.md` al final de su URL o haz clic en **Copy for LLM** debajo del título del artículo. Por ejemplo: [adapty-cursor-unity.md](https://adapty.io/docs/es/adapty-cursor-unity.md). Cada etapa del [recorrido de implementación](#implementation-walkthrough) incluye un bloque "Envía esto a tu LLM" con enlaces `.md` para pegar. Para acceder a más documentación a la vez, consulta los [archivos índice y subconjuntos por plataforma](#plain-text-doc-index-files) más abajo. ## Recorrido de implementación \{#implementation-walkthrough\} El resto de esta guía recorre la integración de Adapty en orden de implementación. Cada etapa incluye la documentación que debes enviar a tu LLM, lo que deberías ver al terminar y los problemas más comunes. ### Planifica tu integración \{#plan-your-integration\} Antes de ponerte a programar, pide a tu LLM que analice tu proyecto y cree un plan de implementación. Si tu herramienta de IA admite un modo de planificación (como el de Cursor o Claude Code), úsalo para que el LLM pueda leer tanto la estructura de tu proyecto como la documentación de Adapty antes de escribir código. Indica a tu LLM qué enfoque usas para las compras — esto determina las guías que debe seguir: - [**Adapty Paywall Builder**](adapty-paywall-builder): Creas paywalls en el editor no-code de Adapty y el SDK los renderiza automáticamente. - [**Paywalls creados manualmente**](unity-making-purchases): Construyes tu propia interfaz de paywall en código, pero usas Adapty para obtener los productos y gestionar las compras. - [**Modo Observer**](observer-vs-full-mode): Mantienes tu infraestructura de compras existente y usas Adapty solo para analíticas e integraciones. ¿No sabes cuál elegir? Lee la [tabla comparativa del quickstart](unity-quickstart-paywalls). ### Instala y configura el SDK \{#install-and-configure-the-sdk\} Añade el paquete del SDK de Adapty a través del Unity Package Manager y actívalo con tu clave pública del SDK. Esta es la base — nada más funciona sin ella. **Guía:** [Instalar y configurar el SDK de Adapty](sdk-installation-unity) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/sdk-installation-unity.md ``` :::tip[Punto de control] - **Esperado:** El proyecto compila y se ejecuta. La consola de Unity muestra el log de activación de Adapty. - **Problema frecuente:** "Public API key is missing" → comprueba que hayas reemplazado el marcador de posición con tu clave real de App settings. ::: ### Muestra paywalls y gestiona las compras \{#show-paywalls-and-handle-purchases\} Obtén un paywall por ID de placement, muéstralo y gestiona los eventos de compra. Las guías que necesitas dependen de cómo gestionas las compras. Prueba cada compra en el sandbox a medida que avances — no esperes al final. Consulta [Probar compras en sandbox](test-purchases-in-sandbox) para las instrucciones de configuración. **Guías:** - [Habilitar compras con paywalls (quickstart)](unity-quickstart-paywalls) - [Obtener paywalls del Paywall Builder y su configuración](unity-get-pb-paywalls) - [Mostrar paywalls](unity-present-paywalls) - [Gestionar eventos de paywall](unity-handling-events) - [Responder a acciones de botones](unity-handle-paywall-actions) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/unity-quickstart-paywalls.md - https://adapty.io/docs/es/unity-get-pb-paywalls.md - https://adapty.io/docs/es/unity-present-paywalls.md - https://adapty.io/docs/es/unity-handling-events.md - https://adapty.io/docs/es/unity-handle-paywall-actions.md ``` :::tip[Punto de control] - **Esperado:** El paywall aparece con tus productos configurados. Al pulsar un producto se abre el diálogo de compra en sandbox. - **Problema frecuente:** Paywall vacío o error en `GetPaywall` → verifica que el ID de placement coincide exactamente con el del dashboard y que el placement tiene una audiencia asignada. ::: **Guías:** - [Habilitar compras en tu paywall personalizado (quickstart)](unity-quickstart-manual) - [Obtener paywalls y productos](fetch-paywalls-and-products-unity) - [Renderizar paywalls diseñados con Remote Config](present-remote-config-paywalls-unity) - [Realizar compras](unity-making-purchases) - [Restaurar compras](unity-restore-purchase) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/unity-quickstart-manual.md - https://adapty.io/docs/es/fetch-paywalls-and-products-unity.md - https://adapty.io/docs/es/present-remote-config-paywalls-unity.md - https://adapty.io/docs/es/unity-making-purchases.md - https://adapty.io/docs/es/unity-restore-purchase.md ``` :::tip[Punto de control] - **Esperado:** Tu paywall personalizado muestra los productos obtenidos de Adapty. Al pulsar un producto se abre el diálogo de compra en sandbox. - **Problema frecuente:** Array de productos vacío → verifica que el paywall tiene productos asignados en el dashboard y que el placement tiene una audiencia. ::: **Guías:** - [Descripción general del modo Observer](observer-vs-full-mode) - [Implementar el modo Observer](implement-observer-mode-unity) - [Reportar transacciones en modo Observer](report-transactions-observer-mode-unity) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/observer-vs-full-mode.md - https://adapty.io/docs/es/implement-observer-mode-unity.md - https://adapty.io/docs/es/report-transactions-observer-mode-unity.md ``` :::tip[Punto de control] - **Esperado:** Tras una compra en sandbox usando tu flujo de compras existente, la transacción aparece en el **Event Feed** del dashboard de Adapty. - **Problema frecuente:** Sin eventos → verifica que estás reportando las transacciones a Adapty y que las notificaciones del servidor están configuradas para ambos stores. ::: ### Comprueba el estado de la suscripción \{#check-subscription-status\} Tras una compra, comprueba el perfil de usuario para ver si hay un nivel de acceso activo que permita el acceso al contenido premium. **Guía:** [Comprobar el estado de la suscripción](unity-check-subscription-status) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/unity-check-subscription-status.md ``` :::tip[Punto de control] - **Esperado:** Tras una compra en sandbox, `profile.AccessLevels["premium"]?.IsActive` devuelve `true`. - **Problema frecuente:** `AccessLevels` vacío tras la compra → comprueba que el producto tiene un nivel de acceso asignado en el dashboard. ::: ### Identifica a los usuarios \{#identify-users\} Vincula las cuentas de usuario de tu app con los perfiles de Adapty para que las compras persistan entre dispositivos. :::important Omite este paso si tu app no tiene autenticación. ::: **Guía:** [Identificar usuarios](unity-quickstart-identify) Envía esto a tu LLM: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/es/unity-quickstart-identify.md ``` :::tip[Punto de control] - **Esperado:** Tras llamar a `Adapty.Identify("your-user-id")`, la sección **Profiles** del dashboard muestra tu ID de usuario personalizado. - **Problema frecuente:** Llama a `Identify` después de la activación pero antes de obtener los paywalls para evitar problemas de atribución con perfiles anónimos. ::: ### Prepárate para el lanzamiento \{#prepare-for-release\} Una vez que tu integración funcione en el sandbox, revisa la lista de verificación de lanzamiento para asegurarte de que todo está listo para producción. **Guía:** [Lista de verificación para el lanzamiento](release-checklist) Envía esto a tu LLM: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/es/release-checklist.md ``` :::tip[Punto de control] - **Esperado:** Todos los elementos de la lista confirmados: conexiones de stores, notificaciones del servidor, flujo de compras, comprobaciones de nivel de acceso y requisitos de privacidad. - **Problema frecuente:** Notificaciones del servidor no configuradas → configura las App Store Server Notifications en **App settings → iOS SDK** y las Google Play Real-Time Developer Notifications en **App settings → Android SDK**. ::: ## Archivos índice de documentación en texto plano \{#plain-text-doc-index-files\} Si necesitas dar a tu LLM un contexto más amplio más allá de páginas individuales, ofrecemos archivos índice que listan o combinan toda la documentación de Adapty: - [`llms.txt`](https://adapty.io/docs/es/llms.txt): Lista todas las páginas con enlaces `.md`. Es un [estándar emergente](https://llmstxt.org/) para hacer los sitios web accesibles a los LLMs. Ten en cuenta que para algunos agentes de IA (por ejemplo, ChatGPT) necesitarás descargar `llms.txt` y subirlo al chat como archivo. - [`llms-full.txt`](https://adapty.io/docs/es/llms-full.txt): Toda la documentación del sitio de Adapty combinada en un único archivo. Muy grande — úsalo solo cuando necesites el panorama completo. - Subconjuntos específicos de Unity: [`unity-llms.txt`](https://adapty.io/docs/es/unity-llms.txt) y [`unity-llms-full.txt`](https://adapty.io/docs/es/unity-llms-full.txt): Subconjuntos específicos de la plataforma que ahorran tokens en comparación con el sitio completo. --- # File: unity-get-pb-paywalls --- --- title: "Obtener paywalls del Paywall Builder y su configuración en el SDK de Unity" description: "Aprende a recuperar paywalls de PB en Adapty para un mejor control de suscripciones en tu app de Unity." --- Después de [diseñar la parte visual de tu paywall](adapty-paywall-builder) con el nuevo Paywall Builder en el Adapty Dashboard, puedes mostrarlo en tu app móvil. El primer paso es obtener el paywall asociado al placement y su configuración de vista, tal como se describe a continuación. :::warning El nuevo Paywall Builder funciona con el SDK de Unity versión 3.3.0 o superior. ::: Ten en cuenta que este tema hace referencia a paywalls personalizados con Paywall Builder. Si estás implementando tus paywalls manualmente, consulta el tema [Obtener paywalls y productos para paywalls de Remote Config en tu app móvil](fetch-paywalls-and-products-unity). :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. :::
Antes de empezar a mostrar paywalls en tu app móvil (haz clic para expandir) 1. [Crea tus productos](create-product) en el Adapty Dashboard. 2. [Crea un paywall e incorpora los productos en él](create-paywall) en el Adapty Dashboard. 3. [Crea placements e incorpora tu paywall en ellos](create-placement) en el Adapty Dashboard. 4. Instala el [SDK de Adapty](sdk-installation-unity) en tu app móvil.
## Obtener el paywall diseñado con Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si has [diseñado un paywall con el Paywall Builder](adapty-paywall-builder), no necesitas preocuparte por renderizarlo en el código de tu app móvil para mostrárselo al usuario. Este tipo de paywall contiene tanto lo que debe mostrarse como la forma en que debe mostrarse. Aun así, necesitas obtener su ID a través del placement, su configuración de vista, y luego presentarlo en tu app móvil. Para garantizar un rendimiento óptimo, es fundamental recuperar el paywall y su [configuración de vista](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) lo antes posible, dejando tiempo suficiente para que las imágenes se descarguen antes de presentarlas al usuario. Para obtener un paywall, usa el método `GetPaywall`: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | requerido | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta es para el idioma, la segunda para la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre códigos de idioma y cómo recomendamos usarlos.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización regular descrita arriba y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para que siempre obtengas la versión más reciente de tus paywalls, garantizando fiabilidad incluso cuando la conexión a internet es escasa.

| | **loadTimeout** | por defecto: 5 seg |

Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local.

Ten en cuenta que en casos excepcionales este método puede agotar el tiempo ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente.

| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) con una lista de IDs de productos, el identificador del paywall, Remote Config y varias otras propiedades. | ## Obtener la configuración de vista del paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el toggle **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye una `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te orientará sobre cómo mostrar el paywall. Si la `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-unity). En el SDK de Unity, llama directamente al método `CreatePaywallView` sin necesidad de obtener primero la configuración de vista manualmente. :::warning El resultado del método `CreatePaywallView` solo puede usarse una vez. Si necesitas usarlo de nuevo, vuelve a llamar al método `CreatePaywallView`. Llamarlo dos veces sin recrearlo puede resultar en el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers var parameters = new AdaptyUICreatePaywallViewParameters() .SetPreloadProducts(preloadProducts) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------ | :------------- | :----------------------------------------------------------- | | **paywall** | requerido | Un objeto `AdaptyPaywall` para obtener un controlador para el paywall deseado. | | **loadTimeout** | por defecto: 5 seg | Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local. Ten en cuenta que en casos excepcionales este método puede agotar el tiempo ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente. | | **PreloadProducts** | opcional | Proporciona un array de `AdaptyPaywallProducts` para optimizar el tiempo de visualización de los productos en pantalla. Si se pasa `nil`, AdaptyUI obtendrá automáticamente los productos necesarios. | | **CustomTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido del paywall, reemplazados dinámicamente por cadenas específicas para contenido personalizado. Consulta el tema [Etiquetas personalizadas en el Paywall Builder](custom-tags-in-paywall-builder) para más detalles. | | **CustomTimers** | opcional | Define un diccionario de temporizadores personalizados y sus fechas de finalización. Los temporizadores personalizados te permiten mostrar cuentas regresivas en tu paywall. | :::note Si usas varios idiomas, aprende cómo añadir una [localización del Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](localizations-and-locale-codes). ::: Una vez que tengas la vista, [presenta el paywall](unity-present-paywalls). ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa los recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizado, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el dashboard de Adapty. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Adapty para Unity a la versión 3.8.0 o superior. ::: A continuación se muestra un ejemplo de cómo proporcionar recursos personalizados mediante un diccionario simple: ```csharp showLineNumbers var customAssets = new Dictionary { { "custom_image", AdaptyCustomAsset.LocalImageFile("custom_assets/images/custom_image.png") }, { "hero_video", AdaptyCustomAsset.LocalVideoFile("custom_assets/videos/custom_video.mp4") } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomAssets(customAssets) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` :::note Si no se encuentra un recurso, el paywall usará su apariencia predeterminada. ::: ## Configurar temporizadores definidos por el desarrollador \{#set-up-developer-defined-timers\} Para usar temporizadores personalizados en tu app de Unity, puedes pasar un diccionario de IDs de temporizadores y sus fechas de finalización directamente al método `SetCustomTimers`. Aquí tienes un ejemplo: ```csharp showLineNumbers var customTimers = new Dictionary { { "CUSTOM_TIMER_6H", DateTime.Now.AddHours(6) }, { "CUSTOM_TIMER_NY", new DateTime(2025, 1, 1) } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomTimers(customTimers) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` En este ejemplo, `CUSTOM_TIMER_NY` y `CUSTOM_TIMER_6H` son los **Timer ID** de los temporizadores definidos por el desarrollador que configuraste en el Adapty Dashboard. El resolvedor de temporizadores garantiza que tu app actualice dinámicamente cada temporizador con el valor correcto. Por ejemplo: - `CUSTOM_TIMER_NY`: El tiempo restante hasta el final del temporizador, como el Año Nuevo. - `CUSTOM_TIMER_6H`: El tiempo restante en un período de 6 horas que comenzó cuando el usuario abrió el paywall. ## Acelerar la obtención del paywall con el paywall de audiencia predeterminada \{#speed-up-paywall-fetching-with-default-audience-paywall\} Normalmente, los paywalls se obtienen casi al instante, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, en casos en los que tengas numerosas audiencias y paywalls, y tus usuarios tengan una conexión a internet débil, obtener un paywall puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un paywall predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún paywall. Para abordar esto, puedes usar el método `GetPaywallForDefaultAudience`, que obtiene el paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, como se detalla en la sección [Obtener paywall](#fetch-paywall) anterior. :::warning Considera usar `GetPaywall` en lugar de `GetPaywallForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede crear problemas al dar soporte a varias versiones de la app, requiriendo diseños compatibles con versiones anteriores o aceptando que las versiones más antiguas puedan mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si la obtención más rápida supera estos inconvenientes para tu caso de uso, usa `GetPaywallForDefaultAudience` como se muestra a continuación. De lo contrario, usa `GetPaywall` como se describe [arriba](#fetch-paywall). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requerido | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la localización del paywall. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta es para el idioma, la segunda para la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización regular descrita arriba y los paywalls de respaldo. También usamos CDN para obtener paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para que siempre obtengas la versión más reciente de tus paywalls, garantizando fiabilidad incluso cuando la conexión a internet es escasa.

| --- # File: unity-present-paywalls --- --- title: "Mostrar paywalls" description: "Aprende cómo mostrar paywalls en tu app de Unity con el SDK de Adapty." --- Si has personalizado un paywall con el Paywall Builder, no necesitas preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Ese paywall contiene tanto lo que debe mostrarse como la forma en que debe hacerse. :::warning Esta guía cubre el **nuevo Paywall Builder**, que requiere el SDK de Adapty 3.3.0 o posterior. Para mostrar paywalls con Remote Config, consulta [Renderizar paywalls diseñados con remote config](present-remote-config-paywalls). ::: Para mostrar un paywall, usa el método `view.Present()` sobre el `view` creado por el método [`CreatePaywallView`](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreatePaywallView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Mostrar diálogo \{#show-dialog\} Usa este método en lugar de los diálogos de alerta nativos cuando hay un paywall visible en Android. En Android, las alertas normales aparecen detrás del paywall y el usuario no puede verlas. Este método garantiza que el diálogo se muestre correctamente por encima del paywall en todas las plataformas. ```csharp showLineNumbers title="Unity" var dialog = new AdaptyUIDialogConfiguration() .SetTitle("Close paywall?") .SetContent("You will lose access to exclusive offers.") .SetDefaultActionTitle("Stay") .SetSecondaryActionTitle("Close"); AdaptyUI.ShowDialog(view, dialog, (action, error) => { if (error == null) { if (action == AdaptyUIDialogActionType.Secondary) { // User confirmed - close the paywall view.Dismiss(); } // If primary - do nothing, user stays } }); ``` ## Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el paywall en iOS pasando el parámetro `iosPresentationStyle` al método `Present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.FullScreen` (predeterminado) o `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` --- # File: unity-handle-paywall-actions --- --- title: "Responder a acciones de botones en el SDK de Unity" description: "Gestiona las acciones de botones de paywall en Unity usando Adapty para una mejor monetización de la app." --- Si estás creando paywalls con el Paywall Builder de Adapty, es fundamental configurar los botones correctamente: 1. Añade un [botón en el Paywall Builder](paywall-buttons) y asígnale una acción existente o crea un ID de acción personalizado. 2. Escribe código en tu app para gestionar cada acción que hayas asignado. Esta guía muestra cómo gestionar acciones personalizadas y predefinidas en tu código. :::warning **Solo las compras y restauraciones se gestionan automáticamente.** El resto de acciones de botones, como cerrar paywalls o abrir enlaces, requieren implementar respuestas específicas en el código de la app. ::: ## Cerrar paywalls \{#close-paywalls\} Para añadir un botón que cierre tu paywall: 1. En el Paywall Builder, añade un botón y asígnale la acción **Close**. 2. En el código de tu app, implementa un handler para la acción `close` que descarte el paywall. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; default: // handle other events break; } } ``` ## Abrir URLs desde paywalls \{#open-urls-from-paywalls\} :::tip Si quieres añadir un grupo de enlaces (p. ej., términos de uso y restauración de compras), añade un elemento **Link** en el Paywall Builder y gestíonalo igual que los botones con la acción **Open URL**. ::: Para añadir un botón que abra un enlace desde tu paywall (p. ej., **Terms of use** o **Privacy policy**): 1. En el Paywall Builder, añade un botón, asígnale la acción **Open URL** e introduce la URL que quieres abrir. 2. En el código de tu app, implementa un handler para la acción `openUrl` que abra la URL recibida en un navegador. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if(!string.IsNullOrWhiteSpace(urlString)) { Application.OpenURL(urlString); } break; default: // handle other events break; } } ``` ## Iniciar sesión en la app \{#log-into-the-app\} Para añadir un botón que permita a los usuarios iniciar sesión en tu app: 1. En el Paywall Builder, añade un botón y asígnale la acción **Custom** con el ID `login`. 2. En el código de tu app, implementa un handler para la acción personalizada `login` que identifique a tu usuario. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "login") { // Navigate to login scene SceneManager.LoadScene("LoginScene"); } break; default: // handle other events break; } } ``` ## Gestionar acciones personalizadas \{#handle-custom-actions\} Para añadir un botón que gestione cualquier otra acción: 1. En el Paywall Builder, añade un botón, asígnale la acción **Custom** y asígnale un ID. 2. En el código de tu app, implementa un handler para el ID de acción que hayas creado. Por ejemplo, si tienes otro conjunto de ofertas de suscripción o compras únicas, puedes añadir un botón que muestre otro paywall: ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "openNewPaywall") { // Display another paywall ShowAlternativePaywall(); } break; default: // handle other events break; } } private void ShowAlternativePaywall() { // Implement your logic to show alternative paywall } ``` --- # File: unity-handling-events --- --- title: "Gestionar eventos del paywall" description: "Aprende a gestionar eventos del paywall en tu aplicación Unity con el SDK de Adapty." --- :::important Esta guía cubre la gestión de eventos para compras, restauraciones, selección de productos y renderizado del paywall. También debes implementar el manejo de botones (cerrar paywall, abrir enlaces, etc.). Consulta nuestra [guía sobre el manejo de acciones de botones](unity-handle-paywall-actions) para más detalles. ::: Los paywalls configurados con el [Paywall Builder](adapty-paywall-builder) no necesitan código adicional para realizar y restaurar compras. Sin embargo, generan ciertos eventos a los que tu aplicación puede responder. Estos eventos incluyen pulsaciones de botones (botones de cierre, URLs, selecciones de productos, etc.), así como notificaciones sobre acciones relacionadas con compras realizadas en el paywall. A continuación aprenderás cómo responder a estos eventos. :::warning Esta guía es **exclusivamente para paywalls del nuevo Paywall Builder**, que requieren el SDK de Adapty v3.3.0 o posterior. ::: :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Gestión de eventos \{#handling-events\} Para controlar o monitorear los procesos que ocurren en la pantalla del paywall dentro de tu aplicación móvil, implementa la interfaz `AdaptyPaywallsEventsListener`: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; public class PaywallEventsHandler : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { Adapty.SetPaywallsEventsListener(this); } // Implement all required interface methods below } ``` ### Eventos generados por el usuario \{#user-generated-events\} #### Paywall mostrado \{#paywall-appeared\} Se invoca cuando la vista del paywall aparece en pantalla. :::note En iOS, también se invoca cuando el usuario pulsa el [botón del web paywall](web-paywall#step-2a-add-a-web-purchase-button) dentro de un paywall y el web paywall se abre en un navegador integrado. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### Paywall ocultado \{#paywall-disappeared\} Se invoca cuando la vista del paywall desaparece de la pantalla. :::note En iOS, también se invoca cuando un [web paywall](web-paywall#step-2a-add-a-web-purchase-button) abierto desde un paywall en un navegador integrado desaparece de la pantalla. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### Selección de producto \{#product-selection\} Se invoca cuando se selecciona un producto para comprar (por el usuario o por el sistema). ```csharp showLineNumbers title="Unity" public void PaywallViewDidSelectProduct( AdaptyUIPaywallView view, string productId ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "productId": "premium_monthly" } ```
#### Compra iniciada \{#started-purchase\} Se invoca cuando el usuario inicia el proceso de compra. ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### Compra exitosa, cancelada o pendiente \{#successful-canceled-or-pending-purchase\} Si la compra se completa correctamente, el usuario la cancela, o queda en estado pendiente, se invocará este método. Las cancelaciones del usuario y los pagos pendientes (como los que requieren aprobación parental) activan este método, no `PaywallViewDidFailPurchase`. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { } ```
Ejemplos de eventos (Haz clic para expandir) ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Cancelled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCancelled" } } // Pending purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Pending" } } ```
Recomendamos cerrar la pantalla en ese caso. #### Compra fallida \{#failed-purchase\} Si una compra falla debido a un error, se invocará este método. Esto incluye errores de StoreKit/Google Play Billing (restricciones de pago, productos inválidos, fallos de red), errores de verificación de transacciones y errores del sistema. Ten en cuenta que las cancelaciones del usuario activan `PaywallViewDidFinishPurchase` con un resultado de cancelación, y los pagos pendientes no activan este método. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ```
#### Restauración iniciada \{#started-restore\} Se invoca cuando el usuario inicia el proceso de restauración: ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### Restauración exitosa \{#successful-restore\} Se invoca cuando la restauración de compras se completa correctamente: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishRestore( AdaptyUIPaywallView view, AdaptyProfile profile ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ```
Recomendamos cerrar la pantalla si el usuario tiene el `accessLevel` requerido. Consulta el tema [Estado de la suscripción](unity-listen-subscription-changes) para aprender cómo verificarlo. #### Restauración fallida \{#failed-restore\} Se invoca cuando la restauración de compras falla: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRestore( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### Navegación web de pago finalizada \{#finished-web-payment-navigation\} Después de intentar abrir un [web paywall](web-paywall) para realizar una compra (tanto si tuvo éxito como si falló), se invocará este método: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishWebPaymentNavigation( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` **Parámetros:** - `product`: El producto para el que se abrió (o intentó abrir) el web paywall - `error`: `null` si el web paywall se abrió correctamente, o un `AdaptyError` si falló
Ejemplos de eventos (Haz clic para expandir) ```javascript // Successful navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "wrong_param", "message": "Current method is not available for this product", "details": { "underlyingError": "Product not configured for web purchases" } } } ```
### Obtención de datos y renderizado \{#data-fetching-and-rendering\} #### Errores de carga de productos \{#product-loading-errors\} Se invoca cuando falla la carga de productos y proporciona un `AdaptyError`. Si no pasaste el array de productos durante la inicialización, AdaptyUI recuperará los objetos necesarios del servidor por sí solo. Esta operación puede fallar, y AdaptyUI reportará el error invocando este método: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailLoadingProducts( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
#### Errores de renderizado \{#rendering-errors\} Se invoca cuando ocurre un error durante el renderizado de la interfaz y proporciona un `AdaptyError`: ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRendering( AdaptyUIPaywallView view, AdaptyError error ) { } ```
Ejemplo de evento (Haz clic para expandir) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ```
En condiciones normales, estos errores no deberían producirse, por lo que si encuentras alguno, por favor haznos saber. --- # File: unity-web-paywalls --- --- title: "Implementar web paywalls en Unity SDK" description: "Configura un web paywall para cobrar sin las comisiones y auditorías del App Store." --- :::important Antes de comenzar, asegúrate de haber [configurado tu web paywall en el dashboard](web-paywall) y de tener instalada la versión 3.14 o posterior del SDK de Adapty. ::: ## Abrir web paywalls \{#open-web-paywalls\} Si trabajas con un paywall que has desarrollado tú mismo, necesitas gestionar los web paywalls mediante el método del SDK. El método `Adapty.OpenWebPaywall`: 1. Genera una URL única que permite a Adapty vincular un paywall concreto mostrado a un usuario con la página web a la que se le redirige. 2. Detecta cuando tus usuarios vuelven a la app y, a continuación, llama a `Adapty.GetProfile` en intervalos cortos para determinar si se han actualizado los derechos de acceso del perfil. De este modo, si el pago se ha realizado con éxito y los derechos de acceso se han actualizado, la suscripción se activa en la app casi de inmediato. ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` :::note Existen dos versiones del método `OpenWebPaywall`: 1. `OpenWebPaywall(product)`, que genera URLs a partir del paywall y también añade los datos del producto a las URLs. 2. `OpenWebPaywall(paywall)`, que genera URLs a partir del paywall sin añadir los datos del producto a las URLs. Úsalo cuando los productos de tu paywall en Adapty sean distintos a los del web paywall. ::: #### Gestionar errores \{#handle-errors\} | Código de error | Descripción | Acción recomendada | |-----------|--------------------------------------------------------|---------------------------------------------------------------------------| | `AdaptyErrorCode.WrongParam` | El paywall o el producto no tiene configurada una URL de compra web, o no se pudo abrir la URL en el navegador | Revisa el mensaje de error para más detalles. Verifica la configuración del paywall/producto en el Adapty Dashboard, o comprueba la configuración del dispositivo. | | `AdaptyErrorCode.DecodingFailed` | No se pudieron codificar correctamente los parámetros en la URL | Verifica que los parámetros de la URL sean válidos y estén correctamente formateados | :::note Consulta la propiedad `Message` del error para obtener detalles concretos sobre qué salió mal, ya que `WrongParam` puede indicar varios problemas (URL de compra ausente, error al abrir el navegador, etc.). ::: ## Abrir web paywalls en un navegador in-app \{#open-web-paywalls-in-an-in-app-browser\} :::important La apertura de web paywalls en un navegador in-app está disponible a partir del SDK de Adapty v. 3.15. ::: Por defecto, los web paywalls se abren en el navegador externo, lo que lleva a los usuarios fuera de tu app. Para ofrecer una experiencia de usuario fluida, puedes abrir los web paywalls en un navegador in-app. Esto muestra la página de compra web dentro de tu aplicación, permitiendo a los usuarios completar las transacciones sin cambiar de app. Para habilitarlo, pasa `AdaptyWebPresentation.InAppBrowser` al método `OpenWebPaywall`: ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, AdaptyWebPresentation.InAppBrowser, // default — ExternalBrowser (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` --- # File: unity-use-fallback-paywalls --- --- title: "Unity - Usar paywalls de respaldo" description: "Gestiona los casos en los que los usuarios están sin conexión o los servidores de Adapty no están disponibles" --- :::warning Los paywalls de respaldo son compatibles con Unity SDK v2.11 y versiones posteriores. ::: Para mantener una experiencia de usuario fluida, es importante configurar [respaldos](/fallback-paywalls) para tus [paywalls](paywalls) y [onboardings](onboardings). Esta precaución amplía las capacidades de la aplicación en caso de pérdida parcial o total de la conexión a internet. * **Si la aplicación no puede acceder a los servidores de Adapty:** Podrá mostrar un paywall de respaldo y acceder a la configuración local del onboarding. * **Si la aplicación no puede acceder a internet:** Podrá mostrar un paywall de respaldo. Los onboardings incluyen contenido remoto y requieren conexión a internet para funcionar. :::important Antes de seguir los pasos de esta guía, [descarga](/local-fallback-paywalls) los archivos de configuración de respaldo desde Adapty. ::: ## Configuración \{#configuration\} 1. Añade los archivos de configuración de respaldo al directorio común `Assets/StreamingAssets` de tu proyecto. 2. Llama al método `.setFallback` **antes** de obtener el paywall o el onboarding de destino. ```csharp using UnityEngine; using AdaptySDK; #if UNITY_IOS string fileName = "ios_fallback.json"; #elif UNITY_ANDROID string fileName = "android_fallback.json"; #else // Optional: handle Editor or other platforms string fileName = "fallback.json"; #endif Adapty.SetFallback(fileName, (error) => { if (error != null) { Debug.LogError($"Failed to set fallback: {error}"); return; } // Fallback set successfully }); ``` Parámetros: | Parámetro | Descripción | |:-------------|:-----------------------------------------------------| | **fileName** | La cadena con el nombre del archivo de configuración de respaldo. | --- # File: unity-localizations-and-locale-codes --- --- title: "Usar localizaciones y códigos de idioma en Unity SDK" description: "Aprende a localizar paywalls en tu app de Unity con el SDK de Adapty." --- ## Por qué esto es importante \{#why-this-is-important\} Hay algunos escenarios en los que los códigos de idioma entran en juego; por ejemplo, cuando intentas obtener el paywall correcto para la localización actual de tu app. Como los códigos de idioma son complejos y pueden variar de una plataforma a otra, nos apoyamos en un estándar interno para todas las plataformas que soportamos. Sin embargo, precisamente por esa complejidad, es muy importante que entiendas exactamente qué estás enviando a nuestro servidor para obtener la localización correcta y qué ocurre después, de modo que siempre recibas lo que esperas. ## Estándar de códigos de idioma en Adapty \{#locale-code-standard-at-adapty\} Para los códigos de idioma, Adapty utiliza una versión ligeramente modificada del [estándar BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag): cada código se compone de subetiquetas en minúsculas separadas por guiones. Algunos ejemplos: `en` (inglés), `pt-br` (portugués (Brasil)), `zh` (chino simplificado), `zh-hant` (chino tradicional). ## Coincidencia de códigos de configuración regional \{#locale-code-matching\} Cuando Adapty recibe una llamada desde el SDK con el código de configuración regional y comienza a buscar la localización correspondiente de un paywall, ocurre lo siguiente: 1. La cadena de configuración regional entrante se convierte a minúsculas y todos los guiones bajos (`_`) se reemplazan por guiones (`-`) 2. A continuación, se busca la localización cuyo código de configuración regional coincida exactamente 3. Si no se encuentra ninguna coincidencia, se toma la subcadena anterior al primer guion (`pt` para `pt-br`) y se busca la localización correspondiente 4. Si tampoco se encuentra ninguna coincidencia, se devuelve la localización predeterminada `en` De este modo, un dispositivo iOS que envió `'pt_BR'`, un dispositivo Android que envió `pt-BR` y otro dispositivo que envió `pt-br` obtendrán el mismo resultado. ## Implementación de localizaciones: forma recomendada \{#implementing-localizations-recommended-way\} Si te estás preguntando cómo gestionar las localizaciones, probablemente ya estés trabajando con archivos de cadenas localizadas en tu proyecto. En ese caso, te recomendamos añadir un par clave-valor con el código de idioma de Adapty correspondiente en cada uno de esos archivos. Luego, extrae el valor de esa clave al llamar a nuestro SDK, así: ```csharp showLineNumbers // 1. Modify your localization files (e.g., using Unity's Localization package) /* en.json */ { "adapty_paywalls_locale": "en" } /* es.json */ { "adapty_paywalls_locale": "es" } /* pt-BR.json */ { "adapty_paywalls_locale": "pt-br" } // 2. Extract and use the locale code using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using AdaptySDK; public class PaywallManager : MonoBehaviour { public async void FetchPaywall() { // Get the current locale from Unity's Localization system var locale = LocalizationSettings.SelectedLocale; var localeCode = GetAdaptyLocaleCode(locale); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetAdaptyLocaleCode(Locale locale) { // Convert Unity locale to Adapty format var localeIdentifier = locale.Identifier.Code; return localeIdentifier.ToLower().Replace('_', '-'); } } ``` Así te aseguras de tener control total sobre qué localización se recuperará para cada usuario de tu app. ## Implementar localizaciones: otra forma \{#implementing-localizations-the-other-way\} Puedes obtener resultados similares (aunque no idénticos) sin definir explícitamente códigos de idioma para cada localización. Esto implicaría extraer un código de idioma de otros objetos que proporciona tu plataforma, así: ```csharp showLineNumbers using UnityEngine; using System.Globalization; using AdaptySDK; public class PaywallManager : MonoBehaviour { public void FetchPaywall() { var localeCode = GetSystemLocaleCode(); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetSystemLocaleCode() { // Get the system's current culture var culture = CultureInfo.CurrentCulture; var languageCode = culture.TwoLetterISOLanguageName; var regionCode = culture.Name.Contains('-') ? culture.Name.Split('-')[1] : null; if (!string.IsNullOrEmpty(regionCode)) { return $"{languageCode}-{regionCode.ToLower()}"; } return languageCode; } } ``` Ten en cuenta que no recomendamos este enfoque por varias razones: 1. En iOS, los idiomas preferidos y la configuración regional actual no son idénticos. Si quieres que la localización se seleccione correctamente, tendrás que apoyarte en la lógica de Apple, que funciona de forma nativa si usas el enfoque recomendado con archivos de cadenas localizadas, o recrearla manualmente. 2. Es difícil predecir exactamente qué recibirá el servidor de Adapty. Por ejemplo, en iOS es posible obtener una configuración regional como `ar_OM@numbers='latn'` en un dispositivo y enviarla a nuestro servidor. En ese caso, en lugar de la localización `ar-om` que buscabas, recibirás `ar`, lo cual probablemente no es lo esperado. Aun así, si decides optar por este enfoque, asegúrate de cubrir todos los casos de uso relevantes. --- # File: unity-troubleshoot-paywall-builder --- --- title: "Solucionar problemas del Paywall Builder en el SDK de Unity" description: "Solucionar problemas del Paywall Builder en el SDK de Unity" --- Esta guía te ayuda a resolver los problemas más comunes al usar paywalls diseñados en el Adapty Paywall Builder con el SDK de Unity. ## Falla al obtener la configuración de un paywall \{#getting-a-paywall-configuration-fails\} **Problema**: El método `CreateView` no puede obtener la configuración del paywall. **Causa**: El paywall no está habilitado para mostrarse en el dispositivo desde el Paywall Builder. **Solución**: Activa el interruptor **Show on device** en el Paywall Builder. ## El número de vistas del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\} **Problema**: El contador de vistas del paywall muestra el doble del número esperado. **Causa**: Es posible que estés llamando a `LogShowPaywall` en tu código, lo que duplica el contador de vistas cuando se usa el Paywall Builder. Para los paywalls diseñados con el Paywall Builder, el seguimiento de análisis es automático, por lo que no es necesario usar este método. **Solución**: Asegúrate de no llamar a `LogShowPaywall` en tu código si estás usando el Paywall Builder. ## Otros problemas \{#other-issues\} **Problema**: Estás experimentando otros problemas relacionados con el Paywall Builder que no se han cubierto anteriormente. **Solución**: Si es necesario, migra el SDK a la versión más reciente usando las [guías de migración](unity-sdk-migration-guides). Muchos problemas se resuelven en versiones más nuevas del SDK. --- # File: unity-quickstart-manual --- --- title: "Habilitar compras en tu paywall personalizado con Unity SDK" description: "Integra el SDK de Adapty en tus paywalls personalizados de Unity para habilitar compras in-app." --- Esta guía describe cómo integrar Adapty en tus paywalls personalizados. Mantén el control total sobre la implementación del paywall, mientras el SDK de Adapty obtiene los productos, gestiona las nuevas compras y restaura las anteriores. :::important **Esta guía está dirigida a desarrolladores que implementan paywalls personalizados.** Si quieres la forma más sencilla de habilitar compras, usa el [Adapty Paywall Builder](unity-quickstart-paywalls). Con Paywall Builder, creas paywalls en un editor visual sin código, Adapty gestiona toda la lógica de compras automáticamente y puedes probar distintos diseños sin volver a publicar tu app. ::: ## Antes de empezar \{#before-you-start\} ### Configura los productos \{#set-up-products\} Para habilitar las compras in-app, necesitas entender tres conceptos clave: - [**Productos**](product) – cualquier cosa que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida) - [**Paywalls**](paywalls) – configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de obtener productos, pero este diseño te permite modificar productos, precios y ofertas sin tocar el código de tu app. - [**Placements**](placements) – dónde y cuándo muestras los paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita ejecutar pruebas A/B y mostrar distintos paywalls a diferentes usuarios. Asegúrate de entender estos conceptos incluso si trabajas con tu paywall personalizado. Básicamente, son solo tu forma de gestionar los productos que vendes en tu app. Para implementar tu paywall personalizado, necesitarás crear un **paywall** y añadirlo a un **placement**. Esta configuración te permite obtener tus productos. Para saber qué debes hacer en el dashboard, sigue la guía de inicio rápido [aquí](quickstart). ### Gestiona usuarios \{#manage-users\} Puedes trabajar con o sin autenticación de backend en tu lado. Sin embargo, el SDK de Adapty gestiona de forma diferente a los usuarios anónimos e identificados. Lee la [guía de inicio rápido de identificación](unity-quickstart-identify) para entender las particularidades y asegurarte de que trabajas correctamente con los usuarios. ## Paso 1. Obtén los productos \{#step-1-get-products\} Para obtener los productos de tu paywall personalizado, necesitas: 1. Obtener el objeto `paywall` pasando el ID del [placement](placements) al método `getPaywall`. 2. Obtener el array de productos para este paywall usando el método `getPaywallProducts`. ```csharp showLineNumbers using AdaptySDK; void LoadPaywall() { Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // Handle the error return; } Adapty.GetPaywallProducts(paywall, (products, productsError) => { if (productsError != null) { // Handle the error return; } // Use products to build your custom paywall UI }); }); } ``` ## Paso 2. Acepta compras \{#step-2-accept-purchases\} Cuando un usuario toca un producto en tu paywall personalizado, llama al método `makePurchase` con el producto seleccionado. Esto gestionará el flujo de compra y devolverá el perfil actualizado. ```csharp showLineNumbers using AdaptySDK; void PurchaseProduct(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { if (error != null) { // Handle the error return; } switch (result.Type) { case AdaptyPurchaseResultType.Success: var profile = result.Profile; // Purchase successful, profile updated break; case AdaptyPurchaseResultType.UserCancelled: // User canceled the purchase break; case AdaptyPurchaseResultType.Pending: // Purchase is pending (e.g., user will pay offline with cash) break; } }); } ``` ## Paso 3. Restaura compras \{#step-3-restore-purchases\} Los app stores requieren que todas las apps con suscripciones ofrezcan una forma de que los usuarios puedan restaurar sus compras. Llama al método `restorePurchases` cuando el usuario toque el botón de restaurar. Esto sincronizará su historial de compras con Adapty y devolverá el perfil actualizado. ```csharp showLineNumbers using AdaptySDK; void RestorePurchases() { Adapty.RestorePurchases((profile, error) => { if (error != null) { // Handle the error return; } // Restore successful, profile updated }); } ``` ## Próximos pasos \{#next-steps\} --- no_index: true --- import Callout from '../../../components/Callout.astro'; ¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte! Tu paywall está listo para mostrarse en la app. Prueba tus compras en el [sandbox de App Store](test-purchases-in-sandbox) o en [Google Play Store](testing-on-android) para asegurarte de que puedes completar una compra de prueba desde el paywall. A continuación, [comprueba si los usuarios han completado su compra](unity-check-subscription-status) para determinar si mostrar el paywall o dar acceso a las funciones de pago. --- # File: fetch-paywalls-and-products-unity --- --- title: "Obtener paywalls y productos para paywalls con Remote Config en Unity SDK" description: "Obtén paywalls y productos en el SDK de Unity de Adapty para mejorar la monetización de los usuarios." --- Antes de mostrar paywalls con Remote Config y personalizados, necesitas obtener la información sobre ellos. Ten en cuenta que este tema hace referencia a paywalls con Remote Config y personalizados. Para obtener orientación sobre cómo recuperar paywalls creados con Paywall Builder, consulta [Obtener paywalls de Paywall Builder y su configuración](unity-get-pb-paywalls). :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. :::
Antes de empezar a obtener paywalls y productos en tu app (haz clic para expandir) 1. [Crea tus productos](create-product) en el Adapty Dashboard. 2. [Crea un paywall e incorpora los productos en él](create-paywall) en el Adapty Dashboard. 3. [Crea placements e incorpora tu paywall en el placement](create-placement) en el Adapty Dashboard. 4. [Instala el SDK de Adapty](sdk-installation-unity) en tu app.
## Obtener información del paywall \{#fetch-paywall-information\} En Adapty, un [producto](product) es una combinación de productos del App Store y Google Play. Estos productos multiplataforma se integran en paywalls, lo que te permite mostrarlos en placements específicos de tu app. Para mostrar los productos, necesitas obtener un [Paywall](paywalls) de uno de tus [placements](placements) con el método `getPaywall`. :::important **No escribas los IDs de producto en el código.** El único ID que debes incluir en el código es el ID del placement. Los paywalls se configuran de forma remota, por lo que el número de productos y las ofertas disponibles pueden cambiar en cualquier momento. Tu app debe gestionar estos cambios de forma dinámica: si hoy un paywall devuelve dos productos y mañana tres, muéstralos todos sin cambiar el código. ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

Consulta [Localizaciones y códigos de idioma](unity-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los paywalls en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](unity-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.

| | **loadTimeout** | por defecto: 5 seg |

Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local.

Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede constar de diferentes solicitudes internamente.

| ¡No escribas los IDs de producto en el código! Dado que los paywalls se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin requerir cambios en el código. Lo único que tienes que incluir en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) con: una lista de IDs de producto, el identificador del paywall, el Remote Config y varias otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos correspondiente: ```csharp showLineNumbers Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { // handle the error return; } // products - the requested products array }); ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Lista de objetos [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y varias otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html). A continuación se muestran las propiedades más utilizadas, pero consulta el documento enlazado para obtener todos los detalles de las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.LocalizedTitle`. Ten en cuenta que la localización se basa en el país del store seleccionado por el usuario, no en el idioma del propio dispositivo. | | **Price** | Para mostrar una versión localizada del precio, usa `product.Price.LocalizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número usando `product.Price.Amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda asociado, usa `product.Price.CurrencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.Subscription?.LocalizedPeriod`. Esta localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción mediante programación, usa `product.Subscription?.Period`. Desde ahí puedes acceder al enum `Unit` para obtener la duración (es decir, `AdaptySubscriptionPeriodUnit.Day`, `AdaptySubscriptionPeriodUnit.Week`, `AdaptySubscriptionPeriodUnit.Month`, `AdaptySubscriptionPeriodUnit.Year` o `AdaptySubscriptionPeriodUnit.Unknown`). El valor `NumberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral, verías `AdaptySubscriptionPeriodUnit.Month` en la propiedad Unit y `3` en la propiedad NumberOfUnits. | | **Introductory Offer** | Para mostrar un distintivo u otro indicador de que una suscripción incluye una oferta introductoria, revisa la propiedad `product.Subscription?.Offer?.Phases`. Esta es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase están las siguientes propiedades útiles:
• `PaymentMode`: un enum con los valores `AdaptyPaymentMode.FreeTrial`, `AdaptyPaymentMode.PayAsYouGo`, `AdaptyPaymentMode.PayUpFront` y `AdaptyPaymentMode.Unknown`. Las pruebas gratuitas serán del tipo `AdaptyPaymentMode.FreeTrial`.
• `Price`: El precio con descuento como número. Para las pruebas gratuitas, busca `0` aquí.
• `LocalizedNumberOfPeriods`: una cadena localizada según el idioma del dispositivo que describe la duración de la oferta. Por ejemplo, una oferta de prueba de tres días muestra `"3 days"` en este campo.
• `SubscriptionPeriod`: Alternativamente, puedes obtener los detalles individuales del período de la oferta con esta propiedad. Funciona de la misma manera para las ofertas que la sección anterior describe.
• `LocalizedSubscriptionPeriod`: Un período de suscripción formateado del descuento para la configuración regional del usuario. | ## Acelerar la obtención de paywalls con el paywall de audiencia predeterminada \{#speed-up-paywall-fetching-with-default-audience-paywall\} Normalmente, los paywalls se obtienen casi al instante, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, en casos donde tienes numerosas audiencias y paywalls, y tus usuarios tienen una conexión a internet débil, obtener un paywall puede tardar más de lo deseado. En estas situaciones, puede que quieras mostrar un paywall predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún paywall. Para resolver esto, puedes usar el método `GetPaywallForDefaultAudience`, que obtiene el paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, como se detalla en la sección [Obtener información del paywall](#fetch-paywall-information) anterior. :::warning Considera usar `GetPaywall` en lugar de `GetPaywallForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede crear problemas al dar soporte a múltiples versiones de la app, requiriendo diseños retrocompatibles o aceptando que las versiones más antiguas puedan mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación basada en país, atribución o atributos personalizados. Si una obtención más rápida compensa estos inconvenientes para tu caso de uso, usa `GetPaywallForDefaultAudience` como se muestra a continuación. De lo contrario, usa `GetPaywall` como se describe [anteriormente](#fetch-paywall-information). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la localización del paywall. Se espera que este parámetro sea un código de idioma compuesto por una o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los paywalls localmente en dos capas: la caché actualizada regularmente descrita anteriormente y los paywalls de respaldo. También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.

| --- # File: present-remote-config-paywalls-unity --- --- title: "Renderizar paywall diseñado con Remote Config en Unity SDK" description: "Descubre cómo presentar paywalls con Remote Config en Adapty Unity SDK para personalizar la experiencia de usuario." --- Si has personalizado un paywall usando Remote Config, necesitarás implementar el renderizado en el código de tu app para mostrárselo a los usuarios. Como Remote Config ofrece flexibilidad adaptada a tus necesidades, tú decides qué incluir y cómo se ve tu paywall. Proporcionamos un método para obtener la configuración remota, dándote la autonomía de mostrar tu paywall personalizado configurado a través de Remote Config. ## Obtener el Remote Config del paywall y presentarlo \{#get-paywall-remote-config-and-present-it\} Para obtener el Remote Config de un paywall, accede a la propiedad `remoteConfig` y extrae los valores que necesites. ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } // Access remote config dictionary var dictionary = paywall.RemoteConfig?.Dictionary; var headerText = dictionary?["header_text"] as string; // Or access raw JSON data var jsonData = paywall.RemoteConfig?.Data; }); ``` En este punto, una vez que hayas recibido todos los valores necesarios, es momento de renderizarlos y ensamblarlos en una página visualmente atractiva. Asegúrate de que el diseño se adapte a distintos tamaños de pantalla y orientaciones de dispositivos móviles, garantizando una experiencia fluida y amigable en todos los dispositivos. :::warning Asegúrate de [registrar el evento de visualización del paywall](present-remote-config-paywalls-unity#track-paywall-view-events) tal como se describe a continuación, para que los análisis de Adapty puedan recopilar información para los embudos y las pruebas A/B. ::: Una vez que hayas terminado de mostrar el paywall, continúa configurando el flujo de compra. Cuando el usuario realice una compra, simplemente llama a `.MakePurchase()` con el producto de tu paywall. Para más detalles sobre el método `.MakePurchase()`, consulta [Realizar compras](unity-making-purchases). Te recomendamos [crear un paywall de respaldo denominado paywall de respaldo](unity-use-fallback-paywalls). Este respaldo se mostrará al usuario cuando no haya conexión a internet ni caché disponible, garantizando una experiencia fluida incluso en esas situaciones. ## Registrar eventos de visualización del paywall \{#track-paywall-view-events\} Adapty te ayuda a medir el rendimiento de tus paywalls. Aunque recopilamos datos de compras automáticamente, registrar las visualizaciones del paywall requiere tu intervención, ya que solo tú sabes cuándo un usuario ve un paywall. Para registrar un evento de visualización del paywall, simplemente llama a `.LogShowPaywall(paywall)` y se reflejará en las métricas de tu paywall en los embudos y las pruebas A/B. :::important No es necesario llamar a `.LogShowPaywall(paywall)` si estás mostrando paywalls creados en el [Paywall Builder](adapty-paywall-builder). ::: ```csharp showLineNumbers Adapty.LogShowPaywall(paywall, (error) => { // handle the error }); ``` Parámetros de la solicitud: | Parámetro | Presencia | Descripción | | :---------- | :-------- |:------------------------------------------------------------------| | **paywall** | obligatorio | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | --- # File: unity-making-purchases --- --- title: "Realizar compras in-app en Unity SDK" description: "Guía sobre cómo gestionar compras in-app y suscripciones usando Adapty." --- Mostrar paywalls en tu app es un paso fundamental para ofrecer a los usuarios acceso a contenido o servicios premium. Sin embargo, mostrarlos es suficiente para gestionar las compras solo si usas el [Paywall Builder](adapty-paywall-builder) para personalizar tus paywalls. Si no usas el Paywall Builder, debes usar un método independiente llamado `.makePurchase()` para completar una compra y desbloquear el contenido deseado. Este método es la puerta de entrada para que los usuarios interactúen con los paywalls y completen sus transacciones. Si tu paywall tiene una oferta promocional activa para el producto que el usuario intenta comprar, Adapty la aplicará automáticamente en el momento de la compra. :::warning Ten en cuenta que la oferta introductoria se aplicará automáticamente solo si usas paywalls configurados con el Paywall Builder. En otros casos, deberás [verificar la elegibilidad del usuario para una oferta introductoria en iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Omitir este paso puede provocar que tu app sea rechazada durante la revisión. Además, podría suponer cobrar el precio completo a usuarios que tienen derecho a una oferta introductoria. ::: Asegúrate de haber completado la [configuración inicial](quickstart) sin saltarte ningún paso. Sin ella, no podemos validar las compras. ## Realizar una compra \{#make-purchase\} :::note **¿Usas el [Paywall Builder](adapty-paywall-builder)?** Las compras se procesan automáticamente; puedes saltarte este paso. **¿Buscas una guía paso a paso?** Consulta la [guía de inicio rápido](unity-implement-paywalls-manually) para instrucciones de implementación completas con todo el contexto. ::: ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successfull purchase break; default: break; } }); } ``` Parámetros de la solicitud: | Parámetro | Presencia | Descripción | | :---------- | :------- |:------------------------------------------------------------------------------------------------------| | **Product** | obligatorio | Un objeto [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) obtenido del paywall. | Parámetros de la respuesta: | Parámetro | Descripción | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

Si la solicitud fue exitosa, la respuesta incluye este objeto. Un objeto [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas del usuario dentro de la app.

Verifica el estado del nivel de acceso para confirmar si el usuario tiene el acceso requerido a la app.

| :::warning **Nota:** si todavía usas la versión de StoreKit de Apple inferior a v2.0 y la versión del SDK de Adapty inferior a v.2.9.0, debes proporcionar el [secreto compartido de App Store de Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Este método está actualmente deprecado por Apple. ::: ## Cambiar la suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario elige una nueva suscripción en lugar de renovar la actual, el funcionamiento depende del store: - En el App Store, la suscripción se actualiza automáticamente dentro del grupo de suscripciones. Si un usuario compra una suscripción de un grupo mientras ya tiene una suscripción de otro, ambas suscripciones estarán activas al mismo tiempo. - En Google Play, la suscripción no se actualiza automáticamente. Deberás gestionar el cambio en el código de tu app como se describe a continuación. Para reemplazar la suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional: ```csharp showLineNumbers // Create subscription update parameters var subscriptionUpdateParams = new AdaptySubscriptionUpdateParameters( "old_product_id", // Product ID of the current subscription AdaptySubscriptionUpdateReplacementMode.WithTimeProration ); Adapty.MakePurchase(product, subscriptionUpdateParams, (profile, error) => { if(error != null) { // Handle the error return; } // successful cross-grade }); ``` Parámetro adicional de la solicitud: | Parámetro | Presencia | Descripción | | :--------------------------- | :------- |:-------------------------------------------------------------------------------------------------------| | **subscriptionUpdateParams** | obligatorio | Un objeto [`AdaptySubscriptionUpdateParameters`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_subscription_update_parameters.html). | Puedes leer más sobre suscripciones y modos de reemplazo en la documentación para desarrolladores de Google: - [Acerca de los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recomendaciones de Google para los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Modo de reemplazo [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Nota: este método solo está disponible para actualizaciones de suscripción. No se admiten degradaciones. - Modo de reemplazo [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Nota: el cambio real de suscripción solo ocurrirá cuando finalice el período de facturación de la suscripción actual. ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\} --- no_index: true --- import Callout from '../../../components/Callout.astro';
Sobre los códigos de oferta Los códigos de oferta te permiten dar descuentos o períodos de prueba gratuitos a usuarios concretos. A diferencia de las ofertas habituales, que se aplican de forma automática, los códigos de oferta se distribuyen fuera de la app — por email, redes sociales o materiales impresos. Los usuarios los canjean introduciendo el código en el App Store, accediendo a una URL de canje o a través de un diálogo dentro de la app. Para configurar códigos de oferta, abre una suscripción en App Store Connect y ve a su sección **Offer Codes**. Puedes crear [tres tipos](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de códigos de oferta: - **Free** — la suscripción es gratuita durante un período determinado y la siguiente renovación se cobra al precio completo. - **Pay as you go** — el usuario paga un precio reducido en cada ciclo de facturación durante un período determinado y, después, la suscripción se renueva al precio completo. - **Pay up front** — el usuario paga un precio único reducido por toda la duración de la oferta y, después, la suscripción se renueva al precio completo. No es necesario añadir los códigos de oferta a Adapty. Apple etiqueta cada transacción durante el período de la oferta con la categoría del código de oferta. Esto incluye el canje inicial y todas las renovaciones con descuento posteriores. Adapty detecta la etiqueta y registra cada transacción con la categoría de oferta `offer_code`. Cuando termina el período de oferta y la suscripción se renueva al precio completo, la etiqueta deja de estar presente. Puedes filtrar los análisis por el tipo de oferta **Offer Code** en el [Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Resolución de discrepancias en los ingresos \{#revenue-discrepancy-troubleshooting\} Si observas que una transacción con código de oferta aparece en Adapty al precio completo del producto en lugar del precio reducido, verifica lo siguiente en App Store Connect: - El código de oferta tiene los precios correctos configurados para todas las regiones donde los usuarios pueden canjearlo. - El precio de la oferta está configurado para el país o región específica del usuario. Apple envía el precio regional en la transacción. Si no hay ningún precio regional configurado para la oferta, Apple puede enviar el precio completo del producto. Puedes filtrar y verificar las transacciones con código de oferta en el [Adapty Dashboard](controls-filters-grouping-compare-proceeds) mediante los filtros de tipo de oferta **Offer Code** y **Offer Discount Type**. #### Códigos promocionales heredados (obsoletos) \{#legacy-promo-codes-deprecated\} Apple dejó obsoletos los códigos promocionales para compras in-app en marzo de 2026. Los códigos de oferta los sustituyen con más funcionalidades: elegibilidad configurable, fechas de expiración y hasta 1 millón de códigos por trimestre. Si antes usabas códigos promocionales para compras in-app, migra a los códigos de oferta en App Store Connect. Los códigos promocionales heredados (limitados a 100 por app y versión) daban acceso gratuito a una suscripción. A diferencia de los códigos de oferta, Apple no incluía información de descuento en las transacciones con código promocional — enviaba el precio completo del producto en el recibo. Por ello, Adapty registraba estas transacciones al precio completo, lo que generaba discrepancias entre los análisis de Adapty y App Store Connect. Si ves transacciones históricas al precio completo que deberían haber sido gratuitas, es probable que provengan de códigos promocionales heredados. Como estos códigos ya están obsoletos, migra a los códigos de oferta para un seguimiento preciso de los ingresos.
Para mostrar la hoja de canje de códigos en tu app: ```csharp showLineNumbers Adapty.PresentCodeRedemptionSheet((error) => { // handle the error }); ``` :::danger Según nuestras observaciones, la hoja de canje de códigos de oferta puede no funcionar de forma fiable en algunas apps. Recomendamos redirigir al usuario directamente al App Store. Para ello, debes abrir la URL con el siguiente formato: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ## Gestionar planes prepago (Android) \{#manage-prepaid-plans-android\} Si los usuarios de tu app pueden comprar [planes prepago](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (por ejemplo, comprar una suscripción no renovable por varios meses), puedes habilitar las [transacciones pendientes](https://developer.android.com/google/play/billing/subscriptions#pending) para planes prepago. ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetGoogleEnablePendingPrepaidPlans(true); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: unity-restore-purchase --- --- title: "Restaurar compras en la app móvil con Unity SDK" description: "Aprende cómo restaurar compras en Adapty para garantizar una experiencia de usuario sin interrupciones." --- Restaurar compras tanto en iOS como en Android es una funcionalidad que permite a los usuarios recuperar el acceso a contenido comprado previamente, como suscripciones o compras in-app, sin que se les vuelva a cobrar. Esta funcionalidad es especialmente útil para usuarios que hayan desinstalado y reinstalado la app, o que hayan cambiado de dispositivo y quieran acceder a su contenido ya adquirido sin pagar de nuevo. :::note En los paywalls creados con [Paywall Builder](adapty-paywall-builder), las compras se restauran automáticamente sin que tengas que añadir código adicional. Si ese es tu caso, puedes saltarte este paso. ::: Para restaurar una compra cuando no usas [Paywall Builder](adapty-paywall-builder) para personalizar el paywall, llama al método `.restorePurchases()`: ```csharp showLineNumbers Adapty.RestorePurchases((profile, error) => { if (error != null) { // handle the error return; } var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; if (accessLevel != null && accessLevel.IsActive) { // restore access } }); ``` Parámetros de respuesta: | Parámetro | Descripción | |---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

Un objeto [`AdaptyProfile`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Este modelo contiene información sobre los niveles de acceso, suscripciones y compras únicas.

Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.

| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-unity --- --- title: "Implementar el modo Observer en el SDK de Unity" description: "Implementa el modo observer en Adapty para registrar eventos de suscripción de usuarios en el SDK de Unity." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [modo Observer](observer-vs-full-mode). En su forma básica, el modo Observer ofrece analíticas avanzadas e integración fluida con sistemas de atribución y analíticas. Si esto cubre tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK de Adapty estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 2. [Reportar transacciones](report-transactions-observer-mode-unity) desde tu infraestructura de compras existente a Adapty. ### Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de suscripción por tu cuenta y utilizas Adapty para enviar eventos de suscripción y analíticas. :::important Cuando se ejecuta en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlo tú mismo. ::: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetObserverMode(true); // Enable observer mode Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` Parámetros: | Parámetro | Descripción | |--------------|----------------------------------------------------------------------------------------------------------------| | observerMode | Un valor booleano que controla el [modo Observer](observer-vs-full-mode). El valor por defecto es `false`. | ## Usar los paywalls de Adapty en el modo Observer \{#using-adapty-paywalls-in-observer-mode\} Si también quieres usar los paywalls y las funciones de pruebas A/B de Adapty, puedes hacerlo, pero requiere algo de configuración adicional en el modo Observer. Esto es lo que necesitarás hacer además de los pasos anteriores: 1. Muestra los paywalls de la forma habitual para [paywalls con Remote Config](present-remote-config-paywalls-unity). 3. [Asocia los paywalls](report-transactions-observer-mode-unity) con las transacciones de compra. --- # File: report-transactions-observer-mode-unity --- --- title: "Reportar transacciones en Observer Mode en el SDK de Unity" description: "Reporta transacciones de compras en el Observer Mode de Adapty para obtener información sobre usuarios y seguimiento de ingresos en el SDK de Unity." --- En Observer Mode, el SDK de Adapty no puede rastrear por sí solo las compras realizadas a través de tu sistema de compras existente. Necesitas reportar las transacciones desde tu app store. Es fundamental configurar esto **antes** de publicar tu app para evitar errores en los análisis. Usa `reportTransaction` para reportar explícitamente cada transacción y que Adapty la reconozca. :::warning **¡No omitas el reporte de transacciones!** Si no llamas a `ReportTransaction`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones. ::: Si usas paywalls de Adapty, incluye el `variationId` al reportar una transacción. Esto vincula la compra con el paywall que la originó, garantizando análisis precisos del paywall. ```csharp showLineNumbers Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` Parámetros: | Parámetro | Presencia | Descripción | | ------------- | --------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requerido |
  • Para iOS: Identificador de la transacción.
  • Para Android: Identificador de cadena `purchase.getOrderId` de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación.
| | variationId | opcional | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). |
En Observer Mode, el SDK de Adapty no puede rastrear por sí solo las compras realizadas a través de tu sistema de compras existente. Necesitas reportar las transacciones desde tu app store o restaurarlas. Es fundamental configurar esto **antes** de publicar tu app para evitar errores en los análisis. Usa `reportTransaction` en ambas plataformas para reportar explícitamente cada transacción, y usa `restorePurchases` en Android como paso adicional para asegurarte de que Adapty la reconozca. :::warning **¡No omitas el reporte de transacciones ni la restauración de compras!** Si no llamas a estos métodos, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones. ::: Si usas paywalls de Adapty, incluye el `PAYWALL_VARIATION_ID` al reportar una transacción. Esto vincula la compra con el paywall que la originó, garantizando análisis precisos del paywall. ```csharp showLineNumbers // every time when calling transasction.finish() #if UNITY_ANDROID && !UNITY_EDITOR Adapty.RestorePurchases((profile, error) => { // handle the error }); #endif Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` Parámetros: | Parámetro | Presencia | Descripción | | ------------- | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requerido |
  • Para iOS, StoreKit 1: un objeto [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
  • Para iOS, StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
  • Para Android: Identificador de cadena (`purchase.getOrderId`) de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación.
| | variationId | opcional | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). |
**Reporte de transacciones** - Las versiones hasta la 3.1.x escuchan automáticamente las transacciones en la App Store, por lo que no es necesario reportarlas manualmente. - La versión 3.2 no admite Observer Mode. **Reporte de transacciones** Usa `restorePurchases` para reportar una transacción a Adapty en Observer Mode, tal como se explica en la página [Restaurar compras en código móvil](unity-restore-purchase). :::warning **¡No omitas el reporte de transacciones!** Si no llamas a `restorePurchases`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones. ::: **Asociar paywalls a transacciones** El SDK de Adapty no puede determinar el origen de las compras, ya que eres tú quien las procesa. Por lo tanto, si tienes pensado usar paywalls y/o pruebas A/B en Observer Mode, necesitas asociar la transacción proveniente de tu app store con el paywall correspondiente en el código de tu app. Es importante hacerlo correctamente antes de publicar tu app; de lo contrario, generará errores en los análisis. ```csharp Adapty.SetVariationForTransaction("", "", (error) => { if(error != null) { // handle the error return; } // successful binding }); ``` | Parámetro | Presencia | Descripción | | ------------------------------------------------------ | --------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requerido |

Para iOS, StoreKit 1: un objeto [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).

Para iOS, StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).

Para Android: Identificador de cadena (purchase.getOrderId de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación).

| | variationId | requerido | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). |
--- # File: unity-troubleshoot-purchases --- --- title: "Solucionar problemas de compras en Unity SDK" description: "Solucionar problemas de compras en Unity SDK" --- Esta guía te ayuda a resolver problemas comunes al implementar compras manualmente en el SDK de Unity. ## makePurchase se llama correctamente, pero el perfil no se actualiza \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problema**: El método `makePurchase` se completa correctamente, pero el perfil del usuario y el estado de la suscripción no se actualizan en Adapty. **Causa**: Esto suele indicar una configuración incompleta de Google Play Store o problemas de configuración. **Solución**: Asegúrate de haber completado todos los [pasos de configuración de Google Play](initial-android). ## makePurchase se invoca dos veces \{#makepurchase-is-invoked-twice\} **Problema**: El método `makePurchase` se está llamando varias veces para la misma compra. **Causa**: Esto ocurre normalmente cuando el flujo de compra se activa varias veces debido a problemas de gestión del estado de la interfaz o a interacciones rápidas del usuario. **Solución**: Asegúrate de haber completado todos los [pasos de configuración de Google Play](initial-android). ## AdaptyError.cantMakePayments en modo observador \{#adaptyerror-cantmakepayments-in-observer-mode\} **Problema**: Estás obteniendo `AdaptyError.cantMakePayments` al usar `makePurchase` en modo observador. **Causa**: En el modo observador, debes gestionar las compras por tu cuenta, no usar el método `makePurchase` de Adapty. **Solución**: Si usas `makePurchase` para las compras, desactiva el modo observador. Debes elegir entre usar `makePurchase` o gestionar las compras por tu cuenta en el modo observador. Consulta [Implementar el modo observador](implement-observer-mode-unity) para más detalles. ## Error de Adapty: (code: 103, message: Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\} **Problema**: Estás recibiendo un error de facturación no disponible de Google Play Store. **Causa**: Este error no está relacionado con Adapty. Es un error de la biblioteca de facturación de Google Play que indica que la facturación no está disponible en el dispositivo. **Solución**: Este error no está relacionado con Adapty. Puedes consultar más información en la documentación de Play Store: [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## No se encuentran makePurchasesCompletionHandlers \{#not-found-makepurchasescompletionhandlers\} **Problema**: Estás encontrando problemas porque no se encuentran los `makePurchasesCompletionHandlers`. **Causa**: Esto suele estar relacionado con problemas en las pruebas de sandbox. **Solución**: Crea un nuevo usuario de sandbox e inténtalo de nuevo. Esto generalmente resuelve los problemas con los manejadores de finalización de compra en sandbox. ## Otros problemas \{#other-issues\} **Problema**: Estás experimentando otros problemas relacionados con las compras que no se tratan más arriba. **Solución**: Migra el SDK a la última versión siguiendo las [guías de migración](unity-sdk-migration-guides) si es necesario. Muchos problemas se resuelven en versiones más recientes del SDK. --- # File: unity-identifying-users --- --- title: "Identificar usuarios en Unity SDK" description: "Aprende cómo identificar usuarios en tu app de Unity con el SDK de Adapty." --- Adapty crea un ID de perfil interno para cada usuario. Sin embargo, si tienes tu propio sistema de autenticación, deberías establecer tu propio Customer User ID. Puedes encontrar usuarios por su Customer User ID en la sección [Perfiles](profiles-crm) y utilizarlo en la [API del lado del servidor](getting-started-with-server-side-api), que se enviará a todas las integraciones. ### Configurar el ID de usuario en la inicialización \{#setting-customer-user-id-on-configuration\} Si ya tienes un ID de usuario durante la configuración, pásalo como parámetro `customerUserId` al método `.activate()`: ```csharp showLineNumbers using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ### Establecer el ID de usuario después de la configuración \{#setting-customer-user-id-after-configuration\} Si no tienes un ID de usuario en la configuración del SDK, puedes establecerlo en cualquier momento con el método `.identify()`. Los casos más comunes para usar este método son tras el registro o la autenticación, cuando el usuario pasa de ser anónimo a estar autenticado. ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { if(error == null) { // successful identify } }); ``` Parámetros de la solicitud: - **Customer User ID** (obligatorio): un identificador de usuario de tipo string. :::warning Reenvío de datos significativos del usuario En algunos casos, como cuando un usuario inicia sesión de nuevo en su cuenta, los servidores de Adapty ya tienen información sobre ese usuario. En estos escenarios, el SDK de Adapty cambiará automáticamente para trabajar con el nuevo usuario. Si enviaste algún dato al usuario anónimo, como atributos personalizados o atribuciones de redes de terceros, deberás reenviar esos datos para el usuario identificado. También es importante tener en cuenta que debes volver a solicitar todos los paywalls y productos después de identificar al usuario, ya que los datos del nuevo usuario pueden ser diferentes. ::: ### Cerrar sesión e iniciar sesión \{#logging-out-and-logging-in\} Puedes cerrar la sesión del usuario en cualquier momento llamando al método `.logout()`: ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` Luego puedes iniciar sesión con el usuario usando el método `.identify()`. ## Asignar `appAccountToken` (iOS) [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) es un **UUID** que te permite vincular las transacciones del App Store con la identidad interna de tu usuario. StoreKit asocia este token con cada transacción, de modo que tu backend puede relacionar los datos del App Store con tus usuarios. Usa un UUID estable generado por usuario y reutilízalo para la misma cuenta en todos los dispositivos. Así te aseguras de que las compras y las notificaciones del App Store permanezcan correctamente vinculadas. Puedes configurar el token de dos formas: durante la activación del SDK o al identificar al usuario. :::important Siempre debes pasar `appAccountToken` junto con `customerUserId`. Si solo pasas el token, no se incluirá en la transacción. ::: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; using System; // During configuration: var appAccountToken = new Guid("YOUR_APP_ACCOUNT_TOKEN"); var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", appAccountToken); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", appAccountToken, (error) => { if (error == null) { // successful identify } }); ``` ## Establecer IDs de cuenta ofuscados (Android) \{#set-obfuscated-account-ids-android\} Google Play requiere IDs de cuenta ofuscados en ciertos casos de uso para mejorar la privacidad y seguridad de los usuarios. Estos IDs ayudan a Google Play a identificar compras sin exponer información del usuario, lo que es especialmente importante para la prevención de fraude y los análisis. Es posible que necesites establecer estos IDs si tu app maneja datos sensibles de usuarios o si debes cumplir con normativas de privacidad específicas. Los IDs ofuscados permiten a Google Play rastrear compras sin revelar los identificadores reales de los usuarios. ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; // Durante la configuración: var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // manejar el error return; } }); // O al identificar usuarios Adapty.Identify("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID", (error) => { if (error == null) { // identificación exitosa } }); ``` ## Detectar usuarios en múltiples dispositivos \{#detect-users-across-devices\} --- no_index: true --- Cuando el SDK se activa, lee automáticamente los derechos existentes del usuario desde StoreKit (iOS) o Google Play Billing (Android) y los sincroniza con el backend de Adapty. Una suscripción activa aparece en el perfil de Adapty sin que la app llame a `restorePurchases`. Lo que **no** ocurre automáticamente es reconocer que un perfil en un dispositivo nuevo pertenece al mismo usuario que el perfil en el dispositivo original. Adapty relaciona perfiles por Customer User ID, así que la continuidad de identidad depende de lo que uses como CUID. **Lo que Adapty puede detectar entre dispositivos** | Tu configuración | Lo que Adapty detecta | Lo que debes hacer | | --- | --- | --- | | Customer User ID = `device_id` (sin login en la app) | El nuevo dispositivo obtiene un CUID diferente y, por tanto, un perfil diferente. La suscripción se sincroniza con el nuevo perfil mediante un evento **Access level updated**, pero `subscription_started` no se dispara — el nuevo perfil se trata como heredero de la compra original. Los análisis basados en `subscription_started` contarán de menos a los usuarios que vuelven. | Usa un ID de cuenta estable como Customer User ID para que un usuario que regresa coincida con el perfil existente en todos los dispositivos. | | Customer User ID = ID de cuenta estable (login en cada dispositivo) | El SDK sincroniza automáticamente la suscripción en `activate()`, e `identify()` relaciona el perfil existente por CUID. | No se necesita configuración adicional — tanto la identidad como la suscripción se resuelven automáticamente. | | Heredero de Apple Family Sharing | El miembro de la familia recibe la suscripción solo a través de un evento **Access level updated** — `subscription_started` no se dispara. | Escucha el evento **Access level updated**. Consulta [Apple Family Sharing](apple-family-sharing) para ver la matriz de eventos completa. | | Misma cuenta de Apple/Google, distintos usuarios dentro de la app | El primer perfil que registra la compra se convierte en el principal. Los perfiles posteriores ven la suscripción a través de una cadena de herederos, con un evento **Access level updated**. | Exige login y elige un [modo de compartición](sharing-paid-access-between-user-accounts) que se adapte a tu modelo. | **Restaurar compras en un dispositivo nuevo** Muestra un botón "Restaurar compras" iniciado por el usuario en tu paywall. Apple App Review (directriz 3.1.1) lo exige, y actúa como alternativa cuando la sincronización automática no cubre algún caso límite. El botón debe llamar a `restorePurchases` en tu SDK. No es necesario llamar a `restorePurchases` de forma programática al primer inicio para el uso normal — el SDK ya ejecuta el equivalente en `activate()`. Reserva las llamadas programáticas para forzar una verificación de recibo actualizada, por ejemplo al depurar un acceso que falta después de que `activate()` haya completado. --- # File: unity-setting-user-attributes --- --- title: "Establecer atributos de usuario en el SDK de Unity" description: "Aprende a actualizar atributos de usuario y datos de perfil en tu app de Unity con el SDK de Adapty." --- Puedes añadir atributos opcionales como email, número de teléfono, etc., al usuario de tu app. Luego puedes usarlos para crear [segmentos](segments) de usuarios o simplemente consultarlos en el CRM. ### Establecer atributos de usuario \{#setting-user-attributes\} Para establecer atributos de usuario, llama al método `.updateProfile()`: ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetFirstName("John") .SetLastName("Appleseed") .SetBirthday(new DateTime(1970, 1, 3)) .SetGender(ProfileGender.Female) .SetEmail("example@adapty.io"); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != nil) { // handle the error } }); ``` Ten en cuenta que los atributos que hayas establecido previamente con el método `updateProfile` no se restablecerán. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ### Lista de claves permitidas \{#the-allowed-keys-list\} Las claves permitidas `` de `AdaptyProfileParameters.Builder` y sus valores `` se listan a continuación: | Key | Value | |---|-----| |

email

phoneNumber

firstName

lastName

| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos de usuario personalizados \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados. Normalmente están relacionados con el uso de tu app. Por ejemplo, en apps de fitness podrían ser el número de ejercicios por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes utilizarlos en segmentos para crear paywalls y ofertas segmentadas, y también en análisis para identificar qué métricas de producto influyen más en los ingresos. ```csharp showLineNumbers try { builder = builder.SetCustomStringAttribute("string_key", "string_value"); builder = builder.SetCustomDoubleAttribute("double_key", 123.0f); } catch (Exception e) { // handle the exception } ``` Para eliminar una clave existente, usa el método `.withRemoved(customAttributeForKey:)`: ```csharp showLineNumbers try { builder = builder.RemoveCustomAttribute("key_to_remove"); } catch (Exception e) { // handle the exception } ``` A veces necesitas saber qué atributos personalizados ya se han establecido. Para ello, usa el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos de usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor pueden haber cambiado desde la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario - Los nombres de clave pueden tener hasta 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número flotante con un máximo de 50 caracteres. --- # File: unity-listen-subscription-changes --- --- title: "Comprobar el estado de la suscripción en Unity SDK" description: "Rastrea y gestiona el estado de la suscripción del usuario en Adapty para mejorar la retención de clientes en tu aplicación Unity." --- Con Adapty, hacer seguimiento del estado de la suscripción es muy sencillo. No tienes que insertar manualmente los IDs de producto en tu código. En cambio, puedes confirmar fácilmente el estado de suscripción de un usuario comprobando si tiene un [nivel de acceso](access-level) activo.
Antes de empezar a comprobar el estado de la suscripción (haz clic para ampliar) - Para iOS, configura las [Notificaciones del servidor de App Store](enable-app-store-server-notifications) - Para Android, configura las [Notificaciones en tiempo real para desarrolladores (RTDN)](enable-real-time-developer-notifications-rtdn)
## El nivel de acceso y el objeto AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Los niveles de acceso son propiedades del objeto [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Te recomendamos obtener el perfil cuando tu app arranca, por ejemplo al [identificar a un usuario](unity-identifying-users#setting-customer-user-id-on-configuration), y actualizarlo cada vez que se produzcan cambios. Así podrás usar el objeto de perfil sin necesidad de solicitarlo repetidamente. Para recibir notificaciones sobre actualizaciones del perfil, suscríbete a los cambios de perfil como se describe en la sección [Escuchar actualizaciones del estado de la suscripción](#listening-for-subscription-status-updates) más abajo. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Obtener el nivel de acceso desde el servidor \{#retrieving-the-access-level-from-the-server\} Para obtener el nivel de acceso desde el servidor, usa el método `.GetProfile()`: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` Parámetros de respuesta: | Parámetro | Descripción | | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile |

Un objeto [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). En general, solo tienes que comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.

El método `.getProfile` proporciona el resultado más actualizado, ya que siempre intenta consultar la API. Si por algún motivo (por ejemplo, sin conexión a internet) el SDK de Adapty no puede obtener información del servidor, se devuelven los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` de forma periódica para mantener esta información lo más actualizada posible.

| El método `.getProfile()` te proporciona el perfil del usuario a partir del cual puedes obtener el estado del nivel de acceso. Puedes tener múltiples niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a diferentes temáticas de forma independiente, puedes crear los niveles de acceso "sports" y "science". Sin embargo, la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso "premium" predeterminado. Aquí tienes un ejemplo para comprobar el nivel de acceso "premium" predeterminado: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // "premium" is an identifier of default access level var accessLevel = profile.AccessLevels["premium"]; if (accessLevel != null && accessLevel.IsActive) { // grant access to premium features } }); ``` ### Escuchar actualizaciones del estado de la suscripción \{#listening-for-subscription-status-updates\} Cada vez que la suscripción del usuario cambia, Adapty lanza un evento. Para recibir mensajes de Adapty, necesitas hacer una configuración adicional: ```csharp showLineNumbers // Extend `AdaptyEventListener ` with `OnLoadLatestProfile ` method: public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle any changes to subscription state } } ``` Adapty también lanza un evento al inicio de la aplicación. En ese caso, se pasará el estado de suscripción almacenado en caché. ### Caché del estado de la suscripción \{#subscription-status-cache\} La caché implementada en el SDK de Adapty almacena el estado de suscripción del perfil. Esto significa que, incluso si el servidor no está disponible, se puede acceder a los datos en caché para obtener información sobre el estado de suscripción del perfil. No obstante, hay que tener en cuenta que no es posible solicitar datos directamente desde la caché. El SDK consulta periódicamente el servidor cada minuto para comprobar si hay actualizaciones o cambios relacionados con el perfil. Si hay modificaciones, como nuevas transacciones u otras actualizaciones, se enviarán a los datos en caché para mantenerlos sincronizados con el servidor. --- # File: unity-deal-with-att --- --- title: "Gestionar ATT en el SDK de Unity" description: "Comienza con Adapty en Unity para simplificar la configuración y gestión de suscripciones." --- Si tu aplicación utiliza el framework AppTrackingTransparency y presenta al usuario una solicitud de autorización de seguimiento de la app, debes enviar el [estado de autorización](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) a Adapty. ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` :::warning Te recomendamos encarecidamente que envíes este valor lo antes posible cuando cambie; solo así los datos se enviarán a tiempo a las integraciones que hayas configurado. ::: --- # File: kids-mode-unity --- --- title: "Kids Mode en Unity SDK" description: "Activa fácilmente el Modo Niños para cumplir con las políticas de Apple y Google. No se recopilan IDFA, GAID ni datos publicitarios en Unity SDK." --- Si tu aplicación Unity está destinada a niños, debes seguir las políticas de [Apple](https://developer.apple.com/kids/) y [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si usas el SDK de Adapty, unos pocos pasos sencillos te ayudarán a configurarlo para cumplir con estas políticas y superar las revisiones de las tiendas. ## ¿Qué se necesita? \{#whats-required\} Debes configurar el SDK de Adapty para desactivar la recopilación de: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [Dirección IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Además, te recomendamos usar el ID de usuario del cliente con cuidado. Un ID en formato `` se considerará claramente como recopilación de datos personales, al igual que usar un correo electrónico. En el Modo Niños, la mejor práctica es usar identificadores aleatorios o anonimizados (por ejemplo, IDs hasheados o UUIDs generados por el dispositivo) para garantizar el cumplimiento normativo. ## Activar el Modo Niños \{#enabling-kids-mode\} ### Cambios en el Adapty Dashboard \{#updates-in-the-adapty-dashboard\} En el Adapty Dashboard, debes desactivar la recopilación de direcciones IP. Para ello, ve a [App settings](https://app.adapty.io/settings/general) y haz clic en **Disable IP address collection** en **Collect users' IP address**. ### Cambios en el código de tu app \{#updates-in-your-mobile-app-code\} ¡La compatibilidad con el Modo Niños en Unity estará disponible próximamente! Por ahora, puedes seguir las guías de plataformas nativas: - [Kids Mode en iOS SDK](kids-mode) para la configuración en iOS - [Kids Mode en Android SDK](kids-mode-android) para la configuración en Android --- # File: unity-get-onboardings --- --- title: "Obtener onboardings en el SDK de Unity" description: "Aprende cómo recuperar onboardings en Adapty para Unity." --- Después de [diseñar la parte visual de tu onboarding](design-onboarding) con el editor en el Adapty Dashboard, puedes mostrarlo en tu app de Unity. El primer paso es obtener el onboarding asociado al placement y su configuración de vista, tal como se describe a continuación. Antes de empezar, asegúrate de que: 1. Has instalado el [SDK de Unity de Adapty](sdk-installation-unity) en su versión 3.14.0 o superior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). ## Obtener el onboarding y crear la vista \{#fetch-onboarding-and-create-view\} Cuando creas un [onboarding](onboardings) con nuestro editor sin código, se almacena como un contenedor con una configuración que tu app necesita obtener y mostrar. Este contenedor gestiona toda la experiencia: qué contenido aparece, cómo se presenta y cómo se procesan las interacciones del usuario (como respuestas a cuestionarios o entradas de formularios). El contenedor también registra automáticamente los eventos de analíticas, por lo que no necesitas implementar un seguimiento de vistas por separado. Para obtener el mejor rendimiento, obtén la configuración del onboarding con antelación para dar tiempo suficiente a que las imágenes se descarguen antes de mostrárselas a los usuarios. Para obtener un onboarding, usa el método `GetOnboarding`: ```csharp showLineNumbers Adapty.GetOnboarding("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

Consulta [Localizaciones y códigos de localización](flutter-localizations-and-locale-codes) para más información sobre los códigos de localización y cómo recomendamos usarlos.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los onboardings localmente en dos capas: la caché actualizada periódicamente descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.

| | **loadTimeout** | por defecto: 5 seg |

Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el respaldo local.

Ten en cuenta que, en casos excepcionales, este método puede agotar el tiempo de espera un poco más tarde de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internas.

| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_onboarding.html) con: el identificador y la configuración del onboarding, Remote Config y otras propiedades. | Tras obtener el onboarding, llama al método `CreateOnboardingView`. :::warning El resultado del método `CreateOnboardingView` solo puede usarse una vez. Si necesitas usarlo de nuevo, llama al método `CreateOnboardingView` otra vez. Llamarlo dos veces sin volver a crearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers AdaptyUI.CreateOnboardingView(onboarding, (view, error) => { // handle the result }); ``` Parámetros: | Parámetro | Presencia | Descripción | |:---------------| :------------- |:-----------------------------------------------------------------------------| | **onboarding** | obligatorio | Un objeto `AdaptyOnboarding` para obtener una vista del onboarding deseado. | | **externalUrlsPresentation** |

opcional

por defecto: `InAppBrowser`

|

Controla cómo se abren los enlaces en el onboarding. Opciones disponibles:

- `AdaptyWebPresentation.InAppBrowser` - Abre los enlaces en un navegador dentro de la app (por defecto)

- `AdaptyWebPresentation.ExternalBrowser` - Abre los enlaces en el navegador externo del dispositivo

Consulta [Personalizar cómo se abren los enlaces en los onboardings](unity-present-onboardings#customize-how-links-open-in-onboardings) para ver ejemplos de uso.

| Una vez que hayas cargado correctamente el onboarding y su configuración de vista, puedes [mostrarlo en tu app móvil](unity-present-onboardings). ## Acelerar la obtención del onboarding con el onboarding de audiencia por defecto \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi de inmediato, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, en los casos en que tienes numerosas audiencias y onboardings, y tus usuarios tienen una conexión a internet débil, obtener un onboarding puede tardar más de lo que te gustaría. En estas situaciones, puede que quieras mostrar un onboarding por defecto para garantizar una experiencia de usuario fluida en lugar de no mostrar ninguno. Para resolver esto, puedes usar el método `GetOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding con el método `getOnboarding`, tal como se detalla en la sección [Obtener el onboarding](#fetch-onboarding) anterior. :::warning Considera usar `GetOnboarding` en lugar de `GetOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede generar problemas al admitir varias versiones de la app, lo que requiere diseños compatibles con versiones anteriores o aceptar que las versiones más antiguas puedan mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación basada en país, atribución o atributos personalizados. Si una obtención más rápida supera estos inconvenientes para tu caso de uso, usa `GetOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `GetOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```csharp showLineNumbers Adapty.GetOnboardingForDefaultAudience("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |

opcional

por defecto: `en`

|

El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.

Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.

| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |

Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.

Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.

Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.

El SDK de Adapty almacena los onboardings localmente en dos capas: la caché actualizada periódicamente descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.

| --- # File: unity-present-onboardings --- --- title: "Presentar onboardings en Unity SDK" description: "Aprende a presentar onboardings de manera efectiva para impulsar más conversiones." --- Si has personalizado un onboarding usando el builder, no necesitas preocuparte por renderizarlo en el código de tu app Unity para mostrárselo al usuario. Dicho onboarding contiene tanto lo que debe mostrarse dentro del onboarding como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Tienes instalado el [SDK de Adapty para Unity](sdk-installation-unity) 3.14.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Para mostrar un onboarding, usa el método `view.Present()` sobre el `view` creado por el método `CreateOnboardingView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreateOnboardingView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede producir un error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((presentError) => { if (presentError != null) { // handle the error } }; ``` ## Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el onboarding en iOS pasando el parámetro `iosPresentationStyle` al método `Present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.FullScreen` (predeterminado) o `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` ## Personalizar cómo se abren los enlaces en los onboardings \{#customize-how-links-open-in-onboardings\} :::important La personalización de cómo se abren los enlaces en los onboardings está disponible a partir del SDK de Adapty v. 3.15. ::: Por defecto, los enlaces en los onboardings se abren en un navegador integrado en la app, lo que ofrece una experiencia fluida al mostrar las páginas web dentro de tu aplicación sin cambiar de app. Para abrir los enlaces en un navegador externo en su lugar, pasa `AdaptyWebPresentation.ExternalBrowser` al método `CreateOnboardingView`: ```csharp showLineNumbers title="Unity" AdaptyUI.CreateOnboardingView( onboarding, AdaptyWebPresentation.ExternalBrowser, // default — InAppBrowser (view, error) => { if (error != null) { // handle the error return; } // present the onboarding view view.Present((presentError) => { if (presentError != null) { // handle the error } }); } ); ``` Opciones disponibles: - `AdaptyWebPresentation.InAppBrowser` - Abre los enlaces en un navegador integrado en la app (predeterminado) - `AdaptyWebPresentation.ExternalBrowser` - Abre los enlaces en el navegador externo del dispositivo --- # File: unity-handling-onboarding-events --- --- title: "Gestionar eventos de onboarding en Unity SDK" description: "Gestiona eventos relacionados con el onboarding en Unity usando Adapty." --- Antes de empezar, asegúrate de que: 1. Tienes instalado el [SDK de Adapty para Unity](sdk-installation-unity) 3.14.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Los onboardings configurados con el builder generan eventos a los que tu app puede responder. A continuación aprenderás cómo responder a esos eventos. Para controlar o monitorizar los procesos que ocurren en la pantalla de onboarding dentro de tu app de Unity, implementa la interfaz `AdaptyOnboardingsEventsListener`. ## Acciones personalizadas \{#custom-actions\} En el builder puedes añadir una acción **custom** a un botón y asignarle un ID. Luego puedes usar ese ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si un usuario pulsa un botón personalizado como **Login** o **Allow notifications**, se activará el método `OnboardingViewOnCustomAction` con el parámetro `actionId` igual al **Action ID** definido en el builder. Puedes crear tus propios IDs, como "allowNotifications". Para gestionar los eventos del onboarding, implementa la interfaz `AdaptyOnboardingsEventsListener`: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { void Start() { Adapty.SetOnboardingsEventsListener(this); } public void OnboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { if (actionId == "allowNotifications") { // request notification permissions } } public void OnboardingViewDidFailWithError( AdaptyUIOnboardingView view, AdaptyError error ) { // handle errors } // Implement other required interface methods (see examples below) } ```
Ejemplo de evento (haz clic para expandir) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
## Cerrar el onboarding \{#closing-onboarding\} El onboarding se considera cerrado cuando el usuario pulsa un botón con la acción **Close** asignada. :::important Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, necesitas dejar de mostrar el onboarding en sí. ::: Implementa el método `OnboardingViewOnCloseAction` en tu clase: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { view.Dismiss((error) => { if (error != null) { // handle the error } }); } // ... other interface methods } ```
Ejemplo de evento (haz clic para expandir) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
## Abrir un paywall \{#opening-a-paywall\} :::tip Gestiona este evento para abrir un paywall si quieres abrirlo dentro del onboarding. Si prefieres abrir el paywall después de que este se cierre, hay una forma más directa: gestiona [`OnboardingViewOnCloseAction`](#closing-onboarding) y abre el paywall sin depender de los datos del evento. ::: Si un usuario pulsa un botón que abre un paywall, recibirás el ID de acción del botón que [configuraste manualmente](get-paid-in-onboardings). La forma más fluida de trabajar con paywalls en onboardings es hacer que el ID de acción sea igual al ID de placement del paywall. Así, tras el evento `OnboardingViewOnPaywallAction`, puedes usar el ID de placement para obtener y abrir el paywall de inmediato. Ten en cuenta que, en iOS, solo puede mostrarse una vista (paywall u onboarding) en pantalla a la vez. Si presentas un paywall encima de un onboarding, no podrás controlar el onboarding en segundo plano de forma programática. Si intentas cerrar el onboarding, se cerrará el paywall en su lugar, dejando visible el onboarding. Para evitarlo, cierra siempre la vista del onboarding antes de presentar el paywall. ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { // Dismiss onboarding before presenting paywall view.Dismiss((dismissError) => { if (dismissError != null) { // handle the error return; } Adapty.GetPaywall(actionId, (paywall, error) => { if (error != null) { // handle the error return; } AdaptyUI.CreatePaywallView(paywall, (paywallView, createError) => { if (createError != null) { // handle the error return; } paywallView.Present((presentError) => { if (presentError != null) { // handle the error } }); }); }); }); } // ... other interface methods } ```
Ejemplo de evento (haz clic para expandir) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
## Finalización de la carga del onboarding \{#finishing-loading-onboarding\} Cuando el onboarding termina de cargarse, implementa el método `OnboardingViewDidFinishLoading`: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta ) { // handle loading completion } // ... other interface methods } ```
Ejemplo de evento (haz clic para expandir) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
## Seguimiento de la navegación \{#tracking-navigation\} El método `OnboardingViewOnAnalyticsEvent` se invoca cuando ocurren distintos eventos de analítica durante el flujo del onboarding. El objeto `analyticsEvent` puede ser uno de los siguientes tipos: | Tipo | Descripción | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | Cuando el onboarding ha sido cargado | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | Cuando se muestra cualquier pantalla | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | Cuando se completa una pantalla. Incluye el `ElementId` opcional (identificador del elemento completado) y `Reply` opcional (respuesta del usuario). Se activa cuando el usuario realiza cualquier acción para salir de la pantalla. | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | Cuando se muestra la segunda pantalla | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | Se activa cuando se recoge el correo electrónico del usuario mediante el campo de entrada | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | Se activa cuando el usuario llega a una pantalla con el ID `final`. Si necesitas este evento, [asigna el ID `final` a la última pantalla](design-onboarding). | | `AdaptyOnboardingsAnalyticsEventUnknown` | Para cualquier tipo de evento no reconocido. Incluye `Name` (el nombre del evento desconocido) y `meta` (metadatos adicionales) | Cada evento incluye información de `meta` con los siguientes campos: | Campo | Descripción | |------------|-------------| | `OnboardingId` | Identificador único del flujo de onboarding | | `ScreenClientId` | Identificador de la pantalla actual | | `ScreenIndex` | Posición de la pantalla actual en el flujo | | `ScreensTotal` | Número total de pantallas en el flujo | Aquí tienes un ejemplo de cómo usar los eventos de analítica para el seguimiento: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent analyticsEvent ) { switch (analyticsEvent) { case AdaptyOnboardingsAnalyticsEventOnboardingStarted: // track onboarding start TrackEvent("onboarding_started", meta); break; case AdaptyOnboardingsAnalyticsEventScreenPresented: // track screen presentation TrackEvent("screen_presented", meta); break; case AdaptyOnboardingsAnalyticsEventScreenCompleted screenCompleted: // track screen completion with user response TrackEvent("screen_completed", meta, screenCompleted.ElementId, screenCompleted.Reply); break; case AdaptyOnboardingsAnalyticsEventOnboardingCompleted: // track successful onboarding completion TrackEvent("onboarding_completed", meta); break; case AdaptyOnboardingsAnalyticsEventUnknown unknownEvent: // handle unknown events TrackEvent(unknownEvent.Name, meta); break; // handle other cases as needed } } // ... other interface methods } ``` :::note El método `TrackEvent` es un marcador de posición que debes implementar tú mismo para enviar analítica a tu servicio preferido. :::
Ejemplos de eventos (haz clic para expandir) ```javascript // onboardingStarted { "name": "onboarding_started", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } // screenPresented { "name": "screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 4 } } // screenCompleted { "name": "screen_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 }, "params": { "element_id": "profile_form", "reply": "success" } } // secondScreenPresented { "name": "second_screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // userEmailCollected { "name": "user_email_collected", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // onboardingCompleted { "name": "onboarding_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
--- # File: unity-onboarding-input --- --- title: "Procesar datos de onboardings en Unity SDK" description: "Guarda y usa datos de onboardings en tu app Unity con Adapty SDK." --- Cuando tus usuarios responden a una pregunta de quiz o introducen datos en un campo de texto, se invocará el método `OnboardingViewOnStateUpdatedAction`. Puedes guardar o procesar el tipo de campo en tu código. Implementa el método `OnboardingViewOnStateUpdatedAction` en tu clase: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { switch (@params) { case AdaptyOnboardingsSelectParams selectParams: // handle single selection break; case AdaptyOnboardingsMultiSelectParams multiSelectParams: // handle multiple selections break; case AdaptyOnboardingsInputParams inputParams: // handle text input break; case AdaptyOnboardingsDatePickerParams datePickerParams: // handle date selection break; } } // ... other interface methods } ``` Los parámetros incluyen: | Parámetro | Descripción | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | Un identificador único para el elemento de entrada. Puedes usarlo para asociar preguntas con respuestas al guardarlas. | | `@params` | El objeto con los datos de entrada del usuario. Puede ser uno de los siguientes tipos. | | `AdaptyOnboardingsSelectParams` | Selección única entre opciones. Contiene `Id`, `Value`, `Label` | | `AdaptyOnboardingsMultiSelectParams` | Selecciones múltiples entre opciones. Contiene una lista de `Params` (cada uno con `Id`, `Value`, `Label`)
• `input`: Objeto con `type`, `value`
• `datePicker`: Objeto con `day`, `month`, `year` | | `AdaptyOnboardingsInputParams` | Campo de entrada de texto. Contiene `Input`, que puede ser `AdaptyOnboardingsTextInput`, `AdaptyOnboardingsEmailInput` o `AdaptyOnboardingsNumberInput` | | `AdaptyOnboardingsDatePickerParams` | Selección de fecha. Contiene `Day`, `Month`, `Year` opcionales |
Ejemplos de datos guardados (pueden variar según tu implementación) ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ```
## Casos de uso \{#use-cases\} ### Enriquecer perfiles de usuario con datos \{#enrich-user-profiles-with-data\} Si quieres vincular inmediatamente los datos de entrada con el perfil del usuario y evitar preguntarle dos veces por la misma información, necesitas [actualizar el perfil del usuario](unity-setting-user-attributes) con los datos de entrada al gestionar la acción. Por ejemplo, pides a los usuarios que introduzcan su nombre en el campo de texto con el ID `name` y quieres establecer el valor de ese campo como su nombre de pila. También les pides que introduzcan su correo electrónico en el campo `email`. En el código de tu app, puede verse así: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsInputParams inputParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "name": if (inputParams.Input is AdaptyOnboardingsTextInput textInput) { builder.SetFirstName(textInput.Value); } break; case "email": if (inputParams.Input is AdaptyOnboardingsEmailInput emailInput) { builder.SetEmail(emailInput.Value); } break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` ### Personalizar paywalls según las respuestas \{#customize-paywalls-based-on-answers\} Usando quizzes en los onboardings, también puedes personalizar los paywalls que muestras a los usuarios después de que completen el onboarding. Por ejemplo, puedes preguntarles sobre su experiencia con el deporte y mostrar diferentes CTAs y productos a distintos grupos de usuarios. 1. [Añade un quiz](onboarding-quizzes) en el editor de onboarding y asigna IDs significativos a sus opciones. 2. Gestiona las respuestas del quiz según sus IDs y [establece atributos personalizados](unity-setting-user-attributes) para los usuarios. ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsSelectParams selectParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "experience": // set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.SetCustomStringAttribute("experience", selectParams.Value); break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` 3. [Crea segmentos](segments) para cada valor de atributo personalizado. 4. Crea un [placement](placements) y añade [audiencias](audience) para cada segmento que hayas creado. 5. [Muestra un paywall](unity-paywalls) para el placement en el código de tu app. Si tu onboarding tiene un botón que abre un paywall, implementa el código del paywall como [respuesta a la acción de ese botón](unity-handling-onboarding-events#opening-a-paywall). --- # File: unity-sdk-call-order --- --- title: "Orden de llamadas en Unity SDK" description: "Evita perder acceso premium, atribución faltante y errores intermitentes #2002 llamando a los métodos del SDK de Adapty en el orden correcto." --- `Adapty.Activate()` debe completarse antes de llamar a cualquier otro método del SDK de Adapty. Hasta que se dispare su callback de finalización, el SDK no tiene estado. Cualquier llamada realizada antes o en paralelo con `Activate()` falla con [`#2002 notActivated`](unity-handle-errors#custom-network-codes). Si tu app autentica usuarios y obtienes un customer user ID después del lanzamiento, llama a `Adapty.Identify()` en ese momento. No llames a métodos de acción del usuario hasta que se dispare el callback de `Identify`. Las llamadas que compiten con él o bien fallan con [`#3006 profileWasChanged`](unity-handle-errors#custom-network-codes), o aterrizan en el perfil anónimo creado durante la activación. Cuando esto ocurre, la atribución, los IDs de MMP como `appsflyer_id` y la propiedad de instalación no siempre se transfieren al perfil identificado. Si tu app no autentica usuarios, omite `Identify` y sigue trabajando con el perfil anónimo. Los SDKs de MMP y analíticas (AppsFlyer, Adjust, Branch, PostHog) siguen la misma regla. Inicialízalos primero y espera a sus callbacks de UID antes de llamar a `Adapty.Activate`. De lo contrario, el ID del MMP aterriza en un perfil anónimo temporal y no siempre se transfiere al identificado. Para los detalles específicos de AppsFlyer, consulta [AppsFlyer](appsflyer). ## El orden correcto \{#the-correct-order\} Tu ruta depende de dos cosas: cuándo conoces el customer user ID y si usas un SDK de MMP o analíticas. - **Pasos 2 y 5**: Obligatorios para toda app. Activa el SDK y luego llama a los métodos del SDK. - **Pasos 1 y 3**: Necesarios solo si integras un SDK de MMP o analíticas (AppsFlyer, Adjust, Branch, PostHog). - **Paso 4**: Necesario solo si tu app autentica usuarios y obtiene el customer user ID después del lanzamiento. Si tienes el customer user ID al iniciar la app, pásalo directamente a `Activate()` (paso 2a). Esta ruta nunca crea un perfil anónimo, por lo que el paso 4 es innecesario. | Paso | Llamada | Cuándo | Notas | |------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Inicializa tu SDK de MMP o analíticas (AppsFlyer, Adjust, PostHog, Branch) | Al lanzar la app, lo primero | Espera el callback de UID del MMP, por ejemplo `getAppsFlyerId`. | | 2a | `Adapty.Activate(builder.Build(), ...)` con `SetCustomerUserId` configurado en el builder | Al lanzar la app, después del paso 1, si tienes el customer user ID | Recomendado. Nunca se crea un perfil anónimo. | | 2b | `Adapty.Activate(builder.Build(), ...)` sin `SetCustomerUserId` | Al lanzar la app, después del paso 1, si no tienes el customer user ID (o nunca lo obtienes) | Adapty crea un perfil anónimo. | | 3 | `Adapty.SetIntegrationIdentifier(key, value, callback)` para cada MMP | Después del paso 2, antes de cualquier llamada de acción del usuario | Necesario para que los IDs del MMP aterricen en el perfil correcto. | | 4 | `Adapty.Identify("YOUR_USER_ID", callback)` | Después del paso 3 (o paso 2 si no hay MMP), antes del paso 5 — solo en la ruta 2b con autenticación | Espera el callback de finalización. Las llamadas concurrentes durante `Identify` producen `#3006 profileWasChanged`. | | 5 | `GetPaywall`, `GetPaywallProducts`, `RestorePurchases`, `MakePurchase`, `UpdateAttribution`, `UpdateProfile` | Después del paso 4 si llamas a `Identify`; en caso contrario, después del paso 3 (o paso 2 si no hay MMP) | Estas llamadas necesitan un perfil estable. | :::important Saltarse estos pasos provoca pérdida de acceso premium para usuarios recurrentes, `appsflyer_id` ausente en los perfiles y paywalls devueltos para la audiencia incorrecta. ::: ## Instalaciones web2app y web-funnel \{#web2app-and-web-funnel-installs\} Si los usuarios compran en un checkout web (Stripe, Paddle) y luego instalan la app nativa, el primer `Activate()` del dispositivo crea un nuevo perfil anónimo. Este perfil no está vinculado al perfil web. Si puedes resolver el customer user ID antes del lanzamiento de la app (desde tu flujo de autenticación o el referrer de instalación), pásalo directamente a `Activate()`. De lo contrario, la compra web es invisible en el dispositivo hasta que llames a `Identify("YOUR_USER_ID")` y luego a `RestorePurchases`. Para los metadatos que debes enviar con cada checkout web, consulta: - [Stripe](stripe) - [Paddle](paddle) --- # File: unity-optimize-paywall-fetching --- --- title: "Optimizar la carga de paywalls en Unity SDK" description: "Carga paywalls de Adapty de forma fiable: timing, caché y patrones de respaldo para Unity." --- Una carga de paywall fiable en Unity hace tres cosas: renderiza rápido, devuelve el paywall dirigido a la audiencia correcta y recurre al respaldo cuando la red es lenta. Las reglas a continuación cubren el timing, la caché y los patrones de respaldo para conseguirlo. :::tip Las reglas asumen que `Adapty.Activate()` y `Adapty.Identify()` ya han finalizado. Consulta [Orden de llamadas en Unity SDK](unity-sdk-call-order). ::: ## Reglas y errores comunes \{#rules-and-pitfalls\} | Haz esto | No hagas esto | Por qué | |---|---|---| | Carga el placement que vas a mostrar. | Precarga todos los placements de forma concurrente al iniciar. | La precarga masiva bloquea el hilo principal y produce una pantalla en negro durante la ráfaga. | | Llama a `GetPaywall` después de que la atribución haya tenido tiempo de resolverse — por ejemplo, 1–2 segundos después de `Activate` o cuando se dispare `OnLoadLatestProfile`. | Llama a `GetPaywall` en `Awake()`. | La atribución aún no ha llegado. El paywall se resuelve contra la audiencia predeterminada y omite silenciosamente los segmentos y la personalización de ASA. | | Establece un `loadTimeout` y configura un [paywall de respaldo](fallback-paywalls) para cada placement. | Esperes indefinidamente a que `GetPaywall` responda. | Sin un timeout, los usuarios con conectividad deficiente ven una pantalla en blanco hasta que la red responde — o cierran la app. | Consulta [Cargar paywalls y productos](fetch-paywalls-and-products-unity) para la referencia de los parámetros `fetchPolicy` y `loadTimeout`, y [Placements](placements) para elegir el placement adecuado. ## Ajustar para conectividad deficiente \{#tune-for-poor-connectivity\} Para mercados con conectividad sistemáticamente deficiente (zonas rurales, transporte, regiones con problemas de enrutamiento): - Establece `fetchPolicy` a `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` en cada carga excepto la primera. - Configura un [paywall de respaldo](fallback-paywalls) para cada placement en el Adapty Dashboard. - Establece `loadTimeout` entre 3 y 5 segundos y acepta el paywall de respaldo cuando se agote el tiempo. - No condicionales la visualización del paywall a `GetProfile`. Llama a `GetPaywall` de forma independiente para que un perfil lento no bloquee la interfaz. --- # File: unity-test --- --- title: "Prueba y lanzamiento con Unity SDK" description: "Aprende a probar y lanzar tu app Unity con el SDK de Adapty." --- Si ya has implementado el SDK de Adapty en tu app de Unity, querrás verificar que todo está configurado correctamente y que las compras funcionan como se espera en las plataformas iOS y Android. Esto implica probar tanto la integración del SDK como el flujo de compra real con el entorno sandbox de Apple y el entorno de pruebas de Google Play. ## Prueba tu app \{#test-your-app\} Para realizar pruebas completas de tus compras in-app, consulta nuestras guías de pruebas específicas para cada plataforma: [guía de pruebas para iOS](test-purchases-in-sandbox) y [guía de pruebas para Android](testing-on-android). ## Prepárate para el lanzamiento \{#prepare-for-release\} Antes de enviar tu app al store, sigue el [checklist de lanzamiento](release-checklist) para confirmar: - La conexión con el store y las notificaciones del servidor están configuradas - Las compras se completan y se reportan a Adapty - El acceso se desbloquea y se restaura correctamente - Se cumplen los requisitos de privacidad y revisión --- # File: InvalidProductIdentifiers-unity --- --- title: "Solución para el error Code-1000 noProductIDsFound en Unity SDK" description: "Resuelve errores de identificador de producto no válido al gestionar suscripciones en Adapty." --- El error con código 1000, `noProductIDsFound`, indica que ninguno de los productos que solicitaste en el paywall está disponible para comprar en el App Store, aunque aparezcan listados allí. A veces este error va acompañado de una advertencia `InvalidProductIdentifiers`. Si la advertencia aparece sin el error, puedes ignorarla sin problema. Si estás viendo el error `noProductIDsFound`, sigue estos pasos para resolverlo: ## Paso 1. Comprueba el bundle ID \{#step-2-check-bundle-id\} --- no_index: true --- 1. Abre [App Store Connect](https://appstoreconnect.apple.com/apps). Selecciona tu app y ve a la sección **General** → **App Information**. 2. Copia el **Bundle ID** en la subsección **General Information**. 3. Abre la pestaña [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) desde el menú superior de Adapty y pega el valor copiado en el campo **Bundle ID**. 4. Vuelve a la página **App information** en App Store Connect y copia el **Apple ID** desde allí. 5. En la página [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) del Adapty Dashboard, pega el ID en el campo **Apple app ID**. ## Paso 2. Comprueba los productos \{#step-3-check-products\} 1. Ve a **App Store Connect** y navega a [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) en el menú de la izquierda. 2. Haz clic en el nombre del grupo de suscripción. Verás tus productos listados en la sección **Subscriptions**. 3. Asegúrate de que el producto que estás probando aparece como **Ready to Submit**. 4. Compara el ID del producto de la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard. ## Paso 3. Comprueba la disponibilidad del producto \{#step-4-check-product-availability\} 1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**. 2. Haz clic en el nombre del grupo de suscripción para ver tus productos. 3. Selecciona el producto que estás probando. 4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones requeridos están en la lista. ## Paso 4. Comprueba los precios del producto \{#step-5-check-product-prices\} 1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**. 2. Haz clic en el nombre del grupo de suscripción. 3. Selecciona el producto que estás probando. 4. Desplázate hacia abajo hasta **Subscription Pricing** y despliega la sección **Current Pricing for New Subscribers**. 5. Asegúrate de que todos los precios requeridos están en la lista. ## Paso 5. Comprueba que el estado de pago de la app, la cuenta bancaria y los formularios fiscales están activos \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**. 2. Selecciona el nombre de tu empresa. 3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, **Bank Account** y **Tax forms** aparecen todos como **Active**. Siguiendo estos pasos deberías poder resolver la advertencia `InvalidProductIdentifiers` y publicar tus productos en el store. ## Paso 6. Vuelve a crear el producto si está bloqueado \{#step-6-recreate-the-product-if-its-stuck\} Puede que los pasos 1 a 5 pasen todos correctamente — estado `Approved`, Bundle ID correcto, API key válida — y aun así el SDK siga devolviendo `1000 noProductIDsFound`. En ese caso, es posible que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple puede entrar en un estado en el que un producto existe en la interfaz de App Store Connect pero no está expuesto en la ruta de búsqueda de StoreKit. Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas después de volver a crearlo para que los cambios se propaguen. --- # File: cantMakePayments-unity --- --- title: "Solución para el error Code-1003 cantMakePayment en el SDK de Unity" description: "Resuelve el error de pagos al gestionar suscripciones en Adapty." --- El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo. Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones: - Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo. - Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo. ## Problema: Restricciones del dispositivo \{#issue-device-restrictions\} | Problema | Solución | |-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------| | Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) | | Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta | | Restricciones regionales | Usa una cuenta de App Store de una región compatible | ## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\} Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo. Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK. --- # File: migration-to-unity-sdk-314 --- --- title: "Migrar el SDK de Adapty para Unity a la v. 3.14" description: "Migra al SDK de Adapty para Unity v3.14 para mejorar el rendimiento y acceder a nuevas funciones de monetización." --- El SDK de Adapty 3.14.0 es una versión mayor que incorpora mejoras que pueden requerir algunos pasos de migración: 1. Listener de eventos independiente para eventos de paywall. 2. Renombrar `AdaptyUI.CreateView` a `AdaptyUI.CreatePaywallView` y métodos relacionados. 3. Actualizar el método `MakePurchase` para usar `AdaptyPurchaseParameters` en lugar de parámetros individuales. 4. Reemplazar `SetFallbackPaywalls` por el método `SetFallback`. 5. Actualizar el acceso a propiedades del paywall para usar `AdaptyPlacement`. 6. Actualizar el acceso a la configuración remota usando el objeto `AdaptyRemoteConfig`. 7. Reemplazar `VendorProductIds` por `ProductIdentifiers` en el modelo `AdaptyPaywall`. 8. Actualizar la política de obtención en `GetPaywall` para usar `AdaptyFetchPolicy`. ## Listener de eventos independiente para eventos de paywall \{#separate-event-listener-for-paywall-events\} Si muestras paywalls diseñados con el [Paywall Builder](adapty-paywall-builder), los eventos de la vista de paywall ahora usan la interfaz dedicada `AdaptyPaywallsEventsListener` y el método `SetPaywallsEventsListener`. La interfaz principal `AdaptyEventListener` sigue siendo la encargada de las actualizaciones de perfil y los detalles de instalación. ```diff showLineNumbers using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, - AdaptyEventListener { + AdaptyEventListener, + AdaptyPaywallsEventsListener { void Start() { Adapty.SetEventListener(this); + Adapty.SetPaywallsEventsListener(this); } // AdaptyEventListener methods public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } + // AdaptyPaywallsEventsListener methods + // Implement paywall event handlers here } ``` [Más información sobre cómo gestionar eventos de paywall](unity-handling-events). ## Renombrar los métodos de creación y presentación de vistas \{#rename-view-creation-and-presentation-methods\} Los métodos de creación y presentación de vistas han sido renombrados: ```diff showLineNumbers using AdaptySDK; - AdaptyUI.CreateView(paywall, parameters, (view, error) => { + AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if (error != null) { // handle the error return; } - AdaptyUI.PresentView(view, (error) => { + AdaptyUI.PresentPaywallView(view, (error) => { // handle the error }); }); } ``` Del mismo modo, el método de cierre ha sido renombrado: ```diff showLineNumbers - AdaptyUI.DismissView(view, (error) => { + AdaptyUI.DismissPaywallView(view, (error) => { // handle the error }); ``` ## Actualizar el método MakePurchase \{#update-makepurchase-method\} El método `MakePurchase` ahora usa `AdaptyPurchaseParameters` en lugar de los argumentos individuales `subscriptionUpdateParams` e `isOfferPersonalized`. Esto mejora la seguridad de tipos y permite ampliar los parámetros de compra en el futuro. ```diff showLineNumbers using AdaptySDK; void MakePurchase( AdaptyPaywallProduct product, AdaptySubscriptionUpdateParameters subscriptionUpdate, bool? isOfferPersonalized ) { - Adapty.MakePurchase(product, subscriptionUpdate, isOfferPersonalized, (result, error) => { + var parameters = new AdaptyPurchaseParametersBuilder() + .SetSubscriptionUpdateParams(subscriptionUpdate) + .SetIsOfferPersonalized(isOfferPersonalized) + .Build(); + + Adapty.MakePurchase(product, parameters, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successful purchase break; default: break; } }); } ``` Si no necesitas parámetros adicionales, puedes usar simplemente: ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { // handle purchase result }); } ``` ## Actualizar el método de respaldo \{#update-fallback-method\} :::important Al actualizar al SDK de Unity 3.14, deberás descargar los nuevos archivos de respaldo desde el Adapty Dashboard y reemplazar los existentes en tu proyecto. ::: El método para configurar los paywall de respaldo ha sido actualizado. El método `SetFallbackPaywalls` ha sido renombrado a `SetFallback`: ```diff showLineNumbers using AdaptySDK; void SetFallBackPaywalls() { #if UNITY_IOS var assetId = "adapty_fallback_ios.json"; #elif UNITY_ANDROID var assetId = "adapty_fallback_android.json"; #else var assetId = ""; #endif - Adapty.SetFallbackPaywalls(assetId, (error) => { + Adapty.SetFallback(assetId, (error) => { // handle the error }); } ``` Consulta el ejemplo de código final en la página [Usar paywalls de respaldo en Unity](unity-use-fallback-paywalls). ## Actualizar el acceso a propiedades del paywall \{#update-paywall-property-access\} Las siguientes propiedades se han movido de `AdaptyPaywall` a `AdaptyPlacement`: ```diff showLineNumbers using AdaptySDK; void ProcessPaywall(AdaptyPaywall paywall) { - var abTestName = paywall.ABTestName; - var audienceName = paywall.AudienceName; - var revision = paywall.Revision; - var placementId = paywall.PlacementId; + var abTestName = paywall.Placement.ABTestName; + var audienceName = paywall.Placement.AudienceName; + var revision = paywall.Placement.Revision; + var placementId = paywall.Placement.Id; } ``` ## Actualizar el acceso a la configuración remota \{#update-remote-config-access\} Las propiedades de Remote Config se han reestructurado en un objeto `AdaptyRemoteConfig` para una mejor organización: ```diff showLineNumbers using AdaptySDK; void ProcessRemoteConfig(AdaptyPaywall paywall) { - var remoteConfigString = paywall.RemoteConfigString; - var locale = paywall.Locale; - var remoteConfigDict = paywall.RemoteConfig; + var remoteConfigString = paywall.RemoteConfig.Data; + var locale = paywall.RemoteConfig.Locale; + var remoteConfigDict = paywall.RemoteConfig.Dictionary; } ``` ## Actualizar el uso del modelo AdaptyPaywall \{#update-adaptyPaywall-model-usage\} La propiedad `VendorProductIds` ha quedado obsoleta en favor de `ProductIdentifiers`. La nueva propiedad devuelve objetos `AdaptyProductIdentifier` en lugar de cadenas simples, lo que proporciona información de producto más estructurada. ```diff showLineNumbers using AdaptySDK; void ProcessPaywallProducts(AdaptyPaywall paywall) { - var productIds = paywall.VendorProductIds; - foreach (var vendorId in productIds) { - // use vendorId - } + var productIdentifiers = paywall.ProductIdentifiers; + foreach (var productId in productIdentifiers) { + var vendorId = productId.VendorProductId; + // use vendorId + } } ``` El objeto `AdaptyProductIdentifier` da acceso al ID del producto del proveedor a través de la propiedad `VendorProductId`, manteniendo la misma funcionalidad y ofreciendo una mejor estructura para futuras mejoras. ## Actualizar la política de obtención en GetPaywall \{#update-getpaywall-fetch-policy\} El tipo del parámetro `fetchPolicy` en el método `GetPaywall` ha cambiado de `AdaptyPaywallFetchPolicy` a `AdaptyPlacementFetchPolicy`. Este cambio unifica el uso de la política de obtención en todo el SDK. ```diff showLineNumbers using AdaptySDK; void GetPaywall(string placementId) { - Adapty.GetPaywall(placementId, AdaptyPaywallFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => { + Adapty.GetPaywall(placementId, AdaptyPlacementFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => { // handle the result }); } ``` --- # File: migration-to-unity-sdk-34 --- --- title: "Migrar Adapty Unity SDK a v. 3.4" description: "Migra al Adapty Unity SDK v3.4 para mejorar el rendimiento y acceder a nuevas funciones de monetización." --- Adapty SDK 3.4.0 es una versión mayor que incluye mejoras que requieren pasos de migración por tu parte. ## Actualizar los archivos de paywall de respaldo \{#update-fallback-paywall-files\} Actualiza los archivos de paywall de respaldo para garantizar la compatibilidad con la nueva versión del SDK: 1. [Descarga los archivos de paywall de respaldo actualizados](fallback-paywalls) desde el Adapty Dashboard. 2. [Reemplaza los paywalls de respaldo existentes en tu aplicación móvil](unity-use-fallback-paywalls) con los nuevos archivos. ## Actualizar la implementación del modo Observer \{#update-implementation-of-observer-mode\} Si usas el modo Observer, asegúrate de actualizar su implementación. Anteriormente, se usaban distintos métodos para reportar transacciones a Adapty. En la nueva versión, el método `reportTransaction` debe usarse de forma consistente tanto en Android como en iOS. Este método reporta explícitamente cada transacción a Adapty, garantizando que sea reconocida. Si se usó un paywall, pasa el ID de variación para vincular la transacción a él. :::warning **¡No omitas el reporte de transacciones!** Si no llamas a `reportTransaction`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones. ::: ```diff showLineNumbers - #if UNITY_ANDROID && !UNITY_EDITOR - Adapty.RestorePurchases((profile, error) => { - // handle the error - }); - #endif Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` --- # File: migration-to-unity330 --- --- title: "Migrar Adapty Unity SDK a la versión 3.3" description: "Migra al Adapty Unity SDK v3.3 para obtener mejor rendimiento y nuevas funciones de monetización." --- Adapty SDK 3.3.0 es una versión mayor que incorpora mejoras que pueden requerir algunos pasos de migración por tu parte. 1. Actualiza a Adapty SDK v3.3.x. 2. Se han renombrado varias clases, propiedades y métodos en los módulos Adapty y AdaptyUI del SDK de Adapty. 3. A partir de ahora, el método `SetLogLevel` acepta un callback como argumento. 4. A partir de ahora, el método `PresentCodeRedemptionSheet` acepta un callback como argumento. 5. Cambia la forma en que se crea la vista del paywall. 6. Elimina el método `GetProductsIntroductoryOfferEligibility`. 7. Guarda los paywalls de respaldo en archivos separados (uno por plataforma) en `Assets/StreamingAssets/` y pasa los nombres de archivo al método `SetFallbackPaywalls`. 8. Actualiza la lógica de compra. 9. Actualiza el manejo de eventos del Paywall Builder. 10. Actualiza el manejo de errores del paywall del Paywall Builder. 11. Actualiza las configuraciones de integración para Adjust, Amplitude, AppMetrica, Appsflyer, Branch, Firebase and Google Analytics, Mixpanel, OneSignal, Pushwoosh. 13. Actualiza la implementación del modo Observer. 14. Actualiza la inicialización del plugin de Unity con una llamada explícita a `Activate`. ## Actualizar el Adapty Unity SDK a la versión 3.3.x \{#upgrade-adapty-unity-sdk-to-33x\} Hasta esta versión, Adapty SDK era el SDK principal e imprescindible para el funcionamiento correcto de Adapty en tu app, mientras que AdaptyUI SDK era un SDK opcional que solo se necesitaba si usabas el Adapty Paywall Builder. A partir de la versión 3.3.0, AdaptyUI SDK queda obsoleto y AdaptyUI se fusiona con el Adapty SDK como módulo. Debido a estos cambios, debes eliminar AdaptyUISDK y reinstalar AdaptySDK. 1. Elimina las dependencias de los paquetes **AdaptySDK** y **AdaptyUISDK** de tu proyecto. 2. Borra las carpetas **AdaptySDK** y **AdaptyUISDK**. 3. Importa de nuevo el paquete AdaptySDK tal como se describe en la página [Instalación y configuración del SDK de Adapty para Unity](sdk-installation-unity). ## Renombramientos \{#renamings\} 1. Renombramientos en el módulo Adapty: | Versión anterior | Nueva versión | | ------------------------- | ------------------------ | | Adapty.sdkVersion | Adapty.SDKVersion | | Adapty.LogLevel | AdaptyLogLevel | | Adapty.Paywall | AdaptyPaywall | | Adapty.PaywallFetchPolicy | AdaptyPaywallFetchPolicy | | PaywallProduct | AdaptyPaywallProduct | | Adapty.Profile | AdaptyProfile | | Adapty.ProfileParameters | AdaptyProfileParameters | | ProfileGender | AdaptyProfileGender | | Error | AdaptyError | 2. Renombramientos en el módulo AdaptyUI: | Versión anterior | Nueva versión | | ------------------ | ------------------ | | CreatePaywallView | CreateView | | PresentPaywallView | PresentView | | DismissPaywallView | DismissView | | AdaptyUI.View | AdaptyUIView | | AdaptyUI.Action | AdaptyUIUserAction | ## Cambiar el método SetLogLevel \{#change-the-setloglevel-method\} A partir de ahora, el método `SetLogLevel` acepta un callback como argumento. ```diff showLineNumbers - Adapty.SetLogLevel(Adapty.LogLevel.Verbose); + Adapty.SetLogLevel(Adapty.LogLevel.Verbose, null); // or you can pass the callback to handle the possible error ``` ## Cambiar el método PresentCodeRedemptionSheet \{#change-the-presentcoderedemptionsheet-method\} A partir de ahora, el método `PresentCodeRedemptionSheet` acepta un callback como argumento. ```diff showLineNumbers - Adapty.PresentCodeRedemptionSheet(); + Adapty.PresentCodeRedemptionSheet(null); // or you can pass the callback to handle the possible error ``` ## Cambiar la forma en que se crea la vista del paywall \{#change-how-the-paywall-view-is-created\} Para ver el ejemplo de código completo, consulta [Obtener la configuración de vista del paywall diseñado con el Paywall Builder](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). ```diff showLineNumbers + var parameters = new AdaptyUICreateViewParameters() + .SetPreloadProducts(true); - AdaptyUI.CreatePaywallView( + AdaptyUI.CreateView( paywall, - preloadProducts: true, + parameters, (view, error) => { // use the view }); ``` ## Eliminar el método GetProductsIntroductoryOfferEligibility \{#remove-the-getproductsintroductoryoffereligibility-method\} Antes de Adapty iOS SDK 3.3.0, el objeto producto siempre incluía las ofertas, independientemente de si el usuario era elegible. Había que comprobar la elegibilidad manualmente antes de usar la oferta. Ahora, el objeto producto solo incluye una oferta si el usuario es elegible. Esto significa que ya no es necesario comprobar la elegibilidad: si hay una oferta disponible, el usuario es elegible. ## Actualizar el método para proporcionar paywalls de respaldo \{#update-method-for-providing-fallback-paywalls\} Hasta esta versión, los paywalls de respaldo se pasaban como JSON serializado. A partir de la versión 3.3.0, el mecanismo ha cambiado: 1. Guarda los paywalls de respaldo en archivos dentro de `/Assets/StreamingAssets/`, un archivo para Android y otro para iOS. 2. Pasa los nombres de archivo al método `SetFallbackPaywalls`. Tu código cambiará de la siguiente manera: ```diff showLineNumbers using AdaptySDK; void SetFallBackPaywalls() { + #if UNITY_IOS + var assetId = "adapty_fallback_ios.json"; + #elif UNITY_ANDROID + var assetId = "adapty_fallback_android.json"; + #else + var assetId = ""; + #endif - Adapty.SetFallbackPaywalls("FALLBACK_PAYWALLS_JSON_STRING", (error) => { + Adapty.SetFallbackPaywalls(assetId, (error) => { // handle the error }); } ``` Consulta el ejemplo de código completo en la página [Usar paywalls de respaldo en Unity](unity-use-fallback-paywalls). ## Actualizar la lógica de compra \{#update-making-purchase\} Anteriormente, las compras canceladas y pendientes se consideraban errores y devolvían los códigos `PaymentCancelled` y `PendingPurchase`, respectivamente. Ahora se usa una nueva clase `AdaptyPurchaseResultType` para procesar las compras canceladas, exitosas y pendientes. Actualiza el código de compra de la siguiente manera: ```diff showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { - Adapty.MakePurchase(product, (profile, error) => { - // handle successfull purchase + Adapty.MakePurchase(product, (result, error) => { + switch (result.Type) { + case AdaptyPurchaseResultType.Pending: + // handle pending purchase + break; + case AdaptyPurchaseResultType.UserCancelled: + // handle purchase cancellation + break; + case AdaptyPurchaseResultType.Success: + var profile = result.Profile; + // handle successful purchase + break; + default: + break; } }); } ``` Consulta el ejemplo de código completo en la página [Realizar compras en la app móvil](unity-making-purchases). ## Actualizar el manejo de eventos del Paywall Builder \{#update-handling-of-paywall-builder-events\} Las compras canceladas y pendientes ya no se consideran errores; todos estos casos se procesan con el método `PaywallViewDidFinishPurchase`. 1. Elimina el procesamiento del evento de compra cancelada. 2. Actualiza el manejo del evento de compra exitosa de la siguiente manera: ```diff showLineNumbers - public void OnFinishPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Profile profile - ) { } + public void PaywallViewDidFinishPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyPurchaseResult purchasedResult + ) { } ``` 3. Actualiza el manejo de acciones: ```diff showLineNumbers - public void OnPerformAction( - AdaptyUI.View view, - AdaptyUI.Action action - ) { + public void PaywallViewDidPerformAction( + AdaptyUIView view, + AdaptyUIUserAction action + ) { switch (action.Type) { - case AdaptyUI.ActionType.Close: + case AdaptyUIUserActionType.Close: view.Dismiss(null); break; - case AdaptyUI.ActionType.OpenUrl: + case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if (urlString != null { Application.OpenURL(urlString); } default: // handle other events break; } } ``` 4. Actualiza el manejo del inicio de compra: ```diff showLineNumbers - public void OnSelectProduct( - AdaptyUI.View view, - Adapty.PaywallProduct product - ) { } + public void PaywallViewDidSelectProduct( + AdaptyUIView view, + string productId + ) { } ``` 5. Actualiza el manejo de compra fallida: ```diff showLineNumbers - public void OnFailPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Error error - ) { } + public void PaywallViewDidFailPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyError error + ) { } ``` 6. Actualiza el manejo del evento de restauración exitosa: ```diff showLineNumbers - public void OnFailRestore( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRestore( + AdaptyUIView view, + AdaptyError error + ) { } ``` Consulta el ejemplo de código completo en la página [Manejar eventos del paywall](unity-handling-events). ## Actualizar el manejo de errores del paywall del Paywall Builder \{#update-handling-of-paywall-builder-paywall-errors\} El manejo de errores también ha cambiado; actualiza tu código según las indicaciones a continuación. 1. Actualiza el manejo de errores de carga de productos: ```diff showLineNumbers - public void OnFailLoadingProducts( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailLoadingProducts( + AdaptyUIView view, + AdaptyError error + ) { } ``` 2. Actualiza el manejo de errores de renderizado: ```diff showLineNumbers - public void OnFailRendering( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRendering( + AdaptyUIView view, + AdaptyError error + ) { } ``` ## Actualizar la configuración del SDK de integraciones de terceros \{#update-third-party-integration-sdk-configuration\} A partir de Adapty Unity SDK 3.3.0, hemos actualizado la API pública del método `updateAttribution`. Anteriormente, aceptaba un diccionario `[AnyHashable: Any]`, lo que permitía pasar objetos de atribución directamente desde varios servicios. Ahora requiere un `[String: any Sendable]`, por lo que tendrás que convertir los objetos de atribución antes de pasarlos. Para garantizar que las integraciones funcionen correctamente con Adapty Unity SDK 3.3.0 y versiones posteriores, actualiza las configuraciones de tu SDK para las siguientes integraciones tal como se describe en las secciones a continuación. ### Adjust Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers - using static AdaptySDK.Adapty; using AdaptySDK; Adjust.GetAdid((adid) => { - Adjust.GetAttribution((attribution) => { - Dictionary data = new Dictionary(); - - data["network"] = attribution.Network; - data["campaign"] = attribution.Campaign; - data["adgroup"] = attribution.Adgroup; - data["creative"] = attribution.Creative; - - String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { - // handle the error - }); + if (adid != null) { + Adapty.SetIntegrationIdentifier( + "adjust_device_id", + adid, + (error) => { + // handle the error + }); } }); Adjust.GetAttribution((attribution) => { Dictionary data = new Dictionary(); data["network"] = attribution.Network; data["campaign"] = attribution.Campaign; data["adgroup"] = attribution.Adgroup; data["creative"] = attribution.Creative; String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { + Adapty.UpdateAttribution(attributionString, "adjust", (error) => { // handle the error }); }); ``` ### Amplitude Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAmplitudeUserId("YOUR_AMPLITUDE_USER_ID"); - builder.SetAmplitudeDeviceId(amplitude.getDeviceId()); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "amplitude_user_id", + "YOUR_AMPLITUDE_USER_ID", + (error) => { + // handle the error + }); + Adapty.SetIntegrationIdentifier( + "amplitude_device_id", + amplitude.getDeviceId(), + (error) => { + // handle the error + }); ``` ### AppMetrica Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var deviceId = AppMetrica.GetDeviceId(); - if (deviceId != null { - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID"); - builder.SetAppmetricaDeviceId(deviceId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); - } + var deviceId = AppMetrica.GetDeviceId(); + if (deviceId != null { + Adapty.SetIntegrationIdentifier( + "appmetrica_device_id", + deviceId, + (error) => { + // handle the error + }); + + Adapty.SetIntegrationIdentifier( + "appmetrica_profile_id", + "YOUR_ADAPTY_CUSTOMER_USER_ID", + (error) => { + // handle the error + }); + } ``` ### AppsFlyer Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers using AppsFlyerSDK; using AdaptySDK; // before SDK initialization AppsFlyer.getConversionData(this.name); // in your IAppsFlyerConversionData void onConversionDataSuccess(string conversionData) { // It's important to include the network user ID - string appsFlyerId = AppsFlyer.getAppsFlyerId(); - Adapty.UpdateAttribution(conversionData, AttributionSource.Appsflyer, appsFlyerId, (error) => { + string appsFlyerId = AppsFlyer.getAppsFlyerId(); + + Adapty.SetIntegrationIdentifier( + "appsflyer_id", + appsFlyerId, + (error) => { // handle the error }); + + Adapty.UpdateAttribution( + conversionData, + "appsflyer", + (error) => { + // handle the error + }); } ``` ### Branch Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers using AdaptySDK; - class YourBranchImplementation { - func initializeBranch() { - Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data { - Adapty.updateAttribution(data, source: .branch) - } - } - } - } + Branch.initSession(delegate(Dictionary parameters, string error) { + string attributionString = JsonUtility.ToJson(parameters); + + Adapty.UpdateAttribution( + attributionString, + "branch", + (error) => { + // handle the error + }); + }); ``` ### Firebase and Google Analytics Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Firebase and Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers // We suppose FirebaseAnalytics Unity Plugin is already installed using AdaptySDK; Firebase.Analytics .FirebaseAnalytics .GetAnalyticsInstanceIdAsync() .ContinueWithOnMainThread((task) => { if (!task.IsCompletedSuccessfully) { // handle error return; } var firebaseId = task.Result var builder = new Adapty.ProfileParameters.Builder(); - builder.SetFirebaseAppInstanceId(firebaseId); - - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error + Adapty.SetIntegrationIdentifier( + "firebase_app_instance_id", + firebaseId, + (error) => { + // handle the error }); }); ``` ### Mixpanel Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetMixpanelUserId(Mixpanel.DistinctId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### OneSignal Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con OneSignal](onesignal#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - using OneSignalSDK; - var pushUserId = OneSignal.Default.PushSubscriptionState.userId; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetOneSignalPlayerId(pushUserId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### Pushwoosh Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [Configuración del SDK para la integración con Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetPushwooshHWID(Pushwoosh.Instance.HWID); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "pushwoosh_hwid", + Pushwoosh.Instance.HWID, + (error) => { + // handle the error + }); ``` ## Actualizar la implementación del modo Observer \{#update-observer-mode-implementation\} Actualiza cómo vinculas los paywalls a las transacciones. Anteriormente, usabas el método `setVariationId` para asignar el `variationId`. Ahora puedes incluir el `variationId` directamente al registrar la transacción mediante el nuevo método `reportTransaction`. Consulta el ejemplo de código completo en [Asociar paywalls con transacciones de compra en el modo Observer](report-transactions-observer-mode-unity). ```diff showLineNumbers // every time when calling transaction.finish() - Adapty.SetVariationForTransaction("", "", (error) => { - if(error != null) { - // handle the error - return; - } - - // successful binding - }); + Adapty.ReportTransaction( + "YOUR_TRANSACTION_ID", + "PAYWALL_VARIATION_ID", // optional + (error) => { + // handle the error + }); ``` ## Actualizar la inicialización del plugin de Unity \{#update-the-unity-plugin-initialization\} A partir de Adapty Unity SDK 3.3.0, es obligatorio llamar al método `Activate` de forma explícita durante la inicialización del plugin: ```csharp showLineNumbers Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: migration-to-unity-sdk-v3 --- --- title: "Migrar Adapty Unity SDK a v. 3.0" description: "Migra al Adapty Unity SDK v3.0 para mejorar el rendimiento y acceder a nuevas funciones de monetización." --- El SDK v.3.0 de Adapty incluye soporte para el nuevo [Adapty Paywall Builder](adapty-paywall-builder), la versión actualizada de la herramienta no-code para crear paywalls de forma visual. Con su máxima flexibilidad y ricas capacidades de diseño, tus paywalls serán más efectivos y rentables. ## Proceso de actualización \{#upgrade-process\} El proceso de actualización para Unity sigue los mismos pasos que en otras plataformas: 1. Actualiza al SDK de Adapty v3.x 2. Migra tus paywalls existentes al nuevo Paywall Builder Para instrucciones de migración específicas de Unity, consulta la [guía de instalación del SDK de Unity](sdk-installation-unity) y sigue los pasos generales de migración descritos en la guía de migración principal. --- # File: unity-migration-guide --- --- title: "Guía de migración del SDK" description: "Guías de migración para el SDK de Adapty para Unity." --- ## Guías de migración \{#migration-guides\} ### [Guía de migración al SDK de Unity Adapty 3.x](unity-sdk-migration-guides) Aprende a migrar desde versiones anteriores al SDK de Unity Adapty 3.x. ## Novedades \{#whats-new\} ### Versión 3.x \{#version-3x\} - Presentación de paywall mejorada - Gestión de errores mejorada - Mejor compatibilidad con C# - Optimizaciones de rendimiento ### Versión 2.x \{#version-2x\} - Nuevas funciones de onboarding - Analíticas mejoradas - Flujo de compra mejorado - Correcciones de errores y mejoras de estabilidad ## Cambios incompatibles \{#breaking-changes\} ### Versión 3.x \{#version-3x-breaking\} - API de observer actualizada - Métodos de presentación de paywall modificados - Estructura de gestión de errores modificada ### Versión 2.x \{#version-2x-breaking\} - API de onboarding actualizada - Estructura de perfil modificada - Flujo de compra modificado ## Lista de comprobación para la migración \{#migration-checklist\} Al migrar a una nueva versión: - [ ] Revisar los cambios incompatibles - [ ] Actualizar las llamadas a la API - [ ] Probar todas las funcionalidades - [ ] Actualizar la gestión de errores - [ ] Verificar el seguimiento de analíticas - [ ] Probar en todas las plataformas --- # End of Documentation _Generated on: 2026-05-22T06:52:52.507Z_ _Successfully processed: 40/40 files_