Gérer les événements de flow et de paywall - Capacitor

Important

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 des boutons pour plus de détails.

Les flows et les paywalls créés avec le Flow Builder n’ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. En revanche, ils génèrent certains événements auxquels votre application peut réagir. Ces événements incluent les appuis 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 qui se déroulent sur l’écran du flow dans votre application mobile, implémentez la méthode view.setEventHandlers :

Important

Vous ne pouvez définir qu’un seul gestionnaire par événement : appeler setEventHandlers plusieurs fois remplacera les gestionnaires que vous fournissez, en écrasant à la fois les gestionnaires par défaut et ceux précédemment définis pour ces événements spécifiques. Les gestionnaires non définis conservent leur comportement par défaut. setEventHandlers retourne une fonction de désabonnement, et view.dismiss() supprime tous les gestionnaires.


const view = await createFlowView(flow);

const unsubscribe = await view.setEventHandlers({
  onCloseButtonPress() {
    return true; // close the flow (default behavior)
  },
  onAndroidSystemBack() {
    return true; // close the flow; by default, it stays open
  },
  onPurchaseCompleted(purchaseResult, product) {
    return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases
  },
  onPurchaseStarted(product) { /***/ },
  onPurchaseFailed(error, product) { /***/ },
  onRestoreCompleted(profile) { /***/ },
  onRestoreFailed(error) { /***/ },
  onProductSelected(productId) { /***/ },
  onError(error) { /***/ },
  onLoadingProductsFailed(error) { /***/ },
  onUrlPress(url, openIn) {
    adapty.openWebUrl({ url, openIn }).catch(console.warn); // same as the SDK default
    return false; // keep the flow open
  },
  onAppeared(appearedView) { /***/ },
  onDisappeared() { /***/ },
  onWebPaymentNavigationFinished() { /***/ },
});
Exemples d’événements (Cliquez pour développer)

Les exemples ci-dessous montrent les propriétés disponibles dans chaque gestionnaire, avec des valeurs illustratives en commentaires.

// onUrlPress
url;    // 'https://example.com/terms'
openIn; // 'browser_in_app' or 'browser_out_app'

// onCustomAction
actionId; // 'login'

// onProductSelected
productId; // 'premium_monthly'

// onAppeared
appearedView.id;          // '3f8a1c7e-9b24-4d51-8e30-6c5b2a9f1d47'
appearedView.placementId; // 'onboarding_paywall'
appearedView.variationId; // 'd21c4b6a-57e8-4f39-b0a2-8c7e13f5d94b'
appearedView.locale;      // 'es'

// onPurchaseStarted, onPurchaseCompleted, onPurchaseFailed
product.vendorProductId;        // 'premium_monthly'
product.localizedTitle;         // 'Premium Monthly'
product.localizedDescription;   // 'Premium subscription for 1 month'
product.price?.amount;          // 9.99
product.price?.currencyCode;    // 'USD'
product.price?.localizedString; // '$9.99'

// onPurchaseCompleted
purchaseResult.type; // 'success', 'pending', or 'user_cancelled'
if (purchaseResult.type === 'success') {
  purchaseResult.profile.accessLevels['premium']?.isActive; // true
}

// onRestoreCompleted
profile.accessLevels['premium']?.isActive; // true

// onPurchaseFailed, onRestoreFailed, onError, onLoadingProductsFailed
error.message; // 'Purchase failed due to insufficient funds'

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

Les gestionnaires d’événements retournent un booléen. Si true est retourné, 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 concernée dans le navigateur natif via adapty.openWebUrl, en respectant l’option Open in définie dans le builder, et laisse le flow ouvert.
  • onAndroidSystemBack : laisse le flow ouvert lorsque le bouton Back est pressé. Retournez true pour le fermer.
  • onPurchaseCompleted : laisse le flow ouvert après qu’un achat est finalisé. Retournez true pour le fermer.
  • onRestoreCompleted : laisse le flow ouvert après une restauration réussie. Retournez true pour le fermer.
  • onError : ferme le flow si son rendu échoue.

Gestionnaires d’événements

Gestionnaire d’événementDescription
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.
onAndroidSystemBackDéclenché lorsqu’un utilisateur appuie sur le bouton système Retour d’Android. Le flow reste ouvert par défaut ; retournez true pour le fermer.
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, 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, problèmes réseau, échecs de vérification de transaction). Non déclenché pour les annulations ou les paiements en attente, qui déclenchent onPurchaseCompleted à la place.
onRestoreStartedDéclenché lorsqu’un utilisateur lance un processus de restauration d’achats.
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 AdaptyError.
onProductSelectedDéclenché lorsqu’un produit du flow est sélectionné, vous permettant de suivre ce que l’utilisateur choisit avant l’achat.
onErrorDé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, merci de 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.
onAppearedDéclenché lorsque le flow s’affiche à l’utilisateur, et fournit la vue apparue — voir L’argument view. 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é.
onDisappearedDé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 ait réussi ou échoué.
onRequestAppReviewRéservé aux demandes d’avis applicatif depuis un flow. Les flows ne déclenchent pas encore de demandes d’avis, vous n’avez donc pas besoin de l’implémenter.
onAnalyticsDéclenché lorsqu’un flow signale un événement analytique, comme une vue d’écran. Voir Événements analytiques ci-dessous.
onRequestPermissionRéservé aux demandes d’autorisation système (comme les notifications push ou l’accès à la caméra) depuis 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 — réalisez-la vous-même, puis signalez les transactions restaurées. Voir Gérer les achats en mode observateur ci-dessous.

L’argument view

L’argument view nécessite Capacitor SDK 4.0.2-beta.1 ou une version ultérieure. Parmi tous les gestionnaires de flow, seul onAppeared reçoit une description de la vue elle-même — un objet FlowEventView avec ces champs :

ChampDescription
idL’identifiant de cette instance de vue. Il est interne au SDK et ne correspond à rien dans l’Adapty Dashboard.
placementIdLe placement pour lequel le flow a été récupéré.
variationIdLa variante vers laquelle le flow a été résolu, pour attribuer vos propres analyses à un test A/B.
localeLa localisation du flow avec laquelle la vue a été construite. Elle diffère de la locale que vous avez demandée si le flow ne dispose pas d’une telle localisation. La vue renvoyée par createFlowView indique la même valeur dans sa propriété locale. Voir Utiliser les localisations et les codes de locale.

Événements analytiques

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

Un flow envoie flow_screen_showed chaque fois qu’un utilisateur ouvre l’un de ses écrans. Adapty comptabilise ces événements dans ses propres analytics de flow et les transmet également à votre application, afin que vous puissiez reconstituer le même funnel dans vos propres analytics.

ParamètreDescription
instanceIdL’ID de l’écran que l’utilisateur a ouvert.
screen_orderLa position de l’écran dans le flow.
is_last_screentrue quand l’écran n’a nulle part où aller ensuite. Un flow avec des embranchements peut se terminer sur plusieurs écrans différents, et chacun d’eux renvoie true.

isBackendEvent et isCustomerEvent sont tous les deux true pour cet événement : Adapty continue de le comptabiliser, et votre application le reçoit également.

Consultez Suivre les vues d’écrans de flow pour savoir comment les utiliser.

Gérer les achats en mode observateur

Si vous avez activé le SDK en mode observateur (observerMode: true) et présentez un flow rendu par Adapty, le SDK n’effectue pas les achats à votre place. Quand un utilisateur appuie sur le bouton d’achat ou de restauration, le SDK appelle onObserverPurchaseInitiated ou onObserverRestoreInitiated à la place, afin que vous puissiez réaliser l’achat ou la restauration avec votre propre code. Consultez Présenter des flows en mode observateur pour la configuration complète.

Important

Ce guide couvre la gestion des événements liés aux achats, restaurations, sélection de produits et affichage 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 des boutons pour plus de détails.

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 incluent des appuis 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 sur le paywall. Découvrez ci-dessous comment réagir à ces événements.

Pour contrôler ou surveiller les processus qui se déroulent sur l’écran du paywall dans votre application mobile, implémentez la méthode view.setEventHandlers :


const view = await createPaywallView(paywall);

const unsubscribe = view.setEventHandlers({
  onCloseButtonPress() {
    console.log('User closed paywall');
    return true; // Allow the paywall to close
  },
  onAndroidSystemBack() {
    console.log('User pressed back button');
    return true; // Allow the paywall to close
  }, 
  onAppeared() {
    console.log('Paywall appeared');
    return false; // Don't close the paywall
  }, 
  onDisappeared() {
    console.log('Paywall disappeared');
  },
  onPurchaseCompleted(purchaseResult, product) {
    console.log('Purchase completed:', purchaseResult);
    return purchaseResult.type !== 'user_cancelled'; // Close if not cancelled
  },
  onPurchaseStarted(product) {
    console.log('Purchase started:', product);
    return false; // Don't close the paywall
  },
  onPurchaseFailed(error, product) {
    console.error('Purchase failed:', error);
    return false; // Don't close the paywall
  },
  onRestoreCompleted(profile) {
    console.log('Restore completed:', profile);
    return true; // Close the paywall after successful restore
  },
  onRestoreFailed(error) {
    console.error('Restore failed:', error);
    return false; // Don't close the paywall
  },
  onProductSelected(productId) {
    console.log('Product selected:', productId);
    return false; // Don't close the paywall
  },
  onRenderingFailed(error) {
    console.error('Rendering failed:', error);
    return false; // Don't close the paywall
  },
  onLoadingProductsFailed(error) {
    console.error('Loading products failed:', error);
    return false; // Don't close the paywall
  },
  onUrlPress(url) {
    window.open(url, '_blank');
    return false; // Don't close the paywall
  },
});
Exemples d’événements (cliquez pour développer)
// onCloseButtonPress
{
  "event": "close_button_press"
}

// onAndroidSystemBack
{
  "event": "android_system_back"
}

// onAppeared
{
  "event": "paywall_shown"
}

// onDisappeared
{
  "event": "paywall_closed"
}

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

// onCustomAction
{
  "event": "custom_action",
  "actionId": "login"
}

// onProductSelected
{
  "event": "product_selected",
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "event": "purchase_started",
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

// onPurchaseCompleted - Success
{
  "event": "purchase_completed",
  "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",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

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

// onPurchaseFailed
{
  "event": "purchase_failed",
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  }
}

// onRestoreCompleted
{
  "event": "restore_completed",
  "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
{
  "event": "restore_failed",
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

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

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

Vous pouvez enregistrer uniquement les gestionnaires d’événements dont vous avez besoin, et ignorer ceux qui ne vous sont pas utiles. Les écouteurs d’événements inutilisés ne seront alors pas créés. Aucun gestionnaire d’événements 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 remplacer si nécessaire :

  • onCloseButtonPress : ferme le paywall lorsque le bouton de fermeture est pressé.
  • onAndroidSystemBack : ferme le paywall lorsque le bouton Back est pressé.
  • onRestoreCompleted : ferme le paywall après une restauration réussie.
  • onPurchaseCompleted : ferme le paywall sauf si l’utilisateur a annulé.
  • onRenderingFailed : ferme le paywall en cas d’échec de son rendu.
  • onUrlPress : ouvre les URLs dans le navigateur système et maintient le paywall ouvert.

Gestionnaires d’événements

Gestionnaire d’événementDescription
onCustomActionInvoqué lorsqu’un utilisateur effectue une action personnalisée, par exemple en cliquant sur un bouton personnalisé.
onUrlPressInvoqué lorsqu’un utilisateur clique sur une URL dans votre paywall.
onAndroidSystemBackInvoqué lorsqu’un utilisateur appuie sur le bouton système Android Back.
onCloseButtonPressInvoqué 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.
onPurchaseCompletedInvoqué 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 (par exemple, approbation parentale requise) déclenchent cet événement, pas onPurchaseFailed.
onPurchaseStartedInvoqué lorsqu’un utilisateur appuie sur le bouton d’action « Acheter » pour lancer le processus d’achat.
onPurchaseCancelledInvoqué lorsqu’un utilisateur lance le processus d’achat et l’interrompt manuellement (annule la boîte de dialogue de paiement).
onPurchaseFailedInvoqué lorsqu’un achat échoue en raison d’erreurs (par exemple, restrictions de paiement, produits invalides, pannes réseau, échecs de vérification des transactions). Non invoqué pour les annulations par l’utilisateur ou les paiements en attente, qui déclenchent onPurchaseCompleted à la place.
onRestoreStartedInvoqué lorsqu’un utilisateur lance un processus de restauration des achats.
onRestoreCompletedInvoqué 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 de l’abonnement pour savoir comment le vérifier.
onRestoreFailedInvoqué lorsque le processus de restauration échoue et fournit AdaptyError.
onProductSelectedInvoqué lorsqu’un produit du paywall est sélectionné, ce qui vous permet de surveiller ce que l’utilisateur sélectionne avant l’achat.
onAppearedInvoqué lorsque la vue du paywall apparaît à l’écran. Sur iOS, également invoqué 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é.
onDisappearedInvoqué lorsque la vue du paywall disparaît de l’écran. Sur iOS, également invoqué lorsqu’un paywall web ouvert depuis un paywall dans un navigateur intégré disparaît de l’écran.
onRenderingFailedInvoqué lorsqu’une erreur survient pendant le rendu de la vue et fournit AdaptyError. Ces erreurs ne devraient pas se produire, donc si vous en rencontrez une, merci de nous le signaler.
onLoadingProductsFailedInvoqué 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.