Gestionar eventos de flow y paywall - React Native

Important

Esta guía cubre el manejo de eventos para compras, restauraciones, selección de productos y renderizado de flows. También puedes configurar el manejo de botones (cerrar el flow, abrir enlaces, acciones personalizadas, etc.). Consulta nuestra guía sobre el manejo de acciones de botones para más detalles.

Los flows y paywalls creados en el Flow & Paywall Builder no necesitan código adicional para realizar y restaurar compras. Sin embargo, generan ciertos eventos a los que tu app 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 flow. A continuación aprende cómo responder a estos eventos.

Para controlar o monitorear los procesos que ocurren en la pantalla del flow dentro de tu app, implementa manejadores de eventos:

Ejemplos de eventos (Haz clic para expandir)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "purchaseResult": {
    "type": "success",
    "profile": {
      "accessLevels": {
        "premium": {
          "id": "premium",
          "isActive": true,
          "expiresAt": "2024-02-15T10:30:00Z"
        }
      }
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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"
      }
    ]
  }
}

// onRestoreFailed
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onError
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render flow interface",
    "details": {
      "underlyingError": "Invalid flow configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onAppeared
{
  "view": {
    "id": "3f8a1c7e-9b24-4d51-8e30-6c5b2a9f1d47",
    "placementId": "onboarding_paywall",
    "variationId": "d21c4b6a-57e8-4f39-b0a2-8c7e13f5d94b",
    "locale": "es"
  }
}

// onDisappeared
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

Puedes registrar solo los manejadores de eventos que necesites y omitir los que no uses. De este modo, no se crearán listeners de eventos innecesarios. No hay manejadores de eventos obligatorios.

Los manejadores de eventos devuelven un booleano. Si se devuelve true, el proceso de visualización se considera completado, por lo que la pantalla del flow se cierra y se eliminan los listeners de eventos para esa vista.

Algunos manejadores de eventos tienen un comportamiento predeterminado que puedes sobreescribir si es necesario:

  • onCloseButtonPress: cierra el flow cuando se pulsa el botón de cierre.
  • onUrlPress: abre la URL pulsada y mantiene el flow abierto.
  • onAndroidSystemBack (solo para presentación modal): mantiene el flow abierto cuando se pulsa el botón Back. Devuelve true para cerrarlo.
  • onRestoreCompleted: mantiene el flow abierto tras una restauración exitosa. Devuelve true para cerrarlo.
  • onPurchaseCompleted: mantiene el flow abierto tras completarse una compra. Devuelve true para cerrarlo.
  • onError: cierra el flow si falla su renderizado.

Controladores de eventos

Manejador de eventosDescripción
onCustomActionSe invoca cuando el usuario realiza una acción personalizada, p. ej., hace clic en un botón personalizado.
onUrlPressSe invoca cuando el usuario hace clic en una URL dentro de tu flow.
onAndroidSystemBackSolo en presentación modal: se invoca cuando el usuario toca el botón Back del sistema Android.
onCloseButtonPressSe invoca cuando el botón de cierre está visible y el usuario lo toca. Se recomienda cerrar la pantalla del flow en este manejador.
onPurchaseCompletedSe invoca cuando la compra finaliza, ya sea exitosa, cancelada por el usuario o pendiente de aprobación. En caso de compra exitosa, proporciona un AdaptyProfile actualizado. Las cancelaciones del usuario y los pagos pendientes (p. ej., aprobación parental requerida) desencadenan este evento, no onPurchaseFailed.
onPurchaseStartedSe invoca cuando el usuario toca el botón de acción “Comprar” para iniciar el proceso de compra.
onPurchaseFailedSe invoca cuando una compra falla debido a errores (p. ej., restricciones de pago, productos no válidos, fallos de red, errores de verificación de transacciones). No se invoca ante cancelaciones del usuario ni pagos pendientes, que desencadenan onPurchaseCompleted en su lugar.
onRestoreStartedSe invoca cuando el usuario inicia un proceso de restauración de compras.
onRestoreCompletedSe invoca cuando la restauración de compras se realiza correctamente y proporciona un AdaptyProfile actualizado. Se recomienda cerrar la pantalla si el usuario tiene el accessLevel requerido. Consulta el tema Estado de suscripción para saber cómo comprobarlo.
onRestoreFailedSe invoca cuando el proceso de restauración falla y proporciona AdaptyError.
onProductSelectedSe invoca cuando se selecciona cualquier producto en la vista del flow, lo que permite monitorizar qué elige el usuario antes de la compra.
onErrorSe invoca cuando ocurre un error durante el renderizado de la vista y proporciona AdaptyError. Estos errores no deberían ocurrir; si te encuentras con uno, comunícanoslo.
onLoadingProductsFailedSe invoca cuando la carga de productos falla y proporciona AdaptyError. Si no has establecido prefetchProducts: true al crear la vista, AdaptyUI recuperará los objetos necesarios del servidor por sí mismo.
onAppearedSe invoca cuando el flow se muestra al usuario y proporciona el view que apareció — consulta El argumento view. En iOS, también se invoca cuando el usuario toca el botón de paywall web dentro de un flow y se abre un paywall web en un navegador in-app.
onDisappearedSolo en presentación modal: se invoca cuando el usuario cierra el flow. En iOS, también se invoca cuando un paywall web abierto desde un flow en un navegador in-app desaparece de la pantalla.
onWebPaymentNavigationFinishedSe invoca tras intentar abrir un paywall web para realizar una compra, independientemente de si se completó con éxito o no.
onAnalyticsSe invoca cuando un flow reporta un evento de analítica, como una vista de pantalla. Consulta Eventos de analítica más abajo.
onRequestAppReviewReservado para solicitudes de valoración de la app desde un flow. Los flows aún no desencadenan solicitudes de valoración, por lo que no es necesario implementarlo.
onRequestPermissionReservado para solicitudes de permisos del sistema (como notificaciones push o acceso a la cámara) desde un flow. Los flows aún no desencadenan solicitudes de permisos, por lo que no es necesario implementarlo.
onObserverPurchaseInitiatedSolo en modo observador: se invoca cuando el usuario toca el botón de compra en un flow. Adapty no realiza la compra — efectúala con tu propio código de compra y luego reporta la transacción a Adapty. Consulta Gestionar compras en modo observador más abajo.
onObserverRestoreInitiatedSolo en modo observador: se invoca cuando el usuario toca el botón de restauración en un flow. Adapty no realiza la restauración — hazlo tú mismo y luego reporta las transacciones restauradas. Consulta Gestionar compras en modo observador más abajo.

El argumento view

El argumento view requiere React Native SDK 4.0.3 o posterior. De todos los manejadores de flow, solo onAppeared recibe una descripción de la propia vista: un objeto FlowEventView con estos campos:

CampoDescripción
idEl identificador de esta instancia de vista. Es interno al SDK y no corresponde a ningún elemento del Adapty Dashboard.
placementIdEl placement para el que se obtuvo el flow.
variationIdLa variante a la que se resolvió el flow, para atribuir tus propios análisis a una prueba A/B.
localeLa localización del flow con la que se construyó la vista. Puede diferir de la que solicitaste si el flow no tiene esa localización. Consúltala para alinear el resto de tu pantalla con el idioma en que se renderizó el flow. Consulta Usar localizaciones y códigos de idioma.

Eventos de analítica

const unsubscribe = view.setEventHandlers({
  onAnalytics(name, params) {
    return false; // keep the flow open
  },
});

Un flow reporta flow_screen_showed cada vez que un usuario abre una de sus pantallas. Adapty contabiliza estos eventos en sus propios análisis de flows y también los envía a tu aplicación, para que puedas construir el mismo embudo en tus propias herramientas de análisis.

ParámetroDescripción
instanceIdEl ID de la pantalla que el usuario abrió.
screen_orderLa posición de la pantalla en el flow.
is_last_screentrue cuando la pantalla no tiene a dónde seguir. Un flow con ramificaciones puede terminar en varias pantallas distintas, y cada una reporta true.

Tanto isBackendEvent como isCustomerEvent son true en este evento: Adapty sigue contabilizándolo y tu aplicación también lo recibe.

Consulta Registrar vistas de pantallas del flow para saber qué hacer con ellos.

Un flow también informa de los valores que los usuarios escriben y seleccionan. Consulta Procesar datos de flows para leerlos.

Gestionar compras en modo observador

Si activaste el SDK en modo observador (observerMode: true) y presentas un flow renderizado por Adapty, el SDK no realiza las compras por ti. Cuando el usuario pulsa el botón de compra o restauración, el SDK invoca onObserverPurchaseInitiated o onObserverRestoreInitiated en su lugar. Realiza la compra o restauración con tu propio código, controla el indicador de carga del flow con los callbacks proporcionados y, después, reporta la transacción a Adapty.

const unsubscribe = view.setEventHandlers({
  onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) {
    onStartPurchase(); // show the flow's loading indicator
    myPurchaseApi(product.vendorProductId)
      .then((transactionId) => adapty.reportTransaction(transactionId))
      .finally(() => onFinishPurchase()); // hide the loading indicator
    return false; // keep the flow open; dismiss it yourself after success
  },
  onObserverRestoreInitiated(onStartRestore, onFinishRestore) {
    onStartRestore();
    myRestoreApi()
      .finally(() => onFinishRestore());
    return false;
  },
});
Important

