Migrar el SDK de Adapty React Native a la v. 3.3

Adapty SDK 3.3.1 es una versión mayor que incluye mejoras que pueden requerir algunos pasos de migración de tu parte.

  1. Actualiza al SDK de Adapty v3.3.x.
  2. Actualiza los modelos.
  3. Elimina el método getProductsIntroductoryOfferEligibility.
  4. Actualiza el proceso de compra.
  5. Actualiza la presentación de paywalls del Paywall Builder.
  6. Revisa la implementación del temporizador definido por el desarrollador.
  7. Actualiza el manejo de eventos de compra del Paywall Builder.
  8. Actualiza el manejo de eventos de acción personalizada del Paywall Builder.
  9. Modifica el callback onProductSelected.
  10. Elimina los parámetros de integración de terceros del método updateProfile.
  11. Actualiza las configuraciones de integración para Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase y Google Analytics, Mixpanel, OneSignal y Pushwoosh.
  12. Actualiza la implementación del modo Observer.

Actualiza el SDK de Adapty React Native a 3.3.x

Antes de la versión 3.3.1, el SDK react-native-adapty era el SDK principal y obligatorio para que Adapty funcionara correctamente en tu app. El SDK @adapty/react-native-ui era opcional y solo era necesario si usabas el Paywall Builder de Adapty.

A partir de la versión 3.3.1, el SDK @adapty/react-native-ui está obsoleto y su funcionalidad se ha integrado en el SDK react-native-adapty. Para actualizar a la versión 3.3.1, sigue estos pasos:

  1. Actualiza el paquete react-native-adapty a la versión 3.3.1.
  2. Elimina el paquete @adapty/react-native-ui de las dependencias de tu proyecto.
  3. Sincroniza las dependencias de tu proyecto para aplicar los cambios.

Cambios en los modelos

Nuevos modelos

  1. AdaptySubscriptionOffer:

    export interface AdaptySubscriptionOffer {
      readonly identifier: AdaptySubscriptionOfferId;
    
      phases: AdaptyDiscountPhase[];
    
      android?: {
        offerTags?: string[];
      };
    }
  2. AdaptySubscriptionOfferId:

    export type AdaptySubscriptionOfferId =
      | { id?: string; type: 'introductory'; }
      | { id: string; type: 'promotional' | 'win_back'; };

Modelos modificados

  1. AdaptyPaywallProduct:

    • Se renombró la propiedad subscriptionDetails a subscription.

    -  subscriptionDetails?: AdaptySubscriptionDetails; 
    +  subscription?: AdaptySubscriptionDetails;
  2. AdaptySubscriptionDetails:

    • Se eliminó promotionalOffer. Ahora la oferta promocional se entrega dentro de la propiedad offer solo si está disponible. En ese caso, offer?.identifier?.type será 'promotional'.

    • Se eliminó introductoryOfferEligibility (las ofertas solo se devuelven si el usuario es elegible).

    • Se eliminó offerId. El ID de la oferta ahora se almacena en AdaptySubscriptionOffer.identifier.

    • offerTags se movió a AdaptySubscriptionOffer.android.

    -  introductoryOffers?: AdaptyDiscountPhase[];
    +  offer?: AdaptySubscriptionOffer;
    
       ios?: {
    -    promotionalOffer?: AdaptyDiscountPhase;
         subscriptionGroupIdentifier?: string;
       };
    
       android?: {
    -    offerId?: string;
         basePlanId: string;
    -    introductoryOfferEligibility: OfferEligibility;
    -    offerTags?: string[];
         renewalType?: 'prepaid' | 'autorenewable';
       };
     }
  3. AdaptyDiscountPhase:

    • El campo identifier se eliminó del modelo AdaptyDiscountPhase. El identificador de la oferta ahora se almacena en AdaptySubscriptionOffer.identifier.

    -  ios?: {
    -    readonly identifier?: string;
    -  };

Modelos eliminados

  1. AttributionSource:
    • Ahora se usa un string en los lugares donde antes se usaba AttributionSource.
  2. OfferEligibility:
    • Este modelo se ha eliminado porque ya no es necesario. Ahora, una oferta solo se devuelve si el usuario es elegible.

Elimina el método getProductsIntroductoryOfferEligibility

Antes del SDK de Adapty 3.3.1, los objetos de producto siempre incluían las ofertas, incluso si el usuario no era elegible. Esto requería verificar la elegibilidad manualmente antes de usar la oferta.

A partir de la versión 3.3.1, el objeto de producto incluye ofertas solo si el usuario es elegible. Esto simplifica el proceso, ya que puedes asumir que el usuario es elegible si hay una oferta presente.

