Gérer les événements de flow et de paywall - React Native

Ce guide couvre la gestion des événements pour les achats, les restaurations, la sélection de produits et le rendu des flows. Vous pouvez également configurer la gestion des boutons (fermeture du flow, ouverture de liens, actions personnalisées, etc.). Consultez notre guide sur la gestion des actions de boutons pour plus de détails.

Les flows et paywalls créés avec le Flow Builder n’ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut répondre. Ces événements incluent des pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats effectuées dans le flow. Découvrez ci-dessous comment répondre à ces événements.

Pour contrôler ou surveiller les processus se déroulant sur l’écran du flow dans votre application mobile, implémentez des gestionnaires d’événements :

Exemples d’événements (Cliquez pour agrandir)
// 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
{
  //Record the event
}

// onDisappeared
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

Vous pouvez enregistrer uniquement les gestionnaires d’événements dont vous avez besoin et ignorer les autres. Ainsi, aucun écouteur d’événement inutile ne sera créé. Aucun gestionnaire d’événement n’est obligatoire.

Les gestionnaires d’événements renvoient un booléen. Si true est renvoyé, le processus d’affichage est considéré comme terminé : l’écran du flow se ferme et les écouteurs d’événements associés à cette vue sont supprimés.

Certains gestionnaires d’événements ont un comportement par défaut que vous pouvez remplacer si nécessaire :

  • onCloseButtonPress : ferme le flow lorsque le bouton de fermeture est pressé.
  • onUrlPress : ouvre l’URL tapée et maintient le flow ouvert.
  • onAndroidSystemBack (uniquement pour la présentation modale) : maintient le flow ouvert lorsque le bouton Back est pressé. Retournez true pour le fermer.
  • onRestoreCompleted : maintient le flow ouvert après une restauration réussie. Retournez true pour le fermer.
  • onPurchaseCompleted : maintient le flow ouvert après la finalisation d’un achat. Retournez true pour le fermer.
  • onError : ferme le flow si son rendu échoue.

Gestionnaires d’événements