Esta guía cubre el manejo de eventos para compras, restauraciones, selección de productos y renderizado de paywalls. También debes implementar el manejo de botones (cerrar el paywall, abrir enlaces, etc.). Consulta nuestra guía sobre cómo manejar las acciones de los botones para más detalles.

Os paywalls configurados con el Paywall Builder no necesitan código adicional para realizar y restaurar compras. Sin embargo, generan algunos eventos a los que tu app puede responder. Esos 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. Aprende a responder a estos eventos a continuación.

Warning

Esta guía cubre únicamente paywalls creados con el builder antiguo, que requieren el SDK de Adapty v3.0 o posterior.

Para controlar o monitorear los procesos que ocurren en la pantalla del paywall dentro de tu app móvil, implementa manejadores de eventos:

Ejemplos de eventos (Haz clic para expandir)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "purchaseResult": {
    "type": "success",
    "profile": {
      "accessLevels": {
        "premium": {
          "id": "premium",
          "isActive": true,
          "expiresAt": "2024-02-15T10:30:00Z"
        }
      }
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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"
      }
    ]
  }
}

// onRestoreFailed
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onRenderingFailed
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render paywall interface",
    "details": {
      "underlyingError": "Invalid paywall configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onPaywallShown
{
  //Record the event
}

// onPaywallClosed
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

Puedes registrar solo los manejadores de eventos que necesites y omitir los que no uses. Así no se crearán listeners innecesarios. No hay ningún manejador de eventos obligatorio.

Los manejadores de eventos devuelven un booleano. Si se devuelve true, el proceso de visualización se considera completado, por lo que la pantalla del paywall se cierra y se eliminan los listeners de eventos para esa vista.

Algunos manejadores de eventos tienen un comportamiento predeterminado que puedes reemplazar si lo necesitas:

  • onCloseButtonPress: cierra el paywall cuando se pulsa el botón de cerrar.
  • onUrlPress: abre la URL pulsada y mantiene el paywall abierto.
  • onAndroidSystemBack (solo para presentación modal): cierra el paywall cuando se pulsa el botón Back.
  • onRestoreCompleted: cierra el paywall tras una restauración exitosa.
  • onPurchaseCompleted: cierra el paywall a menos que el usuario haya cancelado.
  • onRenderingFailed: cierra el paywall si falla su renderizado.

Controladores de eventos

Manejador de eventosDescripción
onCustomActionSe invoca cuando el usuario realiza una acción personalizada, por ejemplo, hace clic en un botón personalizado.
onUrlPressSe invoca cuando el usuario hace clic en una URL de tu paywall.
onAndroidSystemBackSolo en presentación modal: se invoca cuando el usuario pulsa el botón de sistema Back de Android.
onCloseButtonPressSe invoca cuando el botón de cierre está visible y el usuario lo pulsa. Se recomienda cerrar la pantalla del paywall en este manejador.
onPurchaseCompletedSe invoca cuando la compra finaliza, ya sea con éxito, cancelada por el usuario o pendiente de aprobación. En caso de compra exitosa, proporciona un AdaptyProfile actualizado. Las cancelaciones del usuario y los pagos pendientes (p. ej., se requiere aprobación parental) disparan este evento, no onPurchaseFailed.
onPurchaseStartedSe invoca cuando el usuario pulsa el botón de acción “Comprar” para iniciar el proceso de compra.
onPurchaseFailedSe invoca cuando una compra falla por errores (p. ej., restricciones de pago, productos no válidos, fallos de red, errores de verificación de transacción). No se invoca por cancelaciones del usuario ni pagos pendientes, que disparan onPurchaseCompleted en su lugar.
onRestoreStartedSe invoca cuando el usuario inicia un proceso de restauración de compras.
onRestoreCompletedSe invoca cuando la restauración de compras tiene éxito y proporciona un AdaptyProfile actualizado. Se recomienda cerrar la pantalla si el usuario tiene el accessLevel requerido. Consulta el tema Estado de suscripción para saber cómo comprobarlo.
onRestoreFailedSe invoca cuando el proceso de restauración falla y proporciona AdaptyError.
onProductSelectedSe invoca cuando se selecciona cualquier producto en la vista del paywall, lo que permite monitorizar qué elige el usuario antes de la compra.
onRenderingFailedSe invoca cuando ocurre un error durante el renderizado de la vista y proporciona AdaptyError. Estos errores no deberían ocurrir; si te encuentras con uno, por favor comunícanoslo.
onLoadingProductsFailedSe invoca cuando la carga de productos falla y proporciona AdaptyError. Si no has configurado prefetchProducts: true al crear la vista, AdaptyUI recuperará los objetos necesarios del servidor por sí mismo.
onPaywallShownSe invoca cuando el paywall se muestra al usuario. En iOS, también se invoca cuando el usuario pulsa el botón de web paywall dentro de un paywall y el web paywall se abre en un navegador in-app.
onPaywallClosedSolo en presentación modal: se invoca cuando el usuario cierra el paywall. En iOS, también se invoca cuando un web paywall abierto desde un paywall en un navegador in-app desaparece de la pantalla.
onWebPaymentNavigationFinishedSe invoca tras intentar abrir un web paywall para realizar una compra, tanto si tiene éxito como si falla.