Actualiza el proceso de compra

En versiones anteriores, las compras canceladas y pendientes se trataban como errores y devolvían los códigos 2: 'paymentCancelled' y 25: 'pendingPurchase', respectivamente.

A partir de la versión 3.3.1, las compras canceladas y pendientes se consideran resultados exitosos y deben manejarse en consecuencia:

try {
    const purchaseResult = await adapty.makePurchase(product);
    switch (purchaseResult.type) {
      case 'success':
        const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive;

        if (isSubscribed) {
          // Grant access to the paid features
        }
        break;
      case 'user_cancelled':
        // Handle the case where the user canceled the purchase
        break;
      case 'pending':
        // Handle deferred purchases (e.g., the user will pay offline with cash)
        break;
    }
} catch (error) {
    // Handle the error
}

Actualiza la presentación de paywalls del Paywall Builder

Para ver ejemplos actualizados, consulta la documentación Presentar paywalls nuevos del Paywall Builder en React Native.

- import { createPaywallView } from '@adapty/react-native-ui';
+ import { createPaywallView } from 'react-native-adapty/dist/ui';

const view = await createPaywallView(paywall);

view.registerEventHandlers(); // handle close press, etc

try {
  await view.present();
} catch (error) {
  // handle the error
}

Actualiza la implementación del temporizador definido por el desarrollador

Renombra el parámetro timerInfo a customTimers:

- let timerInfo = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
+ let customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
 //and then you can pass it to createPaywallView as follows:
- view = await createPaywallView(paywall, { timerInfo })
+ view = await createPaywallView(paywall, { customTimers })

Modifica los eventos de compra del Paywall Builder

Antes:

  • Las compras canceladas activaban el callback onPurchaseCancelled.
  • Las compras pendientes devolvían el código de error 25: 'pendingPurchase'.

Ahora:

  • Ambas se manejan mediante el callback onPurchaseCompleted.

Pasos para migrar:

  1. Elimina el callback onPurchaseCancelled.
  2. Elimina el manejo del código de error 25: 'pendingPurchase'.
  3. Actualiza el callback onPurchaseCompleted:

const view = await createPaywallView(paywall);

const unsubscribe = view.registerEventHandlers({
  // ... other optional callbacks
  onPurchaseCompleted(purchaseResult, product) {
    switch (purchaseResult.type) {
      case 'success':
        const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive;

        if (isSubscribed) {
          // Grant access to the paid features
        }
        break;
      case 'user_cancelled':
        // Handle the case where the user canceled the purchase
        break;
      case 'pending':
        // Handle deferred purchases (e.g., the user will pay offline with cash)
        break;
    }
    return purchaseResult.type !== 'user_cancelled';
  },
});

Modifica los eventos de acción personalizada del Paywall Builder

Callbacks eliminados:

  • onAction
  • onCustomEvent

Callback añadido:

  • Nuevo callback onCustomAction(actionId). Úsalo para acciones personalizadas.

Modifica el callback onProductSelected

Antes, onProductSelected requería el objeto product. Ahora requiere productId como string.

Elimina los parámetros de integración de terceros del método updateProfile

Los identificadores de integración de terceros ahora se configuran con el método setIntegrationIdentifier. El método updateProfile ya no los acepta.

Actualiza la configuración del SDK de integraciones de terceros

Para garantizar que las integraciones funcionen correctamente con el SDK de Adapty React Native 3.3.1 y versiones posteriores, actualiza las configuraciones de tu SDK para las siguientes integraciones según se describe en las secciones a continuación.

Además, si usabas AttributionSource para obtener el identificador de atribución, cambia tu código para proporcionar el identificador requerido como string.

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.

 import { Adjust, AdjustConfig } from "react-native-adjust";
 import { adapty } from "react-native-adapty";

 var adjustConfig = new AdjustConfig(appToken, environment);

 // Before submiting Adjust config...
 adjustConfig.setAttributionCallbackListener(attribution => {
   // Make sure Adapty SDK is activated at this point
   // You may want to lock this thread awaiting of `activate`
   adapty.updateAttribution(attribution, "adjust");
 });

 // ...
 Adjust.create(adjustConfig);

+ Adjust.getAdid((adid) => {
+   if (adid)
+     adapty.setIntegrationIdentifier("adjust_device_id", adid);
+ });

AirBridge

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 AirBridge.

 import Airbridge from 'airbridge-react-native-sdk';
 import { adapty } from 'react-native-adapty';

 try {
   const deviceId = await Airbridge.state.deviceUUID();

-  await adapty.updateProfile({
-    airbridgeDeviceId: deviceId,
-  });
+  await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId);
 } catch (error) {
   // handle `AdaptyError`
 }

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.

  import { adapty } from 'react-native-adapty';

 try {
-   await adapty.updateProfile({
-     amplitudeDeviceId: deviceId,
-     amplitudeUserId: userId,
-   });
+   await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId);
+   await adapty.setIntegrationIdentifier("amplitude_user_id", userId);
 } catch (error) {
   // handle `AdaptyError`
 }

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.

 import { adapty } from 'react-native-adapty';
 import AppMetrica, { DEVICE_ID_KEY, StartupParams, StartupParamsReason } from '@appmetrica/react-native-analytics';

 // ...
 const startupParamsCallback = async (
   params?: StartupParams,
   reason?: StartupParamsReason
 ) => {
   const deviceId = params?.deviceId
   if (deviceId) {
     try {
-       await adapty.updateProfile({
-         appmetricaProfileId: 'YOUR_ADAPTY_CUSTOMER_USER_ID',
-         appmetricaDeviceId: deviceId,
-       });
+       await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID');
+       await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId);
     } catch (error) {
       // handle `AdaptyError`
     }
   }
 }

 AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_KEY])

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.

 import { adapty, AttributionSource } from 'react-native-adapty';
 import appsFlyer from 'react-native-appsflyer';

 appsFlyer.onInstallConversionData(installData => {
     try {
-        const networkUserId = appsFlyer.getAppsFlyerUID();
-        adapty.updateAttribution(installData, AttributionSource.AppsFlyer, networkUserId);
+        const uid = appsFlyer.getAppsFlyerUID();
+        adapty.setIntegrationIdentifier("appsflyer_id", uid);
+        adapty.updateAttribution(installData, "appsflyer");
     } catch (error) {
         // handle the error
     }
 });

 // ...
 appsFlyer.initSdk(/*...*/);

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.

 import { adapty, AttributionSource } from 'react-native-adapty';
 import branch from 'react-native-branch';

 branch.subscribe({
   enComplete: ({
     params,
   }) => {
-    adapty.updateAttribution(params, AttributionSource.Branch);
+    adapty.updateAttribution(params, "branch");
   },
 });

Facebook Ads

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 Facebook Ads.

 import { adapty } from 'react-native-adapty';
 import { AppEventsLogger } from 'react-native-fbsdk-next';

 try {
   const anonymousId = await AppEventsLogger.getAnonymousID();

-  await adapty.updateProfile({
-    facebookAnonymousId: anonymousId,
-  });
+  await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId);
 } catch (error) {
   // handle `AdaptyError`
 }

Firebase y 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 y Google Analytics.

 import analytics from '@react-native-firebase/analytics';
 import { adapty } from 'react-native-adapty';

 try {
   const appInstanceId = await analytics().getAppInstanceId();

-   await adapty.updateProfile({
-     firebaseAppInstanceId: appInstanceId,
-   });
+   await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId);
 } catch (error) {
   // handle `AdaptyError`
 }

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.

 import { adapty } from 'react-native-adapty';
 import { Mixpanel } from 'mixpanel-react-native';

 // ...
 try {
-   await adapty.updateProfile({
-     mixpanelUserId: mixpanelUserId,
-   });
+   await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId);
 } catch (error) {
   // handle `AdaptyError`
 }

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.

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.

 import { adapty } from 'react-native-adapty';
 import Pushwoosh from 'pushwoosh-react-native-plugin';

 // ...
 try {
-  await adapty.updateProfile({
-    pushwooshHWID: hwid,
-  });
+  await adapty.setIntegrationIdentifier("pushwoosh_hwid", hwid);
 } catch (error) {
   // handle `AdaptyError`
 }

Actualiza la implementación del modo Observer

Actualiza la forma en que vinculas los paywalls a las transacciones. Antes, usabas el método setVariationId para asignar el variationId. Ahora puedes incluir el variationId directamente al registrar la transacción con el nuevo método reportTransaction. Consulta el ejemplo de código final en Asociar paywalls con transacciones de compra en el modo Observer.

No olvides registrar la transacción con el método reportTransaction. Si omites este paso, Adapty no reconocerá la transacción, no otorgará niveles de acceso, no la incluirá en los análisis ni la enviará a las integraciones. ¡Este paso es imprescindible!

Ten en cuenta que el orden de los parámetros del método reportTransaction es diferente al del método setVariationId.

  const variationId = paywall.variationId;

 try {
-    await adapty.setVariationId(variationId, transactionId);
+    await adapty.reportTransaction(transactionId, variationId);
 } catch (error) {
     // handle the `AdaptyError`
 }