Gestionnaire d’événementsDescription
onCustomActionDéclenché lorsqu’un utilisateur effectue une action personnalisée, par exemple en cliquant sur un bouton personnalisé.
onUrlPressDéclenché lorsqu’un utilisateur clique sur une URL dans votre flow.
onAndroidSystemBackPrésentation modale uniquement : déclenché lorsqu’un utilisateur appuie sur le bouton système Android Retour.
onCloseButtonPressDéclenché lorsque le bouton de fermeture est visible et qu’un utilisateur appuie dessus. Il est recommandé de fermer l’écran du flow dans ce gestionnaire.
onPurchaseCompletedDéclenché lorsque l’achat se termine, qu’il soit réussi, annulé par l’utilisateur ou en attente d’approbation. En cas d’achat réussi, il fournit un AdaptyProfile mis à jour. Les annulations et les paiements en attente (par exemple, approbation parentale requise) déclenchent cet événement, et non onPurchaseFailed.
onPurchaseStartedDéclenché lorsqu’un utilisateur appuie sur le bouton d’action « Acheter » pour démarrer le processus d’achat.
onPurchaseFailedDéclenché lorsqu’un achat échoue en raison d’erreurs (par exemple, restrictions de paiement, produits invalides, échecs réseau, échecs de vérification de transaction). Non déclenché pour les annulations utilisateur ou les paiements en attente, qui déclenchent onPurchaseCompleted à la place.
onRestoreStartedDéclenché lorsqu’un utilisateur lance un processus de restauration d’achat.
onRestoreCompletedDéclenché lorsque la restauration des achats réussit et fournit un AdaptyProfile mis à jour. Il est recommandé de fermer l’écran si l’utilisateur dispose du accessLevel requis. Consultez la rubrique Statut de l’abonnement pour savoir comment le vérifier.
onRestoreFailedDéclenché lorsque le processus de restauration échoue et fournit une AdaptyError.
onProductSelectedDéclenché lorsqu’un produit de la vue du flow est sélectionné, vous permettant de surveiller ce que l’utilisateur sélectionne avant l’achat.
onErrorDéclenché lorsqu’une erreur survient pendant le rendu de la vue et fournit une AdaptyError. Ces erreurs ne devraient pas se produire ; si vous en rencontrez une, merci de nous en informer.
onLoadingProductsFailedDéclenché lorsque le chargement des produits échoue et fournit une AdaptyError. Si vous n’avez pas défini prefetchProducts: true lors de la création de la vue, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur.
onAppearedDéclenché lorsque le flow est affiché à l’utilisateur. Sur iOS, également déclenché lorsqu’un utilisateur appuie sur le bouton de paywall web dans un flow et qu’un paywall web s’ouvre dans un navigateur intégré à l’application.
onDisappearedPrésentation modale uniquement : déclenché lorsque le flow est fermé par l’utilisateur. Sur iOS, également déclenché lorsqu’un paywall web ouvert depuis un flow dans un navigateur intégré disparaît de l’écran.
onWebPaymentNavigationFinishedDéclenché après une tentative d’ouverture d’un paywall web pour un achat, qu’elle soit réussie ou non.
onAnalyticsRéservé aux événements analytiques personnalisés provenant d’un flow. Les flows n’émettent pas encore ces événements vers votre code, vous n’avez donc pas besoin de l’implémenter.
onRequestAppReviewRéservé aux demandes d’avis sur l’application provenant d’un flow. Les flows ne déclenchent pas encore de demandes d’avis, vous n’avez donc pas besoin de l’implémenter.
onRequestPermissionRéservé aux demandes d’autorisation système (telles que les notifications push ou l’accès à la caméra) provenant d’un flow. Les flows ne déclenchent pas encore de demandes d’autorisation, vous n’avez donc pas besoin de l’implémenter.
onObserverPurchaseInitiatedMode observateur uniquement : déclenché lorsqu’un utilisateur appuie sur le bouton d’achat dans un flow. Adapty n’effectue pas l’achat — réalisez-le avec votre propre code d’achat, puis signalez la transaction à Adapty. Voir Gérer les achats en mode observateur ci-dessous.
onObserverRestoreInitiatedMode observateur uniquement : déclenché lorsqu’un utilisateur appuie sur le bouton de restauration dans un flow. Adapty n’effectue pas la restauration — faites-le vous-même, puis signalez les transactions restaurées. Voir Gérer les achats en mode observateur ci-dessous.

Gérer les achats en mode observateur

Si vous avez activé le SDK en mode observateur (observerMode: true) et que vous affichez un flow rendu par Adapty, le SDK n’effectue pas les achats à votre place. Lorsqu’un utilisateur appuie sur le bouton d’achat ou de restauration, le SDK appelle onObserverPurchaseInitiated ou onObserverRestoreInitiated à la place. Effectuez l’achat ou la restauration avec votre propre code, pilotez l’indicateur de chargement du flow avec les callbacks fournis, puis signalez la transaction à Adapty ensuite.

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;
  },
});

Ce guide couvre la gestion des événements pour les achats, les restaurations, la sélection de produits et le rendu des paywalls. Vous devez également implémenter la gestion des boutons (fermeture du paywall, ouverture de liens, etc.). Consultez notre guide sur la gestion des actions de boutons pour en savoir plus.

Les paywalls configurés avec le Paywall Builder n’ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut réagir. Ces événements comprennent les appuis sur des boutons (boutons de fermeture, URL, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats effectuées sur le paywall. Découvrez comment réagir à ces événements ci-dessous.

Ce guide concerne uniquement les paywalls créés avec le nouveau Paywall Builder, qui nécessitent le SDK Adapty v3.0 ou une version ultérieure.

Pour contrôler ou surveiller les processus qui se produisent sur l’écran paywall de votre application mobile, implémentez des gestionnaires d’événements :

Exemples d’événements (Cliquer pour développer)
// 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
}

Vous pouvez enregistrer uniquement les gestionnaires d’événements dont vous avez besoin, et ignorer les autres. Dans ce cas, aucun écouteur d’événement inutile ne sera créé. Aucun gestionnaire d’événement n’est obligatoire.

Les gestionnaires d’événements renvoient un booléen. Si true est renvoyé, le processus d’affichage est considéré comme terminé : l’écran du paywall se ferme et les écouteurs d’événements associés à cette vue sont supprimés.

Certains gestionnaires d’événements ont un comportement par défaut que vous pouvez redéfinir si nécessaire :

  • onCloseButtonPress : ferme le paywall quand le bouton de fermeture est appuyé.
  • onUrlPress : ouvre l’URL touchée et garde le paywall ouvert.
  • onAndroidSystemBack (uniquement pour la présentation modale) : ferme le paywall quand le bouton Back est appuyé.
  • onRestoreCompleted : ferme le paywall après une restauration réussie.
  • onPurchaseCompleted : ferme le paywall sauf si l’utilisateur a annulé.
  • onRenderingFailed : ferme le paywall si son rendu échoue.

Gestionnaires d’événements

Gestionnaire d’événementsDescription
onCustomActionDéclenché lorsqu’un utilisateur effectue une action personnalisée, par exemple en cliquant sur un bouton personnalisé.
onUrlPressDéclenché lorsqu’un utilisateur clique sur une URL dans votre paywall.
onAndroidSystemBackPrésentation modale uniquement : déclenché lorsqu’un utilisateur appuie sur le bouton système Android Back.
onCloseButtonPressDéclenché lorsque le bouton de fermeture est visible et qu’un utilisateur appuie dessus. Il est recommandé de fermer l’écran du paywall dans ce gestionnaire.
onPurchaseCompletedDéclenché lorsque l’achat se termine, qu’il soit réussi, annulé par l’utilisateur ou en attente d’approbation. En cas d’achat réussi, il fournit un AdaptyProfile mis à jour. Les annulations par l’utilisateur et les paiements en attente (ex. : approbation parentale requise) déclenchent cet événement, pas onPurchaseFailed.
onPurchaseStartedDéclenché lorsqu’un utilisateur appuie sur le bouton d’action « Acheter » pour lancer le processus d’achat.
onPurchaseFailedDéclenché lorsqu’un achat échoue en raison d’erreurs (ex. : restrictions de paiement, produits invalides, échecs réseau, échecs de vérification de transaction). Non déclenché pour les annulations utilisateur ou les paiements en attente, qui déclenchent onPurchaseCompleted à la place.
onRestoreStartedDéclenché lorsqu’un utilisateur démarre un processus de restauration d’achat.
onRestoreCompletedDéclenché lorsque la restauration des achats réussit et fournit un AdaptyProfile mis à jour. Il est recommandé de fermer l’écran si l’utilisateur possède le accessLevel requis. Consultez la rubrique Statut d’abonnement pour savoir comment le vérifier.
onRestoreFailedDéclenché lorsque le processus de restauration échoue et fournit AdaptyError.
onProductSelectedDéclenché lorsqu’un produit du paywall est sélectionné, ce qui vous permet de suivre ce que l’utilisateur choisit avant l’achat.
onRenderingFailedDéclenché lorsqu’une erreur survient pendant le rendu de la vue et fournit AdaptyError. Ces erreurs ne devraient pas se produire ; si vous en rencontrez une, veuillez nous le signaler.
onLoadingProductsFailedDéclenché lorsque le chargement des produits échoue et fournit AdaptyError. Si vous n’avez pas défini prefetchProducts: true lors de la création de la vue, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur.
onPaywallShownDéclenché lorsque le paywall est affiché à l’utilisateur. Sur iOS, également déclenché lorsqu’un utilisateur appuie sur le bouton de paywall web dans un paywall et qu’un paywall web s’ouvre dans un navigateur intégré.
onPaywallClosedPrésentation modale uniquement : déclenché lorsque le paywall est fermé par l’utilisateur. Sur iOS, également déclenché lorsqu’un paywall web ouvert depuis un paywall dans un navigateur intégré disparaît de l’écran.
onWebPaymentNavigationFinishedDéclenché après une tentative d’ouverture d’un paywall web pour un achat, qu’elle soit réussie ou non.