# Adapty Documentation (Full Content) > Complete documentation content across all platforms. Locale: fr Generated on: 2026-08-04T15:08:26.354Z --- # ANDROID - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:25.869Z Total files: 49 --- # File: android-sdk-overview --- --- title: "Android SDK overview" description: "Découvrez le SDK Android d'Adapty et ses principales fonctionnalités." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Android.svg?style=flat&logo=android)](https://github.com/adaptyteam/AdaptySDK-Android/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le SDK Android Adapty pour vous décharger de la gestion des achats intégrés, afin que vous puissiez vous concentrer sur l'essentiel : créer des applications géniales. Voici ce que nous prenons en charge à votre place : - Gestion des achats, validation des reçus et gestion des abonnements, prêts à l'emploi - Création et test de flows et de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans configuration — cohortes, LTV, churn et analyse d'entonnoir inclus - Statut d'abonnement utilisateur toujours à jour entre les sessions et les appareils - Intégration de votre application avec des services d'attribution marketing et d'analyse en une seule ligne de code :::note Avant de plonger dans le code, vous devrez intégrer Adapty avec la Google Play Console et configurer vos produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Démarrer \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons aborder dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-android) : Ajoutez le SDK comme dépendance à votre projet et activez-le dans le code. 2. [Activer les achats via les flows](android-quickstart-paywalls) : Configurez le flux d'achat pour que les utilisateurs puissent acheter des produits. Pour créer votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](android-quickstart-manual). 3. [Vérifier le statut de l'abonnement](android-check-subscription-status) : Vérifiez automatiquement l'état d'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (facultatif)](android-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir la cohérence de leurs données entre les appareils. ### Le voir en action \{#see-it-in-action\} Vous voulez voir comment tout s'assemble ? Nous avons ce qu'il vous faut : - **Exemple d'application** : Consultez notre [exemple complet](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app) qui illustre la configuration complète ## Concepts clés \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts essentiels qui font fonctionner Adapty. La particularité de l'approche Adapty, c'est que seuls les placements sont codés en dur dans votre application. Tout le reste — produits, design des paywalls, tarification et offres — peut être géré de manière flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre application — abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Des produits regroupés avec une configuration, associés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, créée dans le Flow Builder. Adapty génère l'interface et gère l'achat à votre place. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous créez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](android-quickstart-manual). Dans le code du SDK, les deux sont récupérés via la même méthode `getFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Considérez les placements comme le « où » et le « quand » de votre stratégie de monétisation. Les placements courants incluent : - `main` - L'emplacement principal de votre paywall - `onboarding` - Affiché lors du flow d'onboarding utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits de votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque les utilisateurs achètent un produit, leur profil se voit attribuer un **niveau d'accès** que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-android --- --- title: "Installer et configurer le SDK Android" description: "Guide étape par étape pour installer le SDK Adapty sur Android pour les applications basées sur les abonnements." --- Le SDK Adapty comprend deux modules clés pour une intégration fluide dans votre application mobile : - **Core Adapty** : ce SDK essentiel est requis pour qu'Adapty fonctionne correctement dans votre application. - **AdaptyUI** : ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. AdaptyUI est automatiquement activé en même temps que le module principal. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez notre [application exemple](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app), qui illustre la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Prérequis \{#requirements\} Version SDK minimale requise : `minSdkVersion 21` :::info Adapty est compatible avec Google Play Billing Library jusqu'à la version 8.x. Par défaut, Adapty fonctionne avec Google Play Billing Library v7.0.0, mais si vous souhaitez forcer une version ultérieure, vous pouvez [ajouter la dépendance](https://developer.android.com/google/play/billing/integrate#dependency) manuellement. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} Choisissez votre méthode de gestion des dépendances : - Gradle standard : ajoutez les dépendances dans votre `build.gradle` **au niveau du module** - Si votre projet utilise des fichiers `.gradle.kts`, ajoutez les dépendances dans votre `build.gradle.kts` au niveau du module - Si vous utilisez des catalogues de versions, ajoutez les dépendances dans votre fichier `libs.versions.toml`, puis référencez-les dans `build.gradle.kts` [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Android.svg?style=flat&logo=android)](https://github.com/adaptyteam/AdaptySDK-Android/releases) ```groovy showLineNumbers dependencies { ... implementation platform('io.adapty:adapty-bom:') implementation 'io.adapty:android-sdk' // Only add this line if you plan to use Paywall Builder implementation 'io.adapty:android-ui' } ``` ```kotlin showLineNumbers dependencies { ... implementation(platform("io.adapty:adapty-bom:")) implementation("io.adapty:android-sdk") // Only add this line if you plan to use Paywall Builder: implementation("io.adapty:android-ui") } ``` ```toml showLineNumbers //libs.versions.toml [versions] .. adaptyBom = "" [libraries] .. adapty-bom = { module = "io.adapty:adapty-bom", version.ref = "adaptyBom" } adapty = { module = "io.adapty:android-sdk" } // Only add this line if you plan to use Paywall Builder: adapty-ui = { module = "io.adapty:android-ui" } //module-level build.gradle.kts dependencies { ... implementation(platform(libs.adapty.bom)) implementation(libs.adapty) // Only add this line if you plan to use Paywall Builder: implementation(libs.adapty.ui) } ``` Si la dépendance ne se résout pas, vérifiez que vous avez bien `mavenCentral()` dans vos scripts Gradle.
Les instructions pour l'ajouter Si votre projet n'a pas de `dependencyResolutionManagement` dans votre `settings.gradle`, ajoutez ce qui suit dans votre `build.gradle` de niveau racine, à la fin de la section repositories : ```groovy showLineNumbers title="top-level build.gradle" allprojects { repositories { ... mavenCentral() } } ``` Sinon, ajoutez ce qui suit dans votre `settings.gradle`, dans la section `repositories` de `dependencyResolutionManagement` : ```groovy showLineNumbers title="settings.gradle" dependencyResolutionManagement { ... repositories { ... mavenCentral() } } ```
## Activer le module Adapty du SDK Adapty \{#activate-adapty-module-of-adapty-sdk\} ### Configuration de base \{#basic-setup\} Activez le SDK Adapty dans le code de votre application. :::note Le SDK Adapty ne doit être activé qu'une seule fois dans votre application. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. ```kotlin showLineNumbers // In your Application class class MyApplication : Application() { override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") .build() ) } } ``` ```java showLineNumbers // In your Application class public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Adapty.activate( getApplicationContext(), new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .build() ); } } ``` :::important Attendez que `Adapty.activate` soit terminé avant d'appeler toute autre méthode du SDK Adapty. Consultez [Ordre d'appel dans le SDK Android](android-sdk-call-order) pour la séquence complète. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), suivez le [démarrage rapide avec Paywall Builder](android-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [démarrage rapide pour les paywalls personnalisés](android-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder), vous avez besoin du module AdaptyUI. Il est activé automatiquement lorsque vous activez le module principal ; vous n'avez rien d'autre à faire. ## Configurer Proguard \{#configure-proguard\} Avant de lancer votre application en production, ajoutez `-keep class com.adapty.** { *; }` à votre configuration Proguard. ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Niveau | Description | | :----------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | | `AdaptyLogLevel.NONE` | Rien ne sera journalisé. Valeur par défaut | | `AdaptyLogLevel.ERROR` | Seules les erreurs seront journalisées | | `AdaptyLogLevel.WARN` | Les erreurs et les messages du SDK qui ne provoquent pas d'erreurs critiques, mais méritent attention, seront journalisés. | | `AdaptyLogLevel.INFO` | Les erreurs, avertissements et divers messages d'information seront journalisés. | | `AdaptyLogLevel.VERBOSE` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera journalisée. | Vous pouvez définir le niveau de journalisation dans votre application avant de configurer Adapty. ```kotlin showLineNumbers Adapty.logLevel = AdaptyLogLevel.VERBOSE //recommended for development and the first production release ``` ```java showLineNumbers Adapty.setLogLevel(AdaptyLogLevel.VERBOSE); //recommended for development and the first production release ``` #### Rediriger les messages du système de journalisation \{#redirect-the-logging-system-messages\} Si vous avez besoin pour une raison quelconque d'envoyer les messages d'Adapty vers votre système ou de les sauvegarder dans un fichier, vous pouvez remplacer le comportement par défaut : ```kotlin showLineNumbers Adapty.setLogHandler { level, message -> //handle the log } ``` ```java showLineNumbers Adapty.setLogHandler((level, message) -> { //handle the log }); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs, sauf si vous les envoyez explicitement, mais vous pouvez mettre en œuvre des politiques de sécurité des données supplémentaires pour vous conformer aux directives du store ou du pays. #### Désactiver la collecte et le partage de l'adresse IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` à `true` pour désactiver la collecte et le partage de l'adresse IP de l'utilisateur. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales sur la protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'IP ne sont pas requises pour votre application. ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build(); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire (Ad ID) \{#disable-advertising-id-ad-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `adIdCollectionDisabled` à `true` pour désactiver la collecte de l'[identifiant publicitaire](https://support.google.com/googleplay/android-developer/answer/6048248) de l'utilisateur. La valeur par défaut est `false`. Utilisez ce paramètre pour vous conformer aux politiques du Play Store, éviter de déclencher l'invite de permission pour l'identifiant publicitaire, ou si votre application ne nécessite pas d'attribution publicitaire ni d'analyses basées sur l'Ad ID. ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withAdIdCollectionDisabled(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withAdIdCollectionDisabled(true) .build(); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire l'utilisation du réseau. Vous pouvez personnaliser les paramètres du cache en fournissant une configuration personnalisée. Utilisez `AdaptyUI.configureMediaCache` pour remplacer la taille du cache et la durée de validité par défaut. C'est optionnel — si vous n'appelez pas cette méthode, les valeurs par défaut seront utilisées (100 Mo sur disque, 7 jours de validité). ```kotlin showLineNumbers val cacheConfig = MediaCacheConfiguration.Builder() .overrideDiskStorageSizeLimit(200L * 1024 * 1024) // 200 MB .overrideDiskCacheValidityTime(3.days) .build() AdaptyUI.configureMediaCache(cacheConfig) ``` ```java showLineNumbers MediaCacheConfiguration cacheConfig = new MediaCacheConfiguration.Builder() .overrideDiskStorageSizeLimit(200L * 1024 * 1024) // 200 MB .overrideDiskCacheValidityTime(TimeInterval.days(3)) .build(); AdaptyUI.configureMediaCache(cacheConfig); ``` **Paramètres :** | Paramètre | Présence | Description | |-------------------------|-----------|--------------------------------------------------------------------------------| | diskStorageSizeLimit | optionnel | Taille totale du cache sur disque en octets. Par défaut : 100 Mo. | | diskCacheValidityTime | optionnel | Durée pendant laquelle les fichiers en cache sont considérés comme valides. Par défaut : 7 jours. | :::tip Vous pouvez vider le cache média à l'exécution avec `AdaptyUI.clearMediaCache(strategy)`, où `strategy` peut être `CLEAR_ALL` ou `CLEAR_EXPIRED_ONLY`. ::: ### Définir des identifiants de compte obscurcis \{#set-obfuscated-account-ids\} Google Play exige des identifiants de compte obscurcis dans certains cas d'usage pour renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants permettent à Google Play d'identifier les achats tout en gardant les informations des utilisateurs anonymes, ce qui est particulièrement important pour la prévention des fraudes et les analyses. Vous devrez peut-être définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations de confidentialité spécifiques. Les identifiants obscurcis permettent à Google Play de suivre les achats sans exposer les identifiants réels des utilisateurs. ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObfuscatedAccountId("YOUR_OBFUSCATED_ACCOUNT_ID") .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObfuscatedAccountId("YOUR_OBFUSCATED_ACCOUNT_ID") .build(); ``` ### Exécuter Adapty dans un processus personnalisé \{#run-adapty-in-a-custom-process\} Par défaut, Adapty ne peut s'exécuter que dans le processus principal de votre application. Si votre application utilise plusieurs processus, n'initialisez Adapty qu'une seule fois ; sinon, un comportement inattendu peut survenir. Si vous devez exécuter Adapty dans un processus différent, spécifiez-le dans votre configuration : ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withProcessName(":custom") .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withProcessName(":custom") .build(); ``` Si vous tentez d'activer Adapty dans un autre processus sans définir cette valeur, le SDK enregistrera un avertissement et ignorera l'activation. ### Activer les niveaux d'accès locaux \{#enable-local-access-levels\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont désactivés sur Android. Pour les activer, définissez `withLocalAccessLevelAllowed` à `true` : ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withLocalAccessLevelAllowed(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withLocalAccessLevelAllowed(true) .build(); ``` ## Résolution des problèmes \{#troubleshooting\} #### Règles de sauvegarde Android (configuration Auto Backup) Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules`, ou `android:allowBackup`. Symptômes d'erreur typiques : `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/sample_data_extraction_rules) is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)` Pour résoudre ce problème, vous devez : - Indiquer au fusionneur de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Fusionner les règles de sauvegarde d'Adapty et des autres SDKs dans un seul fichier XML (ou une paire de fichiers pour Android 12+). #### 1. Ajoutez l'espace de noms `tools` à votre manifeste Si ce n'est pas déjà fait, ajoutez l'espace de noms `tools` à la balise racine `` : ```xml ... ``` #### 2. Remplacez les attributs de sauvegarde dans `` Dans le `AndroidManifest.xml` de votre application, mettez à jour la balise `` pour que votre application fournisse les valeurs finales et indique au fusionneur de manifeste de remplacer les valeurs des bibliothèques : ```xml ... ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez des fichiers de règles de sauvegarde fusionnées Créez des fichiers XML dans `app/src/main/res/xml/` qui combinent les règles d'Adapty avec celles des autres SDKs. Android utilise différents formats de règles de sauvegarde selon la version du système, donc créer les deux fichiers garantit la compatibilité avec toutes les versions Android que votre application prend en charge. :::note Les exemples ci-dessous utilisent AppsFlyer comme SDK tiers d'exemple. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" ``` **Pour Android 11 et inférieur** (utilise l'ancien format de contenu de sauvegarde complète) : ```xml title="sample_backup_rules.xml" ``` Avec cette configuration : - Les exclusions de sauvegarde d'Adapty (`AdaptySDKPrefs.xml`) sont préservées. - Les exclusions des autres SDKs (par exemple, `appsflyer-data`) sont également appliquées. - Le fusionneur de manifeste utilise la configuration de votre application et n'échoue plus sur les attributs de sauvegarde conflictuels. #### Les achats échouent après le retour depuis une autre application Si l'Activity qui démarre le flux d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser de manière incorrecte lorsque l'utilisateur revient depuis Google Play, une application bancaire ou un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son traitement comme annulé. Pour que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flux d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, vérifiez que l'Activity qui démarre le flux d'achat est définie sur `standard` ou `singleTop` : ```xml ``` --- # File: android-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK Android" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez un paywall à la place — voir [Implémenter les paywalls manuellement](android-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez les flows dans votre app (comme `main`, `onboarding`, `settings`). Vous associez les flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre app. Choisissez celle qui correspond à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère l'intégralité du flow d'achat, la validation des reçus et la gestion des abonnements en coulisses. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre app, mais obtenez tout de même l'objet flow depuis Adapty pour conserver la flexibilité des offres de produits. Voir le [guide](android-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limites dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.** Si vous préférez construire l'interface du paywall vous-même, consultez [Implémenter les paywalls manuellement](android-quickstart-manual). ::: Pour afficher un flow créé dans Adapty Flow Builder, vous avez uniquement besoin, dans le code de votre app, de : 1. **Obtenir le flow** : Récupérez-le depuis Adapty. 2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre app. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre app. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. [Connectez votre app à Google Play](initial-android) dans l'Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez-y votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-android) dans le code de votre app. Ce guide utilise les API du SDK Adapty Android v4. :::tip La façon la plus rapide d'effectuer ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des flows et des placements avec la [CLI développeur](developer-cli-quickstart). ::: ## 1. Obtenir le flow \{#1-get-the-flow\} Vos flows sont associés aux placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter différents flows pour différentes audiences ou de lancer des [tests A/B](ab-tests). Pour obtenir un flow créé dans Adapty Flow Builder, vous devez : 1. Obtenir l'objet `flow` par l'ID du [placement](placements) en utilisant la méthode `getFlow` et vérifier s'il dispose d'une configuration de vue. 2. Obtenir la configuration de vue à l'aide de la méthode `getFlowConfiguration`. La configuration de vue contient les éléments d'interface et le style nécessaires pour afficher le flow. :::important Pour obtenir la configuration de vue, vous devez activer le bouton **Show on device** dans le Flow Builder. Sinon, vous obtiendrez une configuration de vue vide et le flow ne sera pas affiché. ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> if (result is AdaptyResult.Success) { val flow = result.value if (!flow.hasViewConfiguration) { return@getFlow } AdaptyUI.getFlowConfiguration(flow) { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value } } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); if (!flow.hasViewConfiguration()) { return; } AdaptyUI.getFlowConfiguration(flow, configResult -> { if (configResult instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) configResult).getValue(); // use loaded configuration } }); } }); ``` ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez la configuration du flow, quelques lignes suffisent pour l'afficher. Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement l'`AdaptyFlowView` : ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, null, // products = null means auto-fetch eventListener, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, null, // products = null means auto-fetch eventListener, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, null, // products = null means auto-fetch eventListener ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml ... flowView.showFlow(flowConfiguration, products, eventListener); ``` ```xml showLineNumbers ``` Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil. :::tip Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](android-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Android gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des liens. Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Ou vous pouvez souhaiter remplacer leur comportement par défaut. Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire. :::tip Consultez nos guides sur la gestion des [actions](android-handle-paywall-actions) et des [événements](android-handling-events) des boutons. ::: ```kotlin showLineNumbers title="Kotlin" override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ```java showLineNumbers @Override public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) { if (action instanceof AdaptyUI.Action.Close) { if (context instanceof Activity) { ((Activity) context).onBackPressed(); } } } ``` ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'app. [Testez vos achats dans le Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow. Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](android-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment toutes ces étapes peuvent être intégrées ensemble dans votre app. ```kotlin showLineNumbers title="Kotlin" class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Adapty.getFlow("YOUR_PLACEMENT_ID") { flowResult -> if (flowResult is AdaptyResult.Success) { val flow = flowResult.value if (!flow.hasViewConfiguration) { // Use custom logic return@getFlow } AdaptyUI.getFlowConfiguration(flow) { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value val flowView = AdaptyUI.getFlowView( this, flowConfiguration, null, // products = null means auto-fetch object : AdaptyFlowDefaultEventListener() { override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Close -> { (context as? Activity)?.onBackPressed() } } } } ) setContentView(flowView) } } } } } } ``` ```java showLineNumbers public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Adapty.getFlow("YOUR_PLACEMENT_ID", flowResult -> { if (flowResult instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) flowResult).getValue(); if (!flow.hasViewConfiguration()) { // Use custom logic return; } AdaptyUI.getFlowConfiguration(flow, configResult -> { if (configResult instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) configResult).getValue(); AdaptyFlowView flowView = AdaptyUI.getFlowView( this, flowConfiguration, null, // products = null means auto-fetch new AdaptyFlowDefaultEventListener() { @Override public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) { if (action instanceof AdaptyUI.Action.Close) { if (context instanceof Activity) { ((Activity) context).onBackPressed(); } } } } ); setContentView(flowView); } }); } }); } } ``` --- # File: android-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK Android" description: "Apprenez à vérifier le statut d'abonnement dans votre application Android avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — afficher un paywall ou leur donner accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appelez `getProfile` si vous avez besoin des dernières données de profil immédiatement (par exemple au lancement de l'application) ou pour forcer une mise à jour. - Configurez les **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement dès que le statut d'abonnement change. ### Obtenir le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // check the access } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour du profil dans votre application : 1. Utilisez `Adapty.setOnProfileUpdatedListener()` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode dès que le statut d'abonnement de l'utilisateur change. 2. Stockez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser partout dans votre application sans effectuer de requêtes réseau supplémentaires. ```kotlin class SubscriptionManager { private var currentProfile: AdaptyProfile? = null init { // Listen for profile updates Adapty.setOnProfileUpdatedListener { profile -> currentProfile = profile // Update UI, unlock content, etc. } } // Use stored profile instead of calling getProfile() fun hasAccess(): Boolean { return currentProfile?.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true } } ``` ```java public class SubscriptionManager { private AdaptyProfile currentProfile; public SubscriptionManager() { // Listen for profile updates Adapty.setOnProfileUpdatedListener(profile -> { this.currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() public boolean hasAccess() { if (currentProfile == null) { return false; } AdaptyAccessLevel premiumAccess = currentProfile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); return premiumAccess != null && premiumAccess.isActive(); } } ``` :::note Adapty appelle automatiquement l'écouteur de mise à jour du profil au démarrage de votre application, en fournissant les données d'abonnement mises en cache même si l'appareil est hors ligne. ::: ## Connecter le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates concernant l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'entrée dans des sections premium, ou avant l'affichage de contenu spécifique. ```kotlin private fun initializePaywall() { loadPaywall { paywallView -> checkAccessLevel { result -> when (result) { is AdaptyResult.Success -> { if (!result.value && paywallView != null) { setContentView(paywallView) // Show paywall if no access } } is AdaptyResult.Error -> { if (paywallView != null) { setContentView(paywallView) // Show paywall if access check fails } } } } } } private fun checkAccessLevel(callback: ResultCallback) { Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val hasAccess = result.value.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true callback.onResult(AdaptyResult.Success(hasAccess)) } is AdaptyResult.Error -> { callback.onResult(AdaptyResult.Error(result.error)) } } } } ``` ```java private void initializePaywall() { loadPaywall(paywallView -> { checkAccessLevel(result -> { if (result instanceof AdaptyResult.Success) { boolean hasAccess = ((AdaptyResult.Success) result).getValue(); if (!hasAccess && paywallView != null) { setContentView(paywallView); // Show paywall if no access } } else if (result instanceof AdaptyResult.Error) { if (paywallView != null) { setContentView(paywallView); // Show paywall if access check fails } } }); }); } private void checkAccessLevel(ResultCallback callback) { Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); AdaptyAccessLevel premiumAccess = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); boolean hasAccess = premiumAccess != null && premiumAccess.isActive(); callback.onResult(AdaptyResult.success(hasAccess)); } else if (result instanceof AdaptyResult.Error) { callback.onResult(AdaptyResult.error(((AdaptyResult.Error) result).getError())); } }); } ``` ## Étapes suivantes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](android-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce pour quoi ils ont payé. --- # File: android-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK Android" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés sur Android." --- :::important Ce guide s'adresse à vous si vous disposez de votre propre système d'authentification. Vous apprendrez ici à gérer les profils utilisateurs dans Adapty pour qu'ils s'alignent sur votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez un **customer user ID** pour faire correspondre les profils Adapty avec votre système d'authentification interne. Voici les différences entre les utilisateurs anonymes et les utilisateurs identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|--------------------------------------------------------------|-------------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil sur toutes les sessions et tous les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'application | Les données des utilisateurs identifiés persistent entre les installations de l'application | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lorsque le SDK est activé au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, cet achat est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme à l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, par défaut, ses achats sont automatiquement synchronisés depuis l'App Store à l'activation du SDK. Ainsi, avec les utilisateurs anonymes, de nouveaux profils seront créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. ## Utilisateurs identifiés \{#identified-users\} Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat associé à un Customer User ID déjà lié à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils bénéficient d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après leur connexion ou inscription), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez jamais utilisé ce customer user ID auparavant**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user ID doivent être uniques pour chaque utilisateur. Si vous codez la valeur du paramètre en dur, tous les utilisateurs seront considérés comme un seul. ::: Attendez que le callback de complétion d'`identify` se déclenche avant d'appeler d'autres méthodes du SDK. Des appels simultanés pourraient atterrir sur le profil anonyme plutôt que sur le profil identifié. Voir [Ordre des appels dans le SDK Android](android-sdk-call-order). ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID au moment de l'activation du SDK, vous pouvez l'envoyer dans la méthode `activate` plutôt que d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`. Vous pouvez passer soit un customer user ID existant (que vous avez déjà utilisé), soit un nouveau. Si vous en passez un nouveau, le profil créé à l'activation sera automatiquement lié à ce customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées en fonction des ID d'appareil. Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une nouvelle installation, ni du fait qu'un customer user ID existant soit utilisé. La création d'un profil (à l'activation du SDK ou lors de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génère pas d'événements d'installation supplémentaires. Si vous souhaitez compter les installations en fonction des utilisateurs uniques plutôt que des appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build(); ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si vous avez un bouton pour déconnecter les utilisateurs, utilisez la méthode `logout`. :::important La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur. ::: ```kotlin showLineNumbers Adapty.logout { error -> if (error == null) { // successful logout } } ``` ```java showLineNumbers Adapty.logout(error -> { if (error == null) { // successful logout } }); ``` :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats aussi bien avant qu'après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty le lie à son ID de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez obtenir le niveau d'accès actuel après le changement de profil. Vous pouvez soit appeler [`getProfile`](android-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](android-check-subscription-status) pour que les données se synchronisent automatiquement. ## Prochaines étapes \{#next-steps\} Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre application ! Pour tirer encore plus de valeur d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu - [**Onboardings**](android-onboardings) : Engagez les utilisateurs avec des onboardings et améliorez la rétention - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code - [**Définir des attributs de profil personnalisés**](android-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher différents paywalls à différents utilisateurs --- # File: adapty-sdk-integration-skill-android --- --- title: "Intégrer Adapty dans votre application Android avec le skill d'intégration SDK" description: "Utilisez le skill adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Android de bout en bout avec votre outil de codage IA." --- :::important Le skill est en bêta. S'il se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-android) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-android --- --- title: "Intégrer Adapty dans votre application Android avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre application Android avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Android à l'aide d'un outil IA — vous lui fournissez la bonne documentation Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite une configuration dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire avec un skill LLM interactif, ou manuellement via le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre application, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Vous avez uniquement besoin de [connecter votre store](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris quand ouvrir le Dashboard pour connecter votre store. ### Approche manuelle \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir. 1. **Connectez votre store** : dans l'Adapty Dashboard, allez dans **App settings → General**. C'est indispensable pour que les achats fonctionnent. [Connecter Google Play](integrate-payments) 2. **Copiez votre clé SDK publique** : dans l'Adapty Dashboard, allez dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez au builder de configuration Adapty. 3. **Créez au moins un produit** : dans l'Adapty Dashboard, allez sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les livre via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID de placement est la chaîne que vous passez à `Adapty.getPaywall("YOUR_PLACEMENT_ID")`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels["premium"]?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants ont accès à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` et un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Dites à votre LLM : "Ma clé SDK publique est X, mon ID de placement est Y" pour qu'il génère un code d'initialisation et de récupération de paywall correct. ::: ### À configurer quand vous serez prêt \{#set-up-when-ready\} Ces éléments ne sont pas nécessaires pour commencer à coder, mais vous en aurez besoin à mesure que votre intégration se développe : - **Tests A/B** : à configurer sur la page **Placements**. Aucun changement de code nécessaire. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : ajoutez d'autres appels `getPaywall` avec des ID de placement différents. - **Intégrations analytiques** : à configurer sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytiques](analytics-integration) et [intégrations d'attribution](attribution-integration). ## Fournir la documentation Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bons documents en fonction de vos questions — pas besoin de coller des URL manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez : ``` npx ctx7 setup ``` Cela détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the Android SDK ``` :::warning Même si Context7 évite de coller des liens vers la documentation manuellement, l'ordre d'implémentation est important. Suivez le [guide d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne. ::: ### Utiliser la documentation en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quel article de la documentation Adapty en Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-android.md](https://adapty.io/docs/fr/adapty-cursor-android.md). Chaque étape du [guide d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc "À envoyer à votre LLM" avec des liens `.md` à coller. Pour obtenir davantage de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Guide d'implémentation \{#implementation-walkthrough\} La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les documents à envoyer à votre LLM, ce que vous devriez observer une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA propose un mode de planification (comme le mode plan de Cursor ou Claude Code), utilisez-le afin que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire du code. Indiquez à votre LLM l'approche que vous utilisez pour les achats — cela influe sur les guides à suivre : - [**Adapty Paywall Builder**](adapty-paywall-builder) : vous créez des paywalls dans l'éditeur no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](android-making-purchases) : vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats. - [**Mode Observer**](observer-vs-full-mode) : vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour l'analytique et les intégrations. Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le guide de démarrage rapide](android-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez la dépendance du SDK Adapty via Gradle dans Android Studio et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans ça. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-android) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-android.md ``` :::tip[Point de contrôle] - **Attendu :** l'application se compile et s'exécute. Logcat affiche le log d'activation Adapty. - **Problème courant :** "Public API key is missing" → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de la façon dont vous gérez les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. **Guides :** - [Activer les achats avec les paywalls (guide de démarrage rapide)](android-quickstart-paywalls) - [Récupérer les paywalls du Paywall Builder et leur configuration](android-get-pb-paywalls) - [Afficher les paywalls](android-present-paywalls) - [Gérer les événements de paywall](android-handling-events) - [Répondre aux actions des boutons](android-handle-paywall-actions) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/android-quickstart-paywalls.md - https://adapty.io/docs/fr/android-get-pb-paywalls.md - https://adapty.io/docs/fr/android-present-paywalls.md - https://adapty.io/docs/fr/android-handling-events.md - https://adapty.io/docs/fr/android-handle-paywall-actions.md ``` :::tip[Point de contrôle] - **Attendu :** le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Problème courant :** paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement à celui du tableau de bord et que le placement a une audience assignée. ::: **Guides :** - [Activer les achats dans votre paywall personnalisé (guide de démarrage rapide)](android-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-android) - [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-android) - [Effectuer des achats](android-making-purchases) - [Restaurer des achats](android-restore-purchase) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/android-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-android.md - https://adapty.io/docs/fr/present-remote-config-paywalls-android.md - https://adapty.io/docs/fr/android-making-purchases.md - https://adapty.io/docs/fr/android-restore-purchase.md ``` :::tip[Point de contrôle] - **Attendu :** votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Problème courant :** tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: **Guides :** - [Présentation du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode-android) - [Signaler les transactions en mode Observer](report-transactions-observer-mode-android) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-android.md - https://adapty.io/docs/fr/report-transactions-observer-mode-android.md ``` :::tip[Point de contrôle] - **Attendu :** après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty. - **Problème courant :** aucun événement → vérifiez que vous signalez les transactions à Adapty et que les notifications Google Play Real-Time Developer Notifications sont configurées. ::: ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez dans le profil utilisateur la présence d'un niveau d'accès actif pour restreindre le contenu premium. **Guide :** [Vérifier le statut de l'abonnement](android-check-subscription-status) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/android-check-subscription-status.md ``` :::tip[Point de contrôle] - **Attendu :** après un achat sandbox, `profile.accessLevels["premium"]?.isActive` renvoie `true`. - **Problème courant :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Liez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent sur tous les appareils. :::important Ignorez cette étape si votre application n'a pas d'authentification. ::: **Guide :** [Identifier les utilisateurs](android-quickstart-identify) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/android-quickstart-identify.md ``` :::tip[Point de contrôle] - **Attendu :** après avoir appelé `Adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Problème courant :** appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter l'attribution à un profil anonyme. ::: ### Se préparer pour la mise en production \{#prepare-for-release\} Une fois votre intégration fonctionnelle en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt pour la production. **Guide :** [Checklist de mise en production](release-checklist) À envoyer à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Point de contrôle] - **Attendu :** tous les éléments de la checklist confirmés : connexion au store, notifications serveur, flux d'achat, vérifications du niveau d'accès et exigences de confidentialité. - **Problème courant :** notifications Google Play Real-Time Developer Notifications manquantes → configurez-les dans **App settings → Android SDK**, sinon les événements n'apparaîtront pas dans le tableau de bord. ::: ## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\} Si vous avez besoin de fournir à votre LLM un contexte plus large que des pages individuelles, nous hébergeons des fichiers d'index qui listent ou regroupent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par exemple ChatGPT), vous devrez télécharger `llms.txt` et le joindre en pièce jointe dans la conversation. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : l'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement lorsque vous avez besoin d'une vue d'ensemble complète. - [`android-llms.txt`](https://adapty.io/docs/fr/android-llms.txt) et [`android-llms-full.txt`](https://adapty.io/docs/fr/android-llms-full.txt) spécifiques à Android : des sous-ensembles par plateforme qui économisent des tokens par rapport au site complet. --- # File: android-paywalls --- --- title: "Flows et paywalls - Android" description: "Affichez et gérez les flows et paywalls créés avec Adapty Flow Builder ou Paywall Builder dans votre application Android." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} :::tip Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](android-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} Pour plus de guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](android-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} --- # File: android-get-pb-paywalls --- --- title: "Obtenir des flows et des paywalls - Android" description: "Récupérez des flows et des paywalls depuis Adapty dans votre application Android." --- Après avoir [conçu votre flow ou votre paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. :::
Avant de commencer à afficher des flows dans votre application mobile (cliquer pour développer) 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. Vous devez néanmoins récupérer son ID via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le flow ou le paywall et sa [configuration de vue](android-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher à l'utilisateur. Pour obtenir un flow ou un paywall, utilisez la méthode `getFlow` : ```kotlin showLineNumbers ... Adapty.getFlow("YOUR_PLACEMENT_ID", loadTimeout = 10.seconds) { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow/paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers ... Adapty.getFlow("YOUR_PLACEMENT_ID", TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow/paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK essaie de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.

Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.

Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.

Le SDK Adapty stocke les flows et les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour les récupérer plus rapidement, ainsi qu'un serveur de secours autonome en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version tout en assurant la fiabilité même lorsque la connexion internet est limitée.

| | **loadTimeout** | par défaut : 5 sec |

Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.

Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en interne.

Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne définir aucune limite, utilisez `TimeInterval.INFINITE`.

| Paramètres de réponse : | Paramètre | Description | | :-------- | :---------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, les Remote Configs, ainsi qu'un indicateur `hasViewConfiguration` précisant si le flow inclut une configuration de vue. Pour récupérer les produits réels en vue d'un préchargement, d'une interface personnalisée ou de vérifications programmatiques, appelez `getPaywallProducts(flow)`. | ## Récupérer la configuration de vue \{#fetch-the-view-configuration\} Après avoir récupéré le flow ou le paywall, vérifiez s'il inclut une configuration de vue via `flow.hasViewConfiguration`. Ce flag permet de distinguer la façon dont le placement a été conçu dans l'Adapty Dashboard : - **`true`** — le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall). Adapty génère l'interface à votre place. Suivez les étapes ci-dessous pour récupérer la configuration de vue et [afficher le flow ou le paywall](android-present-paywalls). - **`false`** — le placement est un paywall personnalisé sans interface Builder. [Traitez-le comme un paywall Remote Config](present-remote-config-paywalls-android). :::important Veillez à activer le bouton **Show on device** dans le Flow Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible pour la récupération. ::: Utilisez la méthode `getFlowConfiguration` pour charger la configuration de la vue. ```kotlin showLineNumbers if (!flow.hasViewConfiguration) { // use your custom logic return } AdaptyUI.getFlowConfiguration(flow, loadTimeout = 10.seconds) { result -> when(result) { is AdaptyResult.Success -> { val flowConfiguration = result.value // use loaded configuration } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` | Paramètre | Présence | Description | | :-------------- | :------------- | :----------------------------------------------------------- | | **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | | **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) dans laquelle afficher la vue, attendu sous forme de code de langue avec un ou deux sous-tags séparés par `-` (ex. : `en`, `pt-br`). Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne contient pas de version `en`. Voir [Localisations et codes de langue](android-localizations-and-locale-codes). | | **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente de la méthode. Si ce délai est dépassé, les données en cache ou le fallback local sont retournés. Notez que dans de rares cas, la méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut regrouper plusieurs requêtes en interne. | Utilisez la méthode `getFlowConfiguration` pour charger la configuration de la vue. ```java showLineNumbers if (!flow.hasViewConfiguration()) { // use your custom logic return; } AdaptyUI.getFlowConfiguration(flow, TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) result).getValue(); // use loaded configuration } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | Paramètre | Présence | Description | | :-------------- | :------------- | :----------------------------------------------------------- | | **flow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | | **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) à utiliser pour afficher la vue, exprimé sous forme de code de langue avec un ou deux sous-tags séparés par `-` (ex. : `en`, `pt-br`). Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de `en`. Voir [Localisations et codes de locale](android-localizations-and-locale-codes). | | **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le contenu de secours local seront renvoyés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](android-localizations-and-locale-codes). ::: Une fois chargé, [présentez le flow ou le paywall](android-present-paywalls). ## Obtenir un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion Internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `getFlow`, comme détaillé dans la section [Récupérer le flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des flows ou des paywalls, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Toutefois, si vous pensez que vos utilisateurs font face à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui le rend fiable pour éviter des requêtes réseau en cours de session.

Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.

| ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre flow ou paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image d'aperçu locale pendant le chargement d'une image principale distante. - Afficher une image d'aperçu avant de lancer une vidéo. Here's an example of how you can provide custom assets via a simple dictionary: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Si un asset n'est pas trouvé, le flow utilisera son apparence par défaut. ::: Pour les vidéos, vous pouvez éventuellement passer une `resolution` pour réserver l'espace de mise en page et définir le ratio d'aspect (`width / height`) avant le chargement de la vidéo : ```kotlin showLineNumbers AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920), ) ```
Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. :::warning Le nouveau Paywall Builder nécessite Android SDK version 3.0 ou supérieure. ::: Veuillez noter que cette rubrique concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez la rubrique [Récupérer les paywalls et produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-android). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. :::
Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer) 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Il vous suffit néanmoins de récupérer son ID via le placement, sa configuration d'affichage, puis de le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les présenter à l'utilisateur. Pour obtenir un paywall, utilisez la méthode `getPaywall` : ```kotlin showLineNumbers ... Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en", loadTimeout = 10.seconds) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers ... Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** |

optionnel

par défaut : `en`

|

L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.

| | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.

Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.

Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.

Le SDK Adapty stocke les paywalls localement sur deux couches : le cache régulièrement mis à jour décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.

| | **loadTimeout** | par défaut : 5 sec |

Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés.

Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comporter différentes requêtes en coulisses.

Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.

| Paramètres de réponse : | Paramètre | Description | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) contenant une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer la configuration d'affichage d'un paywall créé avec Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration d'affichage ne pourra pas être récupérée. ::: Après avoir récupéré le paywall, vérifiez s'il contient un `ViewConfiguration`, ce qui indique qu'il a été créé avec Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si le `ViewConfiguration` est présent, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls). Utilisez la méthode `getViewConfiguration` pour charger la configuration de la vue. ```kotlin showLineNumbers if (!paywall.hasViewConfiguration) { // use your custom logic return } AdaptyUI.getViewConfiguration(paywall, loadTimeout = 10.seconds) { result -> when(result) { is AdaptyResult.Success -> { val viewConfiguration = result.value // use loaded configuration } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` | Paramètre | Présence | Description | | :-------------- | :----------------- | :----------------------------------------------------------- | | **paywall** | requis | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. | | **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de plusieurs requêtes en interne. | Utilisez la méthode `getViewConfiguration` pour charger la configuration de vue. ```java showLineNumbers if (!paywall.hasViewConfiguration()) { // use your custom logic return; } AdaptyUI.getViewConfiguration(paywall, TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyUI.LocalizedViewConfiguration viewConfiguration = ((AdaptyResult.Success) result).getValue(); // use loaded configuration } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | Paramètre | Présence | Description | | :----------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | requis | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. | | **loadTimeout** | défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut inclure différentes requêtes en coulisses. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de locale [ici](android-localizations-and-locale-codes). ::: Une fois chargé, [affichez le paywall](android-present-paywalls). ## Récupérer un paywall pour l'audience par défaut afin d'accélérer le chargement \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs ont une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide, plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients notables : - **Problèmes potentiels de compatibilité descendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (basé notamment sur les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, continuez à utiliser `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir du SDK Android 2.11.3 ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** |

optionnel

défaut : `en`

|

L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.

| | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas avoir les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, donc il est sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.

Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.

| ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos de votre paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image d'aperçu locale pendant le chargement d'une image principale distante. - Afficher une image d'aperçu avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK Android Adapty vers la version 3.7.0 ou supérieure. ::: Voici un exemple montrant comment fournir des ressources personnalisées via un simple dictionnaire : ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Si un asset est introuvable, le paywall reviendra à son apparence par défaut. :::
--- # File: android-present-paywalls --- --- title: "Afficher les flows et paywalls - Android" description: "Présentez des flows et des paywalls aux utilisateurs dans votre application Android." --- Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. :::warning Ce guide couvre les flows et les **paywalls créés avec le nouveau Paywall Builder** rendus par Adapty. Le processus diffère pour les paywalls en Remote Config et le [mode Observer](observer-vs-full-mode). - Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec le Remote Config](present-remote-config-paywalls). - Pour présenter des **paywalls en mode Observer**, consultez [Android - Présenter les paywalls Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) ::: Pour obtenir l'objet `flowConfiguration` utilisé ci-dessous, consultez [Récupérer les flows et paywalls](android-get-pb-paywalls). Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement `AdaptyFlowView` : ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml ... flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver); ``` ```xml showLineNumbers ``` Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil. Si vous obtenez `AdaptyFlowView` _autrement_ qu'en appelant `AdaptyUI.getFlowView()`, vous devrez également appeler la méthode `.showFlow()`. Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, utilisez cette fonction composable : ```kotlin showLineNumbers AdaptyFlowScreen( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **flowConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow. Utilisez la méthode `AdaptyUI.getFlowConfiguration(flow)` pour le charger. Consultez la rubrique [Récupérer la configuration de la vue](android-get-pb-paywalls#fetch-the-view-configuration) pour plus de détails. | | **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le timing d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupérera automatiquement les produits requis. | | **eventListener** | optionnel | Fournissez un `AdaptyFlowEventListener` pour observer les événements du flow. Il est recommandé d'étendre `AdaptyFlowDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gérer les événements flow et paywall](android-handling-events) pour plus de détails. | | **insets** | optionnel |

Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués par les barres système.

Par défaut : `Unspecified`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les flows plein écran.

Si votre flow n'est pas plein écran, vous pouvez définir des insets personnalisés. Pour savoir comment faire, lisez la section [Modifier les insets du flow](android-present-paywalls#change-flow-insets) ci-dessous.

| | **customAssets** | optionnel | Passez un objet `AdaptyCustomAssets` pour remplacer les images et vidéos de votre flow ou paywall au moment de l'exécution. Consultez [Personnaliser les assets](android-get-pb-paywalls#customize-assets) pour plus de détails. | | **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du flow. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique sur les balises personnalisées dans le Paywall Builder pour plus de détails. | | **timerResolver** | optionnel | Passez le résolveur ici si vous souhaitez utiliser la fonctionnalité de minuterie personnalisée. | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Modifier les insets du flow \{#change-flow-insets\} Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués par les barres système. Par défaut, Adapty ajuste automatiquement les insets, ce qui fonctionne parfaitement pour les flows plein écran. Si votre flow n'est pas plein écran, vous pouvez définir des insets personnalisés : - Si ni la barre de statut ni la barre de navigation ne se superposent à `AdaptyFlowView`, utilisez `AdaptyFlowInsets.None`. - Pour des configurations plus personnalisées, par exemple si votre flow se superpose à la barre de statut en haut mais pas en bas, vous pouvez définir uniquement `bottomInset` à `0`, comme indiqué dans l'exemple ci-dessous : ```kotlin showLineNumbers //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view flowView.onReceiveSystemBarsInsets { insets -> val flowInsets = AdaptyFlowInsets.vertical(insets.top, 0) flowView.showFlow( flowConfiguration, products, eventListener, flowInsets, customAssets, tagResolver, timerResolver, ) } ``` ```java showLineNumbers ... ViewCompat.setOnApplyWindowInsetsListener(flowView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(flowView, null); AdaptyFlowInsets flowInsets = AdaptyFlowInsets.vertical(systemBarInsets.top, 0); flowView.showFlow(flowConfiguration, products, eventListener, flowInsets); return insets; }); ``` ## Utiliser une minuterie définie par le développeur \{#use-developer-defined-timer\} Pour utiliser des minuteries définies par le développeur dans votre application mobile, créez un objet `timerResolver` — un dictionnaire ou une map qui associe des minuteries personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du flow. Voici un exemple : ```kotlin showLineNumbers ... val customTimers = mapOf( "CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025 ) val timerResolver = AdaptyUiTimerResolver { timerId -> customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } ) } ``` ```java showLineNumbers ... Map customTimers = new HashMap<>(); customTimers.put( "CUSTOM_TIMER_NY", new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime() ); AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() { @NonNull @Override public Date timerEndAtDate(@NonNull String timerId) { Date date = customTimers.get(timerId); return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */ } }; ``` Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** de la minuterie définie par le développeur que vous avez configurée dans l'Adapty Dashboard. Le `timerResolver` garantit que votre application met dynamiquement à jour la minuterie avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme l'heure de fin de la minuterie, comme le Jour de l'An, moins l'heure actuelle). ## Utiliser des balises personnalisées \{#use-custom-tags\} Pour utiliser des balises personnalisées dans votre application mobile, créez un objet `tagResolver` — un dictionnaire ou une map qui associe des balises personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du flow. Voici un exemple : ```kotlin showLineNumbers val customTags = mapOf("USERNAME" to "John") val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] } ``` ```java showLineNumbers Map customTags = new HashMap<>(); customTags.put("USERNAME", "John"); AdaptyUiTagResolver tagResolver = customTags::get; ``` Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme ``. Le `tagResolver` garantit que votre application remplace dynamiquement cette balise personnalisée par la valeur spécifiée — par exemple `John`. Nous recommandons de créer et de remplir le `tagResolver` juste avant de présenter votre flow. Une fois prêt, passez-le à la méthode AdaptyUI que vous utilisez pour présenter le flow. ## Modifier la couleur de l'indicateur de chargement du flow \{#change-flow-loading-indicator-color\} Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante : ```xml showLineNumbers title = "XML" ```
Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. :::warning Ce guide concerne uniquement les **paywalls créés avec le nouveau Paywall Builder** qui nécessitent le SDK v3.0. Le processus de présentation des paywalls diffère selon les versions du Paywall Builder, les paywalls en Remote Config et le [mode Observer](observer-vs-full-mode). - Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec le Remote Config](present-remote-config-paywalls). - Pour présenter des **paywalls en mode Observer**, consultez [Android - Présenter les paywalls Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) ::: Pour obtenir l'objet `viewConfiguration` utilisé ci-dessous, consultez [Récupérer les paywalls Paywall Builder et leur configuration](android-get-pb-paywalls). Pour afficher le paywall visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement `AdaptyPaywallView` : ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) ``` ```kotlin showLineNumbers val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { showPaywall( viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver ); ``` ```java showLineNumbers AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.showPaywall(viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver); ``` ```xml showLineNumbers ``` Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil. Si vous obtenez `AdaptyPaywallView` _autrement_ qu'en appelant `AdaptyUI.getPaywallView()`, vous devrez également appeler la méthode `.showPaywall()`. Pour afficher le paywall visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, utilisez cette fonction composable : ```kotlin showLineNumbers AdaptyPaywallScreen( viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **viewConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.LocalizedViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. | | **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le timing d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupérera automatiquement les produits requis. | | **eventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gérer les événements du paywall](android-handling-events) pour plus de détails. | | **insets** | optionnel |

Les insets sont les espaces autour du paywall qui empêchent les éléments cliquables d'être masqués par les barres système.

Par défaut : `UNSPECIFIED`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les paywalls plein écran.

Si votre paywall n'est pas plein écran, vous pouvez définir des insets personnalisés. Pour savoir comment faire, lisez la section [Modifier les insets du paywall](android-present-paywalls#change-paywall-insets) ci-dessous.

| | **personalizedOfferResolver** | optionnel | Pour indiquer un prix personnalisé ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et passez votre propre logique qui mappe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. | | **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique sur les balises personnalisées dans le Paywall Builder pour plus de détails. | | **timerResolver** | optionnel | Passez le résolveur ici si vous souhaitez utiliser la fonctionnalité de minuterie personnalisée. | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Modifier les insets du paywall \{#change-paywall-insets\} Les insets sont les espaces autour du paywall qui empêchent les éléments cliquables d'être masqués par les barres système. Par défaut, Adapty ajuste automatiquement les insets, ce qui fonctionne parfaitement pour les paywalls plein écran. Si votre paywall n'est pas plein écran, vous pouvez définir des insets personnalisés : - Si ni la barre de statut ni la barre de navigation ne se superposent à `AdaptyPaywallView`, utilisez `AdaptyPaywallInsets.NONE`. - Pour des configurations plus personnalisées, par exemple si votre paywall se superpose à la barre de statut en haut mais pas en bas, vous pouvez définir uniquement `bottomInset` à `0`, comme indiqué dans l'exemple ci-dessous : ```kotlin showLineNumbers //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view paywallView.onReceiveSystemBarsInsets { insets -> val paywallInsets = AdaptyPaywallInsets.vertical(insets.top, 0) paywallView.showPaywall( viewConfiguration, products, eventListener, paywallInsets, personalizedOfferResolver, tagResolver, timerResolver, ) } ``` ```java showLineNumbers ... ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(paywallView, null); AdaptyPaywallInsets paywallInsets = AdaptyPaywallInsets.of(systemBarInsets.top, 0); paywallView.showPaywall(paywall, products, viewConfiguration, paywallInsets, productTitleResolver); return insets; }); ``` ## Utiliser une minuterie définie par le développeur \{#use-developer-defined-timer\} Pour utiliser des minuteries définies par le développeur dans votre application mobile, créez un objet `timerResolver` — un dictionnaire ou une map qui associe des minuteries personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du paywall. Voici un exemple : ```kotlin showLineNumbers ... val customTimers = mapOf( "CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025 ) val timerResolver = AdaptyUiTimerResolver { timerId -> customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } ) } ``` ```java showLineNumbers ... Map customTimers = new HashMap<>(); customTimers.put( "CUSTOM_TIMER_NY", new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime() ); AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() { @NonNull @Override public Date timerEndAtDate(@NonNull String timerId) { Date date = customTimers.get(timerId); return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */ } }; ``` Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** de la minuterie définie par le développeur que vous avez configurée dans l'Adapty Dashboard. Le `timerResolver` garantit que votre application met dynamiquement à jour la minuterie avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme l'heure de fin de la minuterie, comme le Jour de l'An, moins l'heure actuelle). ## Utiliser des balises personnalisées \{#use-custom-tags\} Pour utiliser des balises personnalisées dans votre application mobile, créez un objet `tagResolver` — un dictionnaire ou une map qui associe des balises personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du paywall. Voici un exemple : ```kotlin showLineNumbers val customTags = mapOf("USERNAME" to "John") val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] } ``` ```java showLineNumbers Map customTags = new HashMap<>(); customTags.put("USERNAME", "John"); AdaptyUiTagResolver tagResolver = customTags::get; ``` Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme ``. Le `tagResolver` garantit que votre application remplace dynamiquement cette balise personnalisée par la valeur spécifiée — par exemple `John`. Nous recommandons de créer et de remplir le `tagResolver` juste avant de présenter votre paywall. Une fois prêt, passez-le à la méthode AdaptyUI que vous utilisez pour présenter le paywall. ## Modifier la couleur de l'indicateur de chargement du paywall \{#change-paywall-loading-indicator-color\} Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante : ```xml showLineNumbers title = "XML" ```
--- # File: android-handle-paywall-actions --- --- title: "Répondre aux actions des flows - Android" description: "Gérez les actions des boutons des flows et paywalls dans votre app Android." --- Si vous créez des flows ou des paywalls avec le Flow Builder ou le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et existantes dans votre code. :::warning **Seuls les achats, les restaurations, la fermeture des flows/paywalls et l'ouverture d'URL sont gérés automatiquement.** Toutes les autres actions de boutons nécessitent une implémentation appropriée dans le code de l'app. ::: ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui ferme votre flow ou paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un handler pour l'action `close`. :::info Dans le SDK Android, l'action `close` déclenche par défaut la fermeture du flow ou du paywall. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un flow peut déclencher l'ouverture d'un autre. ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ## Ouvrir des URL depuis les flows et les paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK Android, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.OpenUrl -> { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior context.startActivity(intent) } } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un handler pour l'ID d'action que vous avez créé. Par exemple, si vous proposez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre flow ou paywall : ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Custom -> { if (action.customId == "openNewPaywall") { // Display another flow or paywall } } } } ``` Si vous créez des paywalls avec le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et existantes dans votre code. :::warning **Seuls les achats, les restaurations, la fermeture des paywalls et l'ouverture d'URL sont gérés automatiquement.** Toutes les autres actions de boutons nécessitent une implémentation appropriée dans le code de l'app. ::: ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui ferme votre paywall : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un handler pour l'action `close` qui ferme le paywall. :::info Dans le SDK Android, l'action `close` déclenche par défaut la fermeture du paywall. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un paywall peut déclencher l'ouverture d'un autre. ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le Paywall Builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK Android, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.OpenUrl -> { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior context.startActivity(intent) } } } ``` ## Se connecter à l'app \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre app : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre app, implémentez un handler pour l'action `login` qui identifie votre utilisateur. ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Login -> { val intent = Intent(context, LoginActivity::class.java) context.startActivity(intent) } } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un handler pour l'ID d'action que vous avez créé. Par exemple, si vous proposez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre paywall : ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Custom -> { if (action.customId == "openNewPaywall") { // Display another paywall } } } } ``` --- # File: android-handling-events --- --- title: "Gérer les événements de flow et de paywall - Android" description: "Gérez les événements de flow et de paywall dans votre application Android." --- :::important Ce guide couvre la gestion des événements liés aux achats, restaurations, sélections de produits et au rendu des flows. Vous devez également implémenter la gestion des boutons (fermeture du flow, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de boutons](android-handle-paywall-actions) pour plus de détails. ::: Les flows et paywalls configurés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-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 les pressions sur les boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez ci-dessous comment répondre à ces événements. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Si vous avez besoin de contrôler ou surveiller les processus qui se déroulent sur l'écran d'achat, implémentez les méthodes `AdaptyFlowEventListener`. Si vous souhaitez conserver le comportement par défaut dans certains cas, vous pouvez étendre `AdaptyFlowDefaultEventListener` et ne remplacer que les méthodes que vous souhaitez modifier. Voici les comportements par défaut de `AdaptyFlowDefaultEventListener`. ### Événements générés par l'utilisateur \{#user-generated-events\} #### Sélection d'un produit \{#product-selection\} Si un produit est sélectionné pour achat (par l'utilisateur ou par le système), cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onProductSelected( product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### Achat initié \{#started-purchase\} Si un utilisateur lance le processus d'achat, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseStarted( product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si l'achat réussit, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFinished( purchaseResult: AdaptyPurchaseResult, product: AdaptyPaywallProduct, context: Context, ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) context.getActivityOrNull()?.onBackPressed() } ```
Exemples d'événements (cliquer pour développer) ```javascript // Successful purchase { "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" } } // Cancelled purchase { "purchaseResult": { "type": "UserCanceled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Pending purchase { "purchaseResult": { "type": "Pending" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
Nous recommandons de fermer l'écran dans ce cas. La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat échoué \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs Google Play Billing (restrictions de paiement, produits invalides, pannes réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `onPurchaseFinished` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode. ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFailure( error: AdaptyError, product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "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", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Navigation vers le paiement web terminée \{#finished-web-payment-navigation\} Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées : ```kotlin showLineNumbers title="Kotlin" public override fun onFinishWebPaymentNavigation( product: AdaptyPaywallProduct?, error: AdaptyError?, context: Context, ) {} ``` **Paramètres :** | Paramètre | Description | |:------------|:-------------------------------------------------------------------------------------------------------------| | **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. | | **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. |
Exemples d'événements (cliquer pour développer) ```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": "web_navigation_failed", "message": "Failed to open web paywall", "details": { "underlyingError": "Browser unavailable" } } } ```
#### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreSuccess( profile: AdaptyProfile, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```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" } ] } } ```
Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](android-listen-subscription-changes) pour savoir comment le vérifier. #### Restauration échouée \{#failed-restore\} Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreFailure( error: AdaptyError, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### Mise à niveau d'abonnement \{#upgrade-subscription\} Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre est déjà actif, vous pouvez contrôler la façon dont le nouvel achat doit être géré en remplaçant cette méthode. Vous avez deux options : 1. **Remplacer l'abonnement actuel** par le nouveau : ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback, ): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived( AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) .build() ) return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` 2. **Conserver les deux abonnements** (ajouter le nouveau séparément) : ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback, ): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` :::note Si vous ne remplacez pas cette méthode, le comportement par défaut est de conserver les deux abonnements actifs (équivalent à utiliser `AdaptyPurchaseParameters.Empty`). ::: Vous pouvez également définir des paramètres d'achat supplémentaires si nécessaire : ```kotlin AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription .withOfferPersonalized(true) // optional - if using personalized pricing .build() ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_yearly", "localizedTitle": "Premium Yearly", "localizedDescription": "Premium subscription for 1 year", "localizedPrice": "$99.99", "price": 99.99, "currencyCode": "USD" }, "subscriptionUpdateParams": { "replacementMode": "with_time_proration" } } ```
### Récupération de données et rendu \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode : ```kotlin showLineNumbers title="Kotlin" public override fun onLoadingProductsFailure( error: AdaptyError, context: Context, ): Boolean = false ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
Si vous retournez `true`, AdaptyUI relancera la requête dans 2 secondes. #### Erreurs de rendu \{#rendering-errors\} Si une erreur survient lors du rendu de l'interface, elle sera signalée en appelant cette méthode : ```kotlin showLineNumbers title="Kotlin" public override fun onError( error: AdaptyError, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } ```
Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le faire savoir. ### Navigation \{#navigation\} #### Bouton retour système \{#system-back-button\} Par défaut, un flow ne peut pas être fermé avec le bouton retour système ou le geste de retour — l'utilisateur le quitte via un chemin que vous définissez, comme un bouton **Fermer** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, remplacez `onBackPressed` et retournez `false` pour laisser votre activité ou fragment hôte gérer l'appui : ```kotlin showLineNumbers title="Kotlin" public override fun onBackPressed(context: Context): Boolean { return false // let the host handle the back press (e.g. finish the activity or pop the fragment) } ``` Ce callback n'est invoqué que lorsqu'aucune action `on_device_back` n'est configurée pour l'écran actuel — une action configurée prend la priorité et est gérée en interne. Retournez `true` pour consommer l'appui (comportement par défaut), ou `false` pour laisser la gestion du retour de l'hôte s'exécuter. ### Événements réservés \{#reserved-events\} `AdaptyFlowEventListener` déclare quelques callbacks pour des fonctionnalités que les flows n'utilisent pas encore. Vous n'avez pas besoin de les implémenter — `AdaptyFlowDefaultEventListener` fournit déjà des implémentations vides par défaut. | Méthode | Description | |:--------|:------------| | **onAnalyticEvent** | Réservé pour les événements analytiques personnalisés 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. | | **onShowAppRate** | Réservé pour les demandes d'évaluation d'application depuis un flow. Les flows ne déclenchent pas encore de demandes d'évaluation, vous n'avez donc pas besoin de l'implémenter. | | **onShowRequestPermission** | Réservé pour les 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. |
:::important Ce guide couvre la gestion des événements liés aux achats, restaurations, sélections de produits et au 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](android-handle-paywall-actions) pour plus de détails. ::: Les paywalls configurés avec le [Paywall Builder](adapty-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 les pressions sur les 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épondre à ces événements. :::warning Ce guide concerne uniquement les **nouveaux paywalls du Paywall Builder** qui nécessitent le SDK Adapty v3.0 ou une version ultérieure. ::: :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Si vous avez besoin de contrôler ou surveiller les processus qui se déroulent sur l'écran d'achat, implémentez les méthodes `AdaptyUiEventListener`. Si vous souhaitez conserver le comportement par défaut dans certains cas, vous pouvez étendre `AdaptyUiDefaultEventListener` et ne remplacer que les méthodes que vous souhaitez modifier. Voici les comportements par défaut de `AdaptyUiDefaultEventListener`. ### Événements générés par l'utilisateur \{#user-generated-events\} #### Sélection d'un produit \{#product-selection\} Si un produit est sélectionné pour achat (par l'utilisateur ou par le système), cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onProductSelected( product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### Achat initié \{#started-purchase\} Si un utilisateur lance le processus d'achat, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseStarted( product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si l'achat réussit, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFinished( purchaseResult: AdaptyPurchaseResult, product: AdaptyPaywallProduct, context: Context, ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) context.getActivityOrNull()?.onBackPressed() } ```
Exemples d'événements (cliquer pour développer) ```javascript // Successful purchase { "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" } } // Cancelled purchase { "purchaseResult": { "type": "UserCanceled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Pending purchase { "purchaseResult": { "type": "Pending" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
Nous recommandons de fermer l'écran dans ce cas. La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat échoué \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs Google Play Billing (restrictions de paiement, produits invalides, pannes réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `onPurchaseFinished` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode. ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFailure( error: AdaptyError, product: AdaptyPaywallProduct, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "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", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Navigation vers le paiement web terminée \{#finished-web-payment-navigation\} Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées : ```kotlin showLineNumbers title="Kotlin" public override fun onFinishWebPaymentNavigation( product: AdaptyPaywallProduct?, error: AdaptyError?, context: Context, ) {} ``` **Paramètres :** | Paramètre | Description | |:------------|:-------------------------------------------------------------------------------------------------------------| | **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. | | **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. |
Exemples d'événements (cliquer pour développer) ```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": "web_navigation_failed", "message": "Failed to open web paywall", "details": { "underlyingError": "Browser unavailable" } } } ```
#### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreSuccess( profile: AdaptyProfile, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```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" } ] } } ```
Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](android-listen-subscription-changes) pour savoir comment le vérifier. #### Restauration échouée \{#failed-restore\} Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreFailure( error: AdaptyError, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### Mise à niveau d'abonnement \{#upgrade-subscription\} Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre est déjà actif, vous pouvez contrôler la façon dont le nouvel achat doit être géré en remplaçant cette méthode. Vous avez deux options : 1. **Remplacer l'abonnement actuel** par le nouveau : ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived( AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) .build() ) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` 2. **Conserver les deux abonnements** (ajouter le nouveau séparément) : ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` :::note Si vous ne remplacez pas cette méthode, le comportement par défaut est de conserver les deux abonnements actifs (équivalent à utiliser `AdaptyPurchaseParameters.Empty`). ::: Vous pouvez également définir des paramètres d'achat supplémentaires si nécessaire : ```kotlin AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription .withOfferPersonalized(true) // optional - if using personalized pricing .build() ``` Si un nouvel abonnement est acheté alors qu'un autre est encore actif, remplacez cette méthode pour substituer l'abonnement actuel par le nouveau. Si l'abonnement actif doit rester actif et que le nouveau est ajouté séparément, appelez `onSubscriptionUpdateParamsReceived(null)` : ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingSubscriptionUpdateParams( product: AdaptyPaywallProduct, context: Context, onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, ) { onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) } ```
Exemple d'événement (cliquer pour développer) ```javascript { "product": { "vendorProductId": "premium_yearly", "localizedTitle": "Premium Yearly", "localizedDescription": "Premium subscription for 1 year", "localizedPrice": "$99.99", "price": 99.99, "currencyCode": "USD" }, "subscriptionUpdateParams": { "replacementMode": "with_time_proration" } } ```
### Récupération de données et rendu \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode : ```kotlin showLineNumbers title="Kotlin" public override fun onLoadingProductsFailure( error: AdaptyError, context: Context, ): Boolean = false ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
Si vous retournez `true`, AdaptyUI relancera la requête dans 2 secondes. #### Erreurs de rendu \{#rendering-errors\} Si une erreur survient lors du rendu de l'interface, elle sera signalée en appelant cette méthode : ```kotlin showLineNumbers title="Kotlin" public override fun onRenderingError( error: AdaptyError, context: Context, ) {} ```
Exemple d'événement (cliquer pour développer) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ```
Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le faire savoir.
--- # File: android-use-fallback-paywalls --- --- title: "Android - Utiliser les paywalls de secours" description: "Gérez les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles." --- :::warning Les paywalls de secours sont pris en charge par le SDK Android v2.11 et versions ultérieures. ::: To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} 1. Déplacez le fichier de configuration de secours dans le répertoire `assets` ou `res/raw` de votre projet Android. 2. Appelez la méthode `.setFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible. ```kotlin showLineNumbers //if you put the 'android_fallback.json' file to the 'assets' directory val location = FileLocation.fromAsset("android_fallback.json") //or `FileLocation.fromAsset("/android_fallback.json")` if you placed it in a child folder of 'assets') //if you put the 'android_fallback.json' file to the 'res/raw' directory val location = FileLocation.fromResId(context, R.raw.android_fallback) //you can also pass a file URI val fileUri: Uri = //get Uri for the file with fallback paywalls val location = FileLocation.fromFileUri(fileUri) //pass the file location Adapty.setFallback(location, callback) ``` ```java showLineNumbers //if you put the 'android_fallback.json' file to the 'assets' directory FileLocation location = FileLocation.fromAsset("android_fallback.json"); //or `FileLocation.fromAsset("/android_fallback.json");` if you placed it in a child folder of 'assets') //if you put the 'android_fallback.json' file to the 'res/raw' directory FileLocation location = FileLocation.fromResId(context, R.raw.android_fallback); //you can also pass a file URI Uri fileUri = //get Uri for the file with fallback paywalls FileLocation location = FileLocation.fromFileUri(fileUri); //pass the file location Adapty.setFallback(location, callback); ``` Paramètres : | Paramètre | Description | | :----------- | :----------------------------------------------------------- | | **location** | L'objet [FileLocation](https://android.adapty.io/adapty/com.adapty.utils/-file-location/-companion/) pour le fichier de configuration de secours | --- # File: android-localizations-and-locale-codes --- --- title: "Utiliser les localisations et codes de locale dans le SDK Android" description: "Gérez les localisations et codes de locale de votre application pour toucher une audience mondiale (Android)." --- ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu quand Adapty choisit la localisation pour un flow, et quand vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prédire quelle localisation un utilisateur recevra. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-étiquettes en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty recherche la localisation correspondant à la locale d'un utilisateur, voici ce qui se passe : 1. La chaîne de locale est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est trouvée à nouveau, Adapty renvoie le contenu dans la langue par défaut du flow Cette façon de procéder permet à `'pt_BR'`, `pt-BR` et `pt-br` de pointer vers la même localisation. ## Implémentation des localisations \{#implementing-localizations\} Dans le SDK v4, vous ne transmettez pas de code de langue lors de la récupération d'un flow — `getFlow` retourne le flow avec toutes ses localisations. - **Flows créés dans le builder** : le SDK ne lit pas la locale de l'appareil, vous devez donc la résoudre dans votre application et la passer comme argument `locale` de `AdaptyUI.getFlowConfiguration`. L'argument est optionnel — omettez-le et le flow s'affiche en `en`, ou dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow n'a pas de localisation `en`. Si vous demandez une localisation que le flow ne possède pas, la vue revient à la valeur par défaut du flow sans erreur, et les chaînes manquantes dans la localisation choisie sont reprises de la locale par défaut. Le rendu en `en` par défaut nécessite le SDK Android 4.0.1. Dans la version 4.0.0, l'omission de `locale` affiche la localisation par défaut du flow. - **Paywalls personnalisés (Remote Config)** : `getFlow` retourne toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée contient un code `locale` et le contenu de la configuration (`jsonString`, ou le `dataMap` parsé). Sélectionnez l'entrée correspondant à l'utilisateur, avec votre propre logique de repli : ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() // read your values from config?.dataMap } is AdaptyResult.Error -> { // handle the error } } } ``` Les règles de correspondance des codes de paramètres régionaux décrites ci-dessus expliquent comment Adapty normalise les codes `locale` stockés dans chaque Remote Config. ## Pourquoi c'est important \{#why-this-is-important\} Il existe plusieurs situations où les codes de langue entrent en jeu — par exemple, lorsque vous essayez de récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de langue étant complexes et pouvant varier d'une plateforme à l'autre, nous nous appuyons sur un standard interne pour toutes les plateformes que nous prenons en charge. Cependant, en raison de cette complexité, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin que vous receviez toujours ce que vous attendez. ## Standard de code de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-tags en minuscules, séparés par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Quand Adapty reçoit un appel du SDK côté client avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de locale reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. On cherche ensuite la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si aucune correspondance n'est trouvée non plus, on renvoie le contenu dans la locale par défaut du paywall Ainsi, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Mise en œuvre des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous interrogez sur les localisations, vous travaillez probablement déjà avec des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de localisation. Ensuite, récupérez la valeur de cette clé lors de l'appel à notre SDK, comme ceci : ```kotlin showLineNumbers // 1. Modify your strings.xml files /* strings.xml - Spanish */ es /* strings.xml - Portuguese (Brazil) */ pt-br // 2. Extract and use the locale code val localeCode = context.getString(R.string.adapty_paywalls_locale) // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` Vous contrôlez ainsi entièrement la localisation qui sera récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : l'autre méthode \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de langue pour chaque localisation. Il s'agirait d'extraire un code de langue depuis d'autres objets fournis par votre plateforme, comme ceci : ```kotlin showLineNumbers val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) context.resources.configuration.locales[0] else context.resources.configuration.locale val localeCode = locale.toLanguageTag() // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` Notez que nous ne recommandons pas cette approche car il est difficile de prévoir exactement ce que le serveur d'Adapty recevra. Si vous décidez tout de même d'utiliser cette approche, assurez-vous d'avoir couvert tous les cas d'utilisation pertinents. --- # File: android-web-paywall --- --- title: "Implémenter les paywalls web dans le SDK Android" description: "Configurez un paywall web pour accepter des paiements sans les frais et audits du Play Store." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé la version 3.15 ou ultérieure du SDK Adapty. ::: ## Ouvrir les paywalls web \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `.openWebPaywall` : 1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `.getProfile` à intervalles rapprochés pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. :::note Après le retour des utilisateurs dans l'application, actualisez l'interface pour refléter les mises à jour du profil. Adapty recevra et traitera les événements de mise à jour du profil. ::: ```kotlin showLineNumbers Adapty.openWebPaywall( activity = activity, product = product, ) { error -> if (error == null) { // the web paywall was opened successfully } else { // handle the error } } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall(product)` qui génère des URL par paywall et ajoute également les données du produit aux URL. 2. `openWebPaywall(paywall)` qui génère des URL par paywall sans ajouter les données du produit aux URL. Utilisez-la quand vos produits dans le paywall Adapty diffèrent de ceux du paywall web. ::: ## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} Par défaut, les paywalls web s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. La page d'achat web s'affiche alors directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application. Pour activer cette option, définissez le paramètre `presentation` sur `AdaptyWebPresentation.InAppBrowser` : ```kotlin showLineNumbers Adapty.openWebPaywall( activity = activity, product = product, presentation = AdaptyWebPresentation.InAppBrowser, ) { error -> if (error == null) { // the web paywall was opened successfully } else { // handle the error val adaptyError = error } } ``` --- # File: android-troubleshoot-paywall-builder --- --- title: "Dépanner le Paywall Builder dans le SDK Android" description: "Dépanner le Paywall Builder dans le SDK Android" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK Android. ## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La méthode `getViewConfiguration` ne parvient pas à récupérer la configuration du paywall. **Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. ## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le compteur de vues du paywall affiche le double du nombre attendu. **Cause** : Vous appelez peut-être `logShowFlow` (SDK Android v4+) / `logShowPaywall` dans votre code, ce qui double le compteur de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls construits avec ces outils, l'analytique est suivie automatiquement, il n'est donc pas nécessaire d'utiliser cette méthode. **Solution** : Assurez-vous de ne pas appeler `logShowFlow` (SDK Android v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder non couverts ci-dessus. **Solution** : Migrez le SDK vers la dernière version en utilisant les [guides de migration](android-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: android-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement dans le SDK Android" description: "Découvrez comment implémenter des paywalls manuellement dans votre application Android avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty en utilisant la méthode `makePurchase`. De cette façon, nous gérons tous les scénarios utilisateur, et vous n'avez qu'à traiter les résultats de l'achat. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, tout en bénéficiant des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: --- # File: android-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec le SDK Android" description: "Intégrez le SDK Adapty dans vos paywalls Android personnalisés pour activer les achats intégrés." --- Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, pendant que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les achats précédents. :::important **Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la méthode la plus simple pour activer les achats, utilisez le [Adapty Flow Builder](android-quickstart-paywalls). Avec Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différents designs sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. - [**Placements**](placements) – où et quand vous affichez les paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite la mise en place de tests A/B et l'affichage de différents paywalls à différents utilisateurs. Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. Ils constituent simplement votre façon de gérer les produits que vous vendez dans votre application. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](android-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs. ## Étape 1. Récupérer les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau de produits pour ce flow en utilisant la méthode `getPaywallProducts`. ```kotlin showLineNumbers fun loadPaywall() { Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value Adapty.getPaywallProducts(flow) { productResult -> when (productResult) { is AdaptyResult.Success -> { val products = productResult.value // Use products to build your custom paywall UI } is AdaptyResult.Error -> { val error = productResult.error // Handle the error } } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void loadPaywall() { Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); Adapty.getPaywallProducts(flow, productResult -> { if (productResult instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) productResult).getValue(); // Use products to build your custom paywall UI } else if (productResult instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) productResult).getError(); // Handle the error } }); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour. ```kotlin showLineNumbers fun purchaseProduct(activity: Activity, product: AdaptyPaywallProduct) { Adapty.makePurchase(activity, product) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // Purchase successful, profile updated } is AdaptyPurchaseResult.UserCanceled -> { // User canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Purchase is pending (e.g., user will pay offline with cash) } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void purchaseProduct(Activity activity, AdaptyPaywallProduct product) { Adapty.makePurchase(activity, product, null, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); // Purchase successful, profile updated } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // User canceled the purchase } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // Purchase is pending (e.g., user will pay offline with cash) } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Google Play et les autres stores d'applications exigent que toutes les applications proposant des abonnements offrent un moyen aux utilisateurs de restaurer leurs achats. Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et retournera le profil mis à jour. ```kotlin showLineNumbers fun restorePurchases() { Adapty.restorePurchases { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // Restore successful, profile updated } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void restorePurchases() { Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // Restore successful, profile updated } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); } ``` ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. [Testez vos achats sur Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez le [ProductListFragment.kt](https://github.com/adaptyteam/AdaptySDK-Android/blob/master/app/src/main/java/com/adapty/example/ProductListFragment.kt) dans notre exemple d'application, qui illustre la gestion des achats avec une gestion des erreurs appropriée, des retours d'interface utilisateur et la gestion des abonnements. Ensuite, [vérifiez si les utilisateurs ont finalisé leur achat](android-check-subscription-status) pour déterminer si vous devez afficher le paywall ou accorder l'accès aux fonctionnalités payantes. --- # File: fetch-paywalls-and-products-android --- --- title: "Récupérer les paywalls et produits pour les paywalls de Remote Config dans le SDK Android" description: "Récupérez les paywalls et produits dans le SDK Android Adapty pour améliorer la monétisation des utilisateurs." --- Avant d'afficher un Remote Config ou des paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne les Remote Config et les paywalls personnalisés. Pour récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Obtenir des flows et des paywalls](android-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. :::
Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer) 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits multi-plateformes sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) à l'aide de la méthode `getFlow`. :::important **N'écrivez pas les identifiants de produits en dur dans le code.** Le seul identifiant à coder en dur est celui du placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements de manière dynamique — si un flow renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. || **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données mises en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.

Toutefois, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données mises en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas accès aux toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui le rend fiable pendant la session pour éviter des requêtes réseau inutiles.

Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou d'un nettoyage manuel.

Le SDK Adapty stocke les flows et les paywalls en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](android-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours autonome au cas où le CDN serait inaccessible.

| | **loadTimeout** | par défaut : 5 sec |

Cette valeur limite le délai d'attente pour cette méthode. Si le délai est atteint, les données mises en cache ou le fallback local sont renvoyés.

Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut regrouper différentes requêtes en arrière-plan.

| N'encodez pas les IDs de produit en dur ! Comme les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer à tout moment. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à encoder en dur est l'ID de placement. Paramètres de la réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, un tableau `remoteConfigs` (une entrée par locale configurée) et un indicateur `hasViewConfiguration`. Pour récupérer les produits du flow, appelez `getPaywallProducts(flow)`. | :::note Dans la v4, le paramètre `locale` a été déplacé hors de `getFlow` et dans `getFlowConfiguration` (utilisé uniquement lors du rendu avec AdaptyUI). Pour les paywalls personnalisés, toutes les locales disponibles sont renvoyées ensemble dans `flow.remoteConfigs` — choisissez la locale qui correspond à la langue de l'appareil de l'utilisateur ou au paramètre de votre application. ::: ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond : ```kotlin showLineNumbers Adapty.getPaywallProducts(flow) { result -> when (result) { is AdaptyResult.Success -> { val products = result.value // the requested products } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallProducts(flow, result -> { if (result instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) result).getValue(); // the requested products } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) contenant : l'identifiant du produit, son nom, son prix, la devise, la durée de l'abonnement et plusieurs autres propriétés. | Lorsque vous implémentez votre propre design de flow, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir des détails complets sur toutes les propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher le prix dans sa version localisée, utilisez `product.price.localizedString`. La localisation est basée sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme de nombre via `product.price.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. La localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez alors accéder à l'enum `unit` pour obtenir la durée (c.-à-d. DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou un autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.
• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, attendez-vous à voir `0` ici.
• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.
• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre avec cette propriété. Elle fonctionne de la même manière pour les offres que dans la section précédente.
• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon la locale de l'utilisateur. | ## Accélérer la récupération des flows avec un flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Cependant, il est crucial de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-android#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows qui ne s'affichent pas correctement. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur le `getFlow` décrit [ci-dessus](fetch-paywalls-and-products-android#fetch-flow-information). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // le flow demandé } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // gérer l'erreur } }); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. || **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.

Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.

|
Avant de présenter les Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne les Remote Config et les paywalls personnalisés. Pour obtenir des instructions sur la récupération des paywalls créés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](android-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. :::
Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer) 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer les informations du paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits provenant à la fois de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés aux paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **Ne codez pas les ID de produits en dur.** Le seul ID que vous devez coder en dur est l'ID de placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** |

optionnel

par défaut : `en`

|

L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](android-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.

| | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.

Toutefois, si vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session pour éviter les requêtes réseau.

Notez que le cache est conservé après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.

Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](android-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système garantit que vous obtenez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion est limitée.

| | **loadTimeout** | par défaut : 5 sec |

Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.

Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en arrière-plan.

| N'encodez pas les identifiants de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent évoluer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à encoder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le paywall, vous pouvez récupérer le tableau de produits qui lui correspond : ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall) { result -> when (result) { is AdaptyResult.Success -> { val products = result.value // the requested products } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallProducts(paywall, result -> { if (result instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) result).getValue(); // the requested products } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) contenant : l'identifiant du produit, le nom du produit, le prix, la devise, la durée de l'abonnement, et plusieurs autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue du terminal. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. La localisation est basée sur les paramètres régionaux du terminal. Vous pouvez également accéder au prix sous forme de nombre avec `product.price.amount`. La valeur est exprimée dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. La localisation est basée sur les paramètres régionaux du terminal. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` indique le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, `unit` vaut `MONTH` et `numberOfUnits` vaut `3`. | | **Introductory Offer** | Pour afficher un badge ou un indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase expose les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.
• `price` : le prix remisé sous forme de nombre. Pour les essais gratuits, cette valeur est `0`.
• `localizedNumberOfPeriods` : une chaîne localisée selon les paramètres régionaux du terminal, décrivant la durée de l'offre. Par exemple, un essai de trois jours affiche `3 days` dans ce champ.
• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété, qui fonctionne de la même manière que décrit dans la section précédente.
• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon les paramètres régionaux de l'utilisateur. | ## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ces situations, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-android#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent avoir des problèmes avec des paywalls non rendus. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (y compris par pays, attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](fetch-paywalls-and-products-android#fetch-paywall-information). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.3 du SDK Android. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** |

optionnel

par défaut : `en`

|

L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](android-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.

| | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.

Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.

|
--- # File: present-remote-config-paywalls-android --- --- title: "Afficher un paywall conçu par Remote Config dans le SDK Android" description: "Découvrez comment présenter des paywalls Remote Config dans le SDK Android Adapty pour personnaliser l'expérience utilisateur." --- Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et l'apparence de votre paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous donnant toute latitude pour présenter votre paywall personnalisé. ## Récupérer la Remote Config d'un flow et l'afficher \{#get-flow-remote-config-and-present-it\} Dans la v4, un flow contient une entrée `AdaptyRemoteConfig` par locale configurée dans le tableau `remoteConfigs`. Sélectionnez la locale qui correspond à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin. ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() val headerText = config?.dataMap?.get("header_text") as? String } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); AdaptyRemoteConfig config = null; for (AdaptyRemoteConfig remoteConfig : flow.getRemoteConfigs()) { if ("en".equals(remoteConfig.getLocale())) { config = remoteConfig; break; } } if (config == null && !flow.getRemoteConfigs().isEmpty()) { config = flow.getRemoteConfigs().get(0); } if (config != null && config.getDataMap().get("header_text") instanceof String) { String headerText = (String) config.getDataMap().get("header_text"); } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler en une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des mobiles, pour une expérience fluide et agréable sur tous les appareils. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-android#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du paywall terminé, configurez le flow d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](android-making-purchases). Nous vous recommandons de [créer un paywall de secours](android-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos flows et paywalls. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages nécessite votre intervention, car vous seul savez quand un utilisateur voit un flow. Pour enregistrer un événement d'affichage, appelez simplement `.logShowFlow(flow)` — cela sera reflété dans vos métriques de funnels et de tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les affichages automatiquement dans ces cas. ::: ```kotlin showLineNumbers Adapty.logShowFlow(flow) ``` Paramètres de la requête : | Paramètre | Obligatoire | Description | | :-------- | :------- |:-----------------------------------------------------------------------------------------| | **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et l'apparence de votre paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous donnant toute latitude pour présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer la Remote Config d'un paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir la Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires. ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); AdaptyPaywall.RemoteConfig remoteConfig = paywall.getRemoteConfig(); if (remoteConfig != null) { if (remoteConfig.getDataMap().get("header_text") instanceof String) { String headerText = (String) remoteConfig.getDataMap().get("header_text"); } } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler en une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des mobiles, pour une expérience fluide et agréable sur tous les appareils. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-android#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du paywall terminé, configurez le flow d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](android-making-purchases). Nous vous recommandons de [créer un paywall de secours](android-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowPaywall(paywall)` — cela sera reflété dans vos métriques de paywall dans les funnels et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```kotlin showLineNumbers Adapty.logShowPaywall(paywall) ``` Paramètres de la requête : | Paramètre | Obligatoire | Description | | :---------- | :------- |:------------------------------------------------------------------------------------------------------------| | **paywall** | obligatoire | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | --- # File: android-making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK Android" description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour offrir aux utilisateurs l'accès à des contenus ou services premium. Cependant, se contenter d'afficher ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour les personnaliser. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode dédiée appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode sert de point d'entrée pour que les utilisateurs interagissent avec les paywalls et procèdent à leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de la publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs pourtant éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans elle, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](android-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: ```kotlin showLineNumbers Adapty.makePurchase(activity, product, null) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // Grant access to the paid features } } is AdaptyPurchaseResult.UserCanceled -> { // Handle the case where the user canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Handle deferred purchases (e.g., the user will pay offline with cash) } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ``` ```java showLineNumbers Adapty.makePurchase(activity, product, null, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); if (premium != null && premium.isActive()) { // Grant access to the paid features } } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // Handle the case where the user canceled the purchase } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // Handle deferred purchases (e.g., the user will pay offline with cash) } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

Si la requête a réussi, la réponse contient cet objet. Un objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur dans l'application.

Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.

| :::warning **Remarque :** si vous utilisez encore une version de StoreKit d'Apple inférieure à v2.0 et une version du SDK Adapty inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple. ::: ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur choisit un nouvel abonnement plutôt que de renouveler l'abonnement en cours, le fonctionnement dépend du store. Sur Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer un abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire suivant : ```kotlin showLineNumbers Adapty.makePurchase( activity, product, AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(subscriptionUpdateParams) .build() ) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------------------------- | :------- | :----------------------------------------------------------- | | **subscriptionUpdateParams** | requis | un objet [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/). | ```java showLineNumbers Adapty.makePurchase( activity, product, new AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(subscriptionUpdateParams) .build(), result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); // successful cross-grade } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // user canceled the purchase flow } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // the purchase has not been finished yet, e.g. user will pay offline by cash } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------------------------- | :------- | :----------------------------------------------------------- | | **subscriptionUpdateParams** | requis | un objet [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/). | Pour en savoir plus sur les abonnements et les modes de remplacement, consultez la documentation Google Developer : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation en cours. ### Gérer les plans prépayés \{#manage-prepaid-plans\} Si les utilisateurs de votre application peuvent acheter des [plans prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, souscrire à un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour ces plans. ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withEnablePendingPrepaidPlans(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withEnablePendingPrepaidPlans(true) .build(); ``` --- # File: android-restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec le SDK Android" description: "Apprenez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés — abonnements ou achats intégrés — sans être facturés à nouveau. Elle est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leurs achats sans repayer. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement, sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder), appelez la méthode `.restorePurchases()` : ```kotlin showLineNumbers Adapty.restorePurchases { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // successful access restore } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); if (profile != null) { AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); if (premium != null && premium.isActive()) { // successful access restore } } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres de la réponse : | Paramètre | Description | |---------|-----------| | **Profile** |

Un objet [`AdaptyProfile`](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.

Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.

| :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: implement-observer-mode-android --- --- title: "Implémenter le mode Observer dans le SDK Android" description: "Implémentez le mode Observer dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Android." --- Si vous avez déjà votre propre infrastructure d'achats et n'êtes pas encore prêt à passer entièrement à Adapty, vous pouvez explorer le [mode Observer](observer-vs-full-mode). Dans sa forme de base, le mode Observer offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analyse. Si cela répond à vos besoins, vous devez uniquement : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk). 2. [Signaler les transactions](report-transactions-observer-mode-android) depuis votre infrastructure d'achats existante à Adapty. ## Configuration du mode Observer \{#observer-mode-setup\} Activez le mode Observer si vous gérez vous-même les achats et l'état des abonnements, et que vous utilisez Adapty pour envoyer des événements d'abonnement et des analyses. :::important En mode Observer, le SDK Adapty ne clôture aucune transaction — assurez-vous donc de les gérer vous-même. ::: ```kotlin showLineNumbers class MyApplication : Application() { override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObserverMode(true) //default false .build() ) } ``` ```java showLineNumbers public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Adapty.activate( applicationContext, new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObserverMode(true) //default false .build() ); } ``` Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | observerMode | Valeur booléenne qui contrôle le [mode Observer](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observer \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observer. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls Remote Config](present-remote-config-paywalls-android). Pour les paywalls Paywall Builder, suivez les guides de configuration spécifiques pour [Android](android-present-paywall-builder-paywalls-in-observer-mode). 3. [Associez les paywalls](report-transactions-observer-mode-android) aux transactions d'achat. --- # File: report-transactions-observer-mode-android --- --- title: "Signaler les transactions en Observer Mode dans le SDK Android" description: "Signalez les transactions d'achat en Adapty Observer Mode pour les informations utilisateurs et le suivi des revenus dans le SDK Android." --- En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela relie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```kotlin showLineNumbers val transactionInfo = TransactionInfo.fromPurchase(purchase) Adapty.reportTransaction(transactionInfo, variationId) { result -> if (result is AdaptyResult.Success) { // success } } ``` Paramètres : | Paramètre | Présence | Description | | --------------- | --------- | ------------------------------------------------------------ | | transactionInfo | obligatoire | Le TransactionInfo issu de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | optionnel | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | ```java showLineNumbers TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase); Adapty.reportTransaction(transactionInfo, variationId, result -> { if (result instanceof AdaptyResult.Success) { // success } }); ``` Paramètres : | Paramètre | Présence | Description | | --------------- | --------- | ------------------------------------------------------------ | | transactionInfo | obligatoire | Le TransactionInfo issu de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | optionnel | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store ou les restaurer. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `restorePurchases` pour signaler la transaction à Adapty. :::warning **Ne sautez pas la restauration des achats !** Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, associez votre transaction au paywall qui a conduit à l'achat via la méthode `setVariationId`. Cela garantit que l'achat est correctement attribué au paywall déclencheur pour des analyses précises. Cette étape n'est nécessaire que si vous utilisez des paywalls Adapty. ```kotlin showLineNumbers Adapty.restorePurchases { result -> if (result is AdaptyResult.Success) { // success } } Adapty.setVariationId(transactionId, variationId) { error -> if (error == null) { // success } } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | obligatoire | Identifiant string (`purchase.getOrderId`) de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | ```java showLineNumbers Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { // success } }); Adapty.setVariationId(transactionId, variationId, error -> { if (error == null) { // success } }); ``` Paramètres : | Paramètre | Présence | Description | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | obligatoire | Identifiant string (`purchase.getOrderId`) de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | **Signalement des transactions** Utilisez `restorePurchases` pour signaler une transaction à Adapty en Observer Mode, comme expliqué sur la page [Restaurer les achats dans le code mobile](android-restore-purchase). :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: **Association des paywalls aux transactions** Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous comptez utiliser des paywalls et/ou des tests A/B en Observer Mode, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de faire cela correctement avant de publier votre application, sinon cela entraînera des erreurs dans les analyses. ```kotlin Adapty.setVariationId(transactionId, variationId) { error -> if (error == null) { // success } } ``` Paramètres de la requête : | Paramètre | Présence | Description | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | obligatoire | Identifiant string (purchase.getOrderId de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | ```java Adapty.setVariationId(transactionId, variationId, error -> { if (error == null) { // success } }); ``` | Paramètre | Présence | Description | | ------------------------------------------------- | --------- | ------------------------------------------------------------ | | transactionId | obligatoire | Identifiant string (purchase.getOrderId de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. | | variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | --- # File: android-present-paywall-builder-paywalls-in-observer-mode --- --- title: "Présenter les paywalls du Paywall Builder en mode Observer dans le SDK Android" description: "Découvrez comment présenter les paywalls en mode observer avec le Paywall Builder d'Adapty." --- Si vous avez créé un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas besoin de vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez plutôt la rubrique [Android - Afficher les flows et paywalls](android-present-paywalls). :::
Avant de commencer à afficher des flows (cliquez pour développer) 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à votre framework [pour Android](sdk-installation-android). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement) dans l'Adapty Dashboard. 6. [Récupérez les flows et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.

1. Implémentez l'`AdaptyUiObserverModeHandler`. L'événement `onPurchaseInitiated` vous informe que l'utilisateur a lancé un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback : ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, flow, flowView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, flow, flowView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` Pour gérer les restaurations en mode Observer, surchargez `getRestoreHandler()`. Par défaut, il retourne `null`, ce qui utilise le flow intégré `Adapty.restorePurchases()` d'Adapty. Pour fournir votre propre implémentation de restauration : ```kotlin showLineNumbers val observerModeHandler = object : AdaptyUiObserverModeHandler { // onPurchaseInitiated implementation (see above) override fun getRestoreHandler() = AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore -> onStartRestore() yourBillingClient.restorePurchases( onSuccess = { restoredPurchases -> onFinishRestore() //handle successful restore }, onError = { onFinishRestore() //handle error } ) } } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() { // onPurchaseInitiated implementation (see above) @Override public RestoreHandler getRestoreHandler() { return (onStartRestore, onFinishRestore) -> { onStartRestore.invoke(); yourBillingClient.restorePurchases( restoredPurchases -> { onFinishRestore.invoke(); //handle successful restore }, error -> { onFinishRestore.invoke(); //handle error } ); }; } }; ``` N'oubliez pas d'appeler les callbacks suivants pour notifier AdaptyUI de l'avancement du processus d'achat ou de restauration. Cela est nécessaire pour le bon fonctionnement du flow, notamment pour l'affichage du chargement : | Callback | Description | | :----------------- |:---------------------------------------------------------------------------------------------------------------| | onStartPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration est terminée. | 2. Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement le `AdaptyFlowView` : ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml ... flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler); ``` ```xml showLineNumbers ``` Après la création réussie de la vue, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher. Pour ce faire, utilisez cette fonction composable : ```kotlin showLineNumbers AdaptyFlowScreen( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) ``` Paramètres de la requête : | Paramètre | Présence | Description | |---------|--------|-----------| | **flowConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow. Utilisez la méthode `AdaptyUI.getFlowConfiguration(flow)` pour le charger. Consultez la rubrique [Récupérer la configuration de la vue](android-get-pb-paywalls#fetch-the-view-configuration) pour plus de détails. | | **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupèrera automatiquement les produits requis. | | **eventListener** | optionnel | Fournissez un `AdaptyFlowEventListener` pour observer les événements du flow. L'extension de `AdaptyFlowDefaultEventListener` est recommandée pour faciliter l'utilisation. Consultez la rubrique [Gérer les événements de flow et de paywall](android-handling-events) pour plus de détails. | | **insets** | optionnel | Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués derrière les barres système. Par défaut : `Unspecified`, ce qui laisse Adapty ajuster les insets automatiquement. Voir [Modifier les insets du flow](android-present-paywalls#change-flow-insets). | | **customAssets** | optionnel | Passez un objet `AdaptyCustomAssets` pour remplacer les images et vidéos de votre flow ou paywall au moment de l'exécution. Consultez [Personnaliser les assets](android-get-pb-paywalls#customize-assets) pour plus de détails. | | **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du flow. Ce resolver prend un paramètre de balise et le résout en chaîne de caractères correspondante. Consultez la rubrique Balises personnalisées dans le Paywall Builder pour plus de détails. | | **observerModeHandler** | obligatoire pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. | :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode-android). Sinon, Adapty ne pourra pas déterminer le flow source de l'achat. :::
Avant de commencer à présenter des paywalls (Cliquez pour développer) 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à chaque framework [pour Android](sdk-installation-android). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des paywalls, assignez-leur des produits](create-paywall) et personnalisez-les à l'aide du Paywall Builder dans l'Adapty Dashboard. 5. [Créez des placements et assignez-y vos paywalls](create-placement) dans l'Adapty Dashboard. 6. [Récupérez les paywalls Paywall Builder et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.

1. Implémentez `AdaptyUiObserverModeHandler`. L'événement `onPurchaseInitiated` vous informe que l'utilisateur a initié un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback : ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` Pour gérer les restaurations en mode Observer, surchargez `getRestoreHandler()`. Par défaut, elle retourne `null`, ce qui utilise le flow intégré d'Adapty `Adapty.restorePurchases()`. Pour fournir votre propre implémentation de restauration : ```kotlin showLineNumbers val observerModeHandler = object : AdaptyUiObserverModeHandler { // onPurchaseInitiated implementation (see above) override fun getRestoreHandler() = AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore -> onStartRestore() yourBillingClient.restorePurchases( onSuccess = { restoredPurchases -> onFinishRestore() //handle successful restore }, onError = { onFinishRestore() //handle error } ) } } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() { // onPurchaseInitiated implementation (see above) @Override public RestoreHandler getRestoreHandler() { return (onStartRestore, onFinishRestore) -> { onStartRestore.invoke(); yourBillingClient.restorePurchases( restoredPurchases -> { onFinishRestore.invoke(); //handle successful restore }, error -> { onFinishRestore.invoke(); //handle error } ); }; } }; ``` N'oubliez pas d'invoquer les callbacks suivants pour notifier AdaptyUI du processus d'achat ou de restauration. Ceci est nécessaire pour un comportement correct du paywall, comme l'affichage du chargeur : | Callback | Description | | :----------------- |:---------------------------------------------------------------------------------------------------| | onStartPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration est terminée. | 2. Pour afficher le paywall visuel à l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement `AdaptyPaywallView` : ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler, ) ``` ```kotlin showLineNumbers val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { showPaywall( viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler ); ``` ```java showLineNumbers AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.showPaywall(viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler); ``` ```xml showLineNumbers ``` Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher. Pour ce faire, utilisez cette fonction composable : ```kotlin showLineNumbers AdaptyPaywallScreen( viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, ) ``` Paramètres de la requête : | Paramètre | Présence | Description | |---------|--------|-----------| | **Products** | optionnel | Fournissez un tableau d'`AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupère automatiquement les produits requis. | | **ViewConfiguration** | requis | Fournissez un objet `AdaptyViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. | | **EventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour simplifier l'utilisation. Consultez la rubrique [Gestion des événements du paywall](android-handling-events) pour plus de détails. | | **PersonalizedOfferResolver** | optionnel | Pour indiquer une tarification personnalisée ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et transmettez votre propre logique qui associe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. | | **TagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le transforme en chaîne correspondante. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | | **ObserverModeHandler** | requis pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. | | **variationId** | requis | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | | **transaction** | requis |

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

Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).

Pour Android : l'identifiant de type String (`purchase.getOrderId()`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.

|
Avant de commencer à afficher les paywalls (Cliquez pour développer) 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à chaque framework [pour Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk) et [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des paywalls, associez-leur des produits](create-paywall) et personnalisez-les à l'aide du Paywall Builder dans l'Adapty Dashboard. 5. [Créez des placements et associez-leur vos paywalls](create-placement) dans l'Adapty Dashboard. 6. [Récupérez les paywalls créés avec le Paywall Builder et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.
1. Implémentez `AdaptyUiObserverModeHandler`. Le callback de `AdaptyUiObserverModeHandler` (`onPurchaseInitiated`) vous informe lorsqu'un utilisateur initie un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback de la façon suivante : ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` Également, n'oubliez pas d'appeler ces callbacks sur AdaptyUI. Cela est nécessaire pour le bon fonctionnement du paywall, comme l'affichage du chargeur, entre autres : | Callback en Kotlin | Callback en Java | Description | | :----------------- | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------- | | onStartPurchase() | onStartPurchase.invoke() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | onFinishPurchase.invoke() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat s'est terminé avec succès, a échoué ou a été annulé. | 2. Pour afficher le paywall visuel, vous devez d'abord l'initialiser. Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement l'`AdaptyPaywallView` : ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), eventListener, personalizedOfferResolver, tagResolver, observerModeHandler, ) //======= OR ======= val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { setEventListener(eventListener) setObserverModeHandler(observerModeHandler) showPaywall( viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), personalizedOfferResolver, tagResolver, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), eventListener, personalizedOfferResolver, tagResolver, observerModeHandler ); //======= OR ======= AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.setEventListener(eventListener); paywallView.setObserverModeHandler(observerModeHandler); paywallView.showPaywall(viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), personalizedOfferResolver); ``` ```xml showLineNumbers ``` Après la création réussie de la vue, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher. Paramètres de la requête : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Products** | optionnel | Fournissez un tableau d'`AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupèrera automatiquement les produits requis. | | **ViewConfiguration** | requis | Fournissez un objet `AdaptyViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. | | **Insets** | requis | Définissez un objet `AdaptyPaywallInsets` contenant les informations sur la zone chevauchée par les barres système, créant ainsi des marges verticales pour le contenu. Si ni la barre de statut ni la barre de navigation ne chevauchent l'`AdaptyPaywallView`, passez `AdaptyPaywallInsets.NONE`. En mode plein écran où les barres système chevauchent une partie de votre interface, obtenez les insets comme indiqué sous le tableau. | | **EventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gestion des événements du paywall](android-handling-events) pour plus de détails. | | **PersonalizedOfferResolver** | optionnel | Pour indiquer une tarification personnalisée ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et passez votre propre logique qui associe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. | | **TagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique Custom tags in Paywall Builder pour plus de détails. | | **ObserverModeHandler** | requis pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. | | **variationId** | requis | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). | | **transaction** | requis |

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

Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).

Pour Android : l'identifiant de chaîne (`purchase.getOrderId()`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.

| Pour le mode plein écran où les barres système chevauchent une partie de votre interface, obtenez les insets de la manière suivante : ```kotlin showLineNumbers import androidx.core.graphics.Insets import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view paywallView.onReceiveSystemBarsInsets { insets -> val paywallInsets = AdaptyPaywallInsets.of(insets.top, insets.bottom) paywallView.setEventListener(eventListener) paywallView.setObserverModeHandler(observerModeHandler) paywallView.showPaywall(viewConfig, products, paywallInsets, personalizedOfferResolver, tagResolver) } ``` ```java showLineNumbers import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; ... ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(paywallView, null); AdaptyPaywallInsets paywallInsets = AdaptyPaywallInsets.of(systemBarInsets.top, systemBarInsets.bottom); paywallView.setEventListener(eventListener); paywallView.setObserverModeHandler(observerModeHandler); paywallView.showPaywall(viewConfiguration, products, paywallInsets, personalizedOfferResolver, tagResolver); return insets; }); ``` Returns: | Objet | Description | | :------------------ | :------------------------------------------------- | | `AdaptyPaywallView` | Objet représentant l'écran de paywall demandé. | :::warning N'oubliez pas d'[Associer les paywalls aux transactions d'achat](report-transactions-observer-mode-android). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. :::
--- # File: android-troubleshoot-purchases --- --- title: "Troubleshoot purchases in Android SDK" description: "Troubleshoot purchases in Android SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Android. ## makePurchase est appelé avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et son statut d'abonnement ne sont pas mis à jour dans Adapty. **Raison** : Cela indique généralement une configuration incomplète du Google Play Store. **Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android). ## makePurchase est appelé deux fois \{#makepurchase-is-invoked-twice\} **Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat. **Raison** : Cela se produit généralement lorsque le flow d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur. **Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android). ## AdaptyError.cantMakePayments en mode observer \{#adaptyerror-cantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` lors de l'utilisation de `makePurchase` en mode observer. **Raison** : En mode observer, vous devez gérer les achats de votre côté, et non utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observer. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observer. Consultez [Implémenter le mode Observer](implement-observer-mode-android) pour plus de détails. ## Erreur 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\} **Problème** : Vous recevez une erreur de facturation indisponible depuis le Google Play Store. **Raison** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil. **Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Gérer les codes de réponse BillingResult](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui ne sont pas trouvés. **Raison** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de fin d'achat liés au sandbox. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés aux achats non couverts ci-dessus. **Solution** : Mettez à jour le SDK vers la dernière version à l'aide des [guides de migration](android-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: android-user --- --- title: "Utilisateurs & accès dans le SDK Android" description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application Android avec le SDK Adapty." --- --- # File: android-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK Android" description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées (Android)." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera transmise à toutes les intégrations. ### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur au moment de la configuration, passez-le simplement en tant que paramètre `customerUserId` à la méthode `.activate()` : ```kotlin showLineNumbers Adapty.activate(applicationContext, "PUBLIC_SDK_KEY", customerUserId = "YOUR_USER_ID") ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous ne disposez pas d'un identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'utilisation les plus courants sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié. ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> if (error == null) { // successful identify } } ``` ```java showLineNumbers Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` Paramètres de la requête : - **Customer User ID** (obligatoire) : un identifiant utilisateur de type chaîne de caractères. :::warning Resoumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces scénarios, le SDK Adapty basculera automatiquement pour travailler avec le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, telles que des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez resoumettre ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```kotlin showLineNumbers Adapty.logout { error -> if (error == null) { // successful logout } } ``` ```java showLineNumbers Adapty.logout(error -> { if (error == null) { // successful logout } }); ``` Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`. ### Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: android-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK Android" description: "Apprenez à définir les attributs utilisateur dans Adapty pour améliorer la segmentation des audiences." --- Vous pouvez définir des attributs facultatifs tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` : ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.OTHER) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } ``` ```java showLineNumbers AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.OTHER) .withBirthday(new AdaptyProfile.Date(1970, 1, 3)); Adapty.updateProfile(builder.build(), error -> { if (error != null) { // handle the error } }); ``` Notez que les attributs que vous avez précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés `` autorisées pour `AdaptyProfileParameters.Builder` et les valeurs `` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| |

email

phoneNumber

firstName

lastName

| String | | gender | Enum, les valeurs autorisées sont : `female`, `male`, `other` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, ainsi que dans les analyses pour déterminer quelles métriques produit ont le plus d'impact sur les revenus. ```kotlin showLineNumbers builder.withCustomAttribute("key1", "value1") ``` ```java showLineNumbers builder.withCustomAttribute("key1", "value1"); ``` Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` : ```kotlin showLineNumbers builder.withRemovedCustomAttribute("key2") ``` ```java showLineNumbers builder.withRemovedCustomAttribute("key2"); ``` Il peut arriver que vous ayez besoin de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut être obsolète, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment. Les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clés peuvent comporter jusqu'à 30 caractères. Ils peuvent contenir des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre flottant, avec 50 caractères maximum. --- # File: android-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK Android" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Android." --- Avec Adapty, suivre le statut d'abonnement est simple. Inutile d'insérer manuellement des identifiants de produits dans votre code. Il suffit de vérifier l'existence d'un [niveau d'accès](access-level) actif pour confirmer le statut d'abonnement d'un utilisateur. Avant de commencer à vérifier le statut d'abonnement, configurez les [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn). ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Nous recommandons de récupérer le profil au démarrage de l'application, par exemple lors de l'[identification d'un utilisateur](android-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque changement. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander constamment. Pour être notifié des mises à jour du profil, écoutez les changements comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](android-listen-subscription-changes) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // check the access } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` Paramètres de la réponse : | Paramètre | Description | | --------- | ------------------------------------------------------------ | | Profile |

Un objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.

La méthode `.getProfile` fournit le résultat le plus récent, car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données en cache sont renvoyées. Il est également important de noter que le SDK Adapty met régulièrement à jour le cache `AdaptyProfile` afin de maintenir ces informations aussi récentes que possible.

| La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Une application peut avoir plusieurs niveaux d'accès. Par exemple, si vous avez une application d'actualités et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer les niveaux d'accès « sports » et « science ». La plupart du temps, cependant, un seul niveau d'accès suffit — dans ce cas, utilisez simplement le niveau d'accès par défaut « premium ». Voici un exemple de vérification du niveau d'accès « premium » par défaut : ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("premium"); if (premium != null && premium.isActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir les messages d'Adapty, une configuration supplémentaire est nécessaire : ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` ```java showLineNumbers t Adapty.setOnProfileUpdatedListener(profile -> { // handle any changes to subscription state }); ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil. Il est cependant important de noter que les données ne peuvent pas être demandées directement depuis le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier s'il y a des mises à jour ou des changements liés au profil. Le cas échéant, les modifications — comme de nouvelles transactions ou d'autres mises à jour — sont transmises aux données en cache afin de les maintenir synchronisées avec le serveur. --- # File: kids-mode-android --- --- title: "Mode Enfants dans le SDK Android" description: "Activez facilement le Mode Enfants pour respecter les politiques Google. Ni GAID ni données publicitaires collectées dans le SDK Android." --- Si votre application Android est destinée aux enfants, vous devez suivre les politiques de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour respecter ces politiques et passer les revues de l'app store. ## Ce qui est requis \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte : - de l'[Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) - de l'[adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `` sera immanquablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activation du Mode Enfants \{#enabling-kids-mode\} ### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, vous devez désactiver la collecte de l'Android Advertising ID (AAID/GAID) et de l'adresse IP lors de l'initialisation du SDK Adapty : **Kotlin :** ```kotlin showLineNumbers override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() ) } ``` **Java :** ```java showLineNumbers @Override public void onCreate() { super.onCreate(); Adapty.activate( applicationContext, new AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() ); } ``` ### Modifications dans votre manifeste Android \{#updates-in-your-android-manifest\} :::note Si votre application cible **uniquement** les enfants et se compile avec Android 13 (API 33) ou supérieur, Google Play exige que vous ne demandiez pas la permission `AD_ID`. Un autre SDK dans votre application (analytics, attribution ou publicité) peut ajouter cette permission via la fusion de manifestes. Définir `withAdIdCollectionDisabled(true)` empêche Adapty de collecter l'identifiant, mais ne supprime pas une permission déclarée par un autre SDK. ::: Pour supprimer la permission, ajoutez ce qui suit à l'intérieur de l'élément `` du fichier `app/src/main/AndroidManifest.xml`. L'élément `` doit déclarer `xmlns:tools="http://schemas.android.com/tools"`. ```xml showLineNumbers title="AndroidManifest.xml" ``` --- # File: android-onboardings --- --- title: "Onboardings dans le SDK Android" description: "Découvrez comment travailler avec les onboardings dans votre application Android avec le SDK Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une apparence Android cohérente, des temps de chargement plus rapides et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour commencer. ::: --- # File: android-get-onboardings --- --- title: "Récupérer les onboardings dans le SDK Android" description: "Apprenez à récupérer les onboardings dans Adapty pour Android." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu cohérent avec Android, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Récupérer les flows et paywalls](android-get-pb-paywalls) et [Afficher les flows et paywalls](android-present-paywalls) pour démarrer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Android. La première étape consiste à récupérer l'onboarding associé au placement et sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'intégralité de l'expérience : quel contenu s'affiche, comment il est présenté et comment les interactions utilisateur (comme les réponses à un quiz ou les saisies de formulaire) sont traitées. Le conteneur suit également automatiquement les événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi séparé des vues. Pour de meilleures performances, récupérez la configuration de l'onboarding tôt afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher aux utilisateurs. Pour récupérer un onboarding, utilisez la méthode `getOnboarding` : ```kotlin showLineNumbers Adapty.getOnboarding("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // the requested onboarding } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** |

optionnel

par défaut : `en`

|

L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.

| | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc safe de l'utiliser pendant la session pour éviter des requêtes réseau.

Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.

Le SDK Adapty stocke les onboardings localement sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système garantit que vous obtenez toujours la dernière version de vos onboardings, même en cas de connexion internet limitée.

| | **loadTimeout** | par défaut : 5 s |

Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.

Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer plusieurs requêtes en interne.

Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.

| Paramètres de la réponse : | Paramètre | Description | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://android.adapty.io/adapty/com.adapty.models/-adapty-onboarding/) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config et plusieurs autres propriétés. | ## Accélérer la récupération de l'onboarding avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un onboarding par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher. Pour cela, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer l'onboarding avec la méthode `getOnboarding`, comme décrit dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des difficultés lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions puissent s'afficher incorrectement. - **Aucune personnalisation** : affiche uniquement le contenu pour l'audience "All Users", sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si la récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```kotlin Adapty.getOnboardingForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // Handle successful onboarding retrieval } is AdaptyResult.Error -> { val error = result.error // Handle error case } } } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** |

optionnel

par défaut : `en`

|

L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.

Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.

Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.

| | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` |

Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.

Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc safe de l'utiliser pendant la session pour éviter des requêtes réseau.

Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.

Le SDK Adapty stocke les onboardings localement sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système garantit que vous obtenez toujours la dernière version de vos onboardings, même en cas de connexion internet limitée.

| --- # File: android-present-onboardings --- --- title: "Présenter les onboardings dans le SDK Android" description: "Apprenez à présenter les onboardings sur Android pour un engagement utilisateur efficace." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows se rendent nativement sur l'appareil — vous offrant des animations plus fluides, un look and feel Android cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir les flows et paywalls](android-get-pb-paywalls) et [Afficher les flows et paywalls](android-present-paywalls) pour commencer. ::: Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Si vous avez personnalisé un onboarding avec l'Onboarding Builder, vous n'avez pas à vous soucier de son rendu dans votre code d'application mobile pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et comment il doit l'être. Pour afficher l'onboarding visuel à l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getOnboardingView()` ou créez directement le `OnboardingView` : ```kotlin val onboardingView = AdaptyUI.getOnboardingView( activity = this, viewConfig = onboardingConfig, eventListener = eventListener ) ``` ```kotlin val onboardingView = AdaptyOnboardingView(activity) onboardingView.show( viewConfig = onboardingConfig, delegate = eventListener ) ``` ```java AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView( activity, onboardingConfig, eventListener ); ``` ```java AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity); onboardingView.show(onboardingConfig, eventListener); ``` ```xml ``` Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher à l'écran de l'appareil. Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **viewConfig** | requis | La configuration d'onboarding obtenue depuis `AdaptyUI.getOnboardingConfiguration()` | | **eventListener** | requis | Une implémentation de `AdaptyOnboardingEventListener` pour gérer les événements d'onboarding. Consultez [Gestion des événements d'onboarding](android-handle-onboarding-events) pour plus de détails. | ## Modifier la couleur de l'indicateur de chargement \{#change-loading-indicator-color\} Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante : ```xml ``` ## Ajouter des transitions fluides entre l'écran de démarrage et l'onboarding \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\} Par défaut, entre l'écran de démarrage et l'onboarding, vous verrez l'écran de chargement jusqu'à ce que l'onboarding soit entièrement chargé. Si vous souhaitez rendre la transition plus fluide, vous pouvez la personnaliser et soit prolonger l'écran de démarrage, soit afficher autre chose. Pour ce faire, créez `adapty_onboarding_placeholder_view.xml` dans `res/layout` et définissez-y un placeholder (ce qui sera affiché pendant le chargement de l'onboarding). Si vous définissez un placeholder, l'onboarding sera chargé en arrière-plan et affiché automatiquement une fois prêt. ## Désactiver les marges de zone sécurisée \{#disable-safe-area-paddings\} Par défaut, la vue d'onboarding applique automatiquement des marges de zone sécurisée pour éviter les éléments d'interface système comme la barre d'état et la barre de navigation. Si vous souhaitez désactiver ce comportement et avoir un contrôle total sur la mise en page, vous pouvez le faire en définissant le paramètre `safeAreaPaddings` sur `false`. ```kotlin val onboardingView = AdaptyUI.getOnboardingView( activity = this, viewConfig = onboardingConfig, eventListener = eventListener, safeAreaPaddings = false ) ``` ```kotlin val onboardingView = AdaptyOnboardingView(activity) onboardingView.show( viewConfig = onboardingConfig, delegate = eventListener, safeAreaPaddings = false ) ``` ```java AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView( activity, onboardingConfig, eventListener, false ); ``` ```java AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity); onboardingView.show(onboardingConfig, eventListener, false); ``` Vous pouvez également contrôler ce comportement globalement en ajoutant une ressource booléenne à votre application : ```xml false ``` Lorsque `safeAreaPaddings` est défini sur `false`, l'onboarding s'étend sur tout l'écran sans ajustement automatique des marges, vous donnant un contrôle total sur la mise en page et permettant au contenu de l'onboarding d'utiliser tout l'espace de l'écran. ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15.1. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web au sein de votre application, permettant aux utilisateurs de les consulter sans changer d'application. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `AdaptyWebPresentation.ExternalBrowser` : ```kotlin val onboardingConfig = AdaptyUI.getOnboardingConfiguration( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser ) ``` ```java AdaptyOnboardingConfiguration onboardingConfig = AdaptyUI.getOnboardingConfiguration( onboarding, AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser ); ``` --- # File: android-handle-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK Android" description: "Gérez les événements liés à l'onboarding sous Android avec Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une apparence cohérente avec Android, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour commencer. ::: Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Découvrez comment y répondre ci-dessous. Pour contrôler ou surveiller les processus qui se produisent sur l'écran d'onboarding dans votre application Android, implémentez l'interface `AdaptyOnboardingEventListener`. ## Actions personnalisées \{#custom-actions\} Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un ID. Vous pouvez ensuite utiliser cet ID dans votre code et le traiter comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé comme **Login** ou **Allow notifications**, la méthode delegate `onCustomAction` sera déclenchée avec l'ID d'action défini dans le builder. Vous pouvez créer vos propres IDs, comme « allowNotifications ». ```kotlin showLineNumbers class YourActivity : AppCompatActivity() { private val eventListener = object : AdaptyOnboardingEventListener { override fun onCustomAction(action: AdaptyOnboardingCustomAction, context: Context) { when (action.actionId) { "allowNotifications" -> { // Request notification permissions } } } override fun onError(error: AdaptyOnboardingError, context: Context) { // Handle errors } // ... other required delegate methods } } ```
Exemple d'événement (Cliquer pour développer) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
## Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton avec l'action **Close** assignée. Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple : :::important Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: Par exemple : ```kotlin override fun onCloseAction(action: AdaptyOnboardingCloseAction, context: Context) { // Dismiss the onboarding screen (context as? Activity)?.onBackPressed() } ```
Exemple d'événement (Cliquer pour développer) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
## Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall si vous souhaitez l'afficher à l'intérieur de l'onboarding. Si vous voulez ouvrir un paywall après sa fermeture, il existe une approche plus directe — gérez [`AdaptyOnboardingCloseAction`](#closing-onboarding) et ouvrez le paywall sans vous appuyer sur les données de l'événement. ::: La manière la plus fluide de travailler avec les paywalls dans les onboardings est de rendre l'ID d'action égal à l'ID de placement du paywall. Ainsi, après l'`AdaptyOnboardingOpenPaywallAction`, vous pouvez utiliser l'ID de placement pour récupérer et ouvrir le paywall directement : ```kotlin override fun onOpenPaywallAction(action: AdaptyOnboardingOpenPaywallAction, context: Context) { // Get the paywall using the placement ID from the action Adapty.getPaywall(placementId = action.actionId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Get the paywall configuration AdaptyUI.getViewConfiguration(paywall) { result -> when(result) { is AdaptyResult.Success -> { val paywallConfig = result.value // Create and present the paywall val paywallView = AdaptyUI.getPaywallView( activity = this, viewConfig = paywallConfig, products, eventListener = paywallEventListener ) // Add the paywall view to your layout binding.container.addView(paywallView) } is AdaptyResult.Error -> { val error = result.error // handle the error } } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } } ```
Exemple d'événement (Cliquer pour développer) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Lorsqu'un onboarding termine son chargement, cette méthode est invoquée : ```kotlin override fun onFinishLoading(action: AdaptyOnboardingLoadedAction, context: Context) { // Handle loading completion } ```
Exemple d'événement (Cliquer pour développer) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
## Événements de navigation \{#navigation-events\} La méthode `onAnalyticsEvent` est appelée lorsque différents événements analytiques se produisent au cours du flow d'onboarding. L'objet `event` peut être de l'un des types suivants : |Type | Description | |------------|-------------| | `OnboardingStarted` | Lorsque l'onboarding a été chargé | | `ScreenPresented` | Lorsqu'un écran est affiché | | `ScreenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque les utilisateurs effectuent une action pour quitter l'écran. | | `SecondScreenPresented` | Lorsque le deuxième écran est affiché | | `UserEmailCollected` | Déclenché lorsque l'adresse e-mail de l'utilisateur est collectée via le champ de saisie | | `OnboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, attribuez l'ID `final` au dernier écran. | | `Unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `totalScreens` | Nombre total d'écrans dans le flow | Voici un exemple d'utilisation des événements analytiques pour le suivi : ```kotlin override fun onAnalyticsEvent(event: AdaptyOnboardingAnalyticsEvent, context: Context) { when (event) { is AdaptyOnboardingAnalyticsEvent.OnboardingStarted -> { // Track onboarding start trackEvent("onboarding_started", event.meta) } is AdaptyOnboardingAnalyticsEvent.ScreenPresented -> { // Track screen presentation trackEvent("screen_presented", event.meta) } is AdaptyOnboardingAnalyticsEvent.ScreenCompleted -> { // Track screen completion with user response trackEvent("screen_completed", event.meta, event.elementId, event.reply) } is AdaptyOnboardingAnalyticsEvent.OnboardingCompleted -> { // Track successful onboarding completion trackEvent("onboarding_completed", event.meta) } is AdaptyOnboardingAnalyticsEvent.Unknown -> { // Handle unknown events trackEvent(event.name, event.meta) } // Handle other cases as needed } } ```
Exemples d'événements (Cliquer pour développer) ```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: android-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK Android" description: "Enregistrez et utilisez les données des onboardings dans votre application Android avec le SDK Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu Android cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour démarrer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```kotlin override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Store user preferences or responses when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Select -> { // Handle single selection } is AdaptyOnboardingStateUpdatedParams.MultiSelect -> { // Handle multiple selections } is AdaptyOnboardingStateUpdatedParams.Input -> { // Handle text input } is AdaptyOnboardingStateUpdatedParams.DatePicker -> { // Handle date selection } } } ``` Consultez le format de l'action [ici](https://android.adapty.io/adapty-ui/com.adapty.ui.onboardings.actions/-adapty-onboarding-state-updated-action/).
Exemples de données enregistrées (le format peut différer selon votre implémentation) ```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 } } } ```
## Cas d'usage \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](android-setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans votre code, cela peut ressembler à ceci : ```kotlin showLineNumbers override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Store user preferences or responses when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Input -> { // Handle text input val builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field when (action.elementId) { "name" -> { when (val inputParams = params.params) { is AdaptyOnboardingInputParams.Text -> { builder.withFirstName(inputParams.value) } } } "email" -> { when (val inputParams = params.params) { is AdaptyOnboardingInputParams.Email -> { builder.withEmail(inputParams.value) } } } } Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } } } } ``` ### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\} Grâce aux quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et attribuez des IDs significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](android-setting-user-attributes) pour les utilisateurs. ```kotlin showLineNumbers override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Handle quiz responses and set custom attributes when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Select -> { // Handle quiz selection val builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes when (action.elementId) { "experience" -> { // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.withCustomAttribute("experience", params.params.value) } } Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } } } } ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](android-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall comme [réponse à l'action de ce bouton](android-handle-onboarding-events#opening-a-paywall). --- # File: android-best-practices --- --- title: "Bonnes pratiques avec le SDK Android" description: "Modèles de référence pour intégrer le SDK Adapty sur Android — ordre des appels, gestion des erreurs et autres règles de préparation à la production." --- --- # File: android-sdk-call-order --- --- title: "Ordre des appels dans le SDK Android" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs ADAPTY_NOT_INITIALIZED intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre." --- `Adapty.activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant qu'il n'est pas terminé, le SDK n'a aucun état. Tout appel émis avant ou en parallèle de `activate()` échoue avec [`ADAPTY_NOT_INITIALIZED`](android-sdk-error-handling). Si votre application authentifie les utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty.identify()` à ce moment-là. N'appelez pas de méthodes liées aux actions utilisateur avant que le callback de fin d'`identify` ne se déclenche. Les appels qui s'exécutent en concurrence avec lui retournent soit une erreur dans leur callback, soit atterrissent sur le profil anonyme créé à l'activation. Dans ce cas, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et d'analytique (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## Le bon ordre \{#the-correct-order\} Votre parcours dépend de deux éléments : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou d'analytique. - **Étapes 2 et 5** : Obligatoires pour toutes les applications. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou d'analytique (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et récupère l'identifiant utilisateur client après le lancement. Si vous disposez de l'identifiant utilisateur client au lancement de l'application, passez-le dans `AdaptyConfig.Builder` avant d'appeler `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, l'étape 4 est donc inutile. | Étape | Appel | Quand | Notes | |-------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou d'analytique (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'app, en premier | Attendez le callback d'UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `Adapty.activate(context, AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | Lancement de l'app, après l'étape 1, si vous disposez de l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `Adapty.activate(context, AdaptyConfig.Builder("KEY").build())` sans `customerUserId` | Lancement de l'app, après l'étape 1, si vous ne disposez pas de l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` pour chaque MMP | Après l'étape 2, avant tout appel lié à une action utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. | | 4 | `Adapty.identify("YOUR_USER_ID") { error -> ... }` | Après l'étape 3 (ou l'étape 2 si pas de MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Utilisez le callback de fin. Les appels concurrents pendant `identify` peuvent atterrir sur le profil anonyme. | | 5 | `getPaywall`, `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 si pas de MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne la perte d'accès premium pour les utilisateurs existants, l'absence d'`appsflyer_id` sur les profils, et des paywalls retournés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent via un paiement web (Stripe, Paddle) et installent ensuite l'application native, le premier `activate()` de l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flux d'authentification ou le referrer d'installation), passez-le directement dans `AdaptyConfig.Builder`. Sinon, l'achat web est invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque paiement web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: android-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK Android" description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour Android." --- Une récupération fiable de paywall sur Android repose sur trois éléments : un affichage rapide, le renvoi du paywall ciblé par audience, et un repli gracieux lorsque le réseau est lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir. :::tip Ces règles supposent que `Adapty.activate()` et `Adapty.identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK Android](android-sdk-call-order). ::: ## Règles et pièges à éviter \{#rules-and-pitfalls\} | À faire | À éviter | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements en parallèle au démarrage. | Le pré-chargement en masse bloque le thread principal et provoque un écran noir pendant le pic de requêtes. | | Appelez `getPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `setOnProfileUpdatedListener`. | Appeler `getPaywall` dans `Application.onCreate()`. | L'attribution n'est pas encore disponible. Le paywall se résout contre l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment que `getPaywall` réponde. | Sans timeout, les utilisateurs avec une mauvaise connexion voient un écran vide jusqu'à ce que le réseau réponde — ou ferment l'application. | Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products-android) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour les connexions lentes \{#tune-for-poor-connectivity\} Pour les marchés avec des connexions régulièrement mauvaises (zones rurales, transports, régions touchées par des problèmes de routage) : - Définissez `fetchPolicy` sur `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour chaque récupération, sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le timeout se déclenche. - Ne conditionnez pas l'affichage du paywall à `getProfile`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: android-test --- --- title: "Tester et publier avec le SDK Android" description: "Découvrez comment vérifier le statut d'abonnement dans votre application Android avec Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application Android, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox de Google Play. ## Tester votre application \{#test-your-app\} Pour tester vos achats intégrés de manière exhaustive, notamment les tests en sandbox et la validation des pistes fermées, consultez notre [guide de test](testing-on-android). ## Préparer la publication \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [checklist de publication](release-checklist) pour confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats sont finalisés et remontés à Adapty - L'accès est débloqué et restauré correctement - Les exigences en matière de confidentialité et de révision sont respectées --- # File: android-reference --- --- title: "Référence pour le SDK Android" description: "Documentation de référence pour le SDK Android Adapty." --- Cette page contient la documentation de référence pour le SDK Android Adapty. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://android.adapty.io)** - Modèles de données et structures utilisés par le SDK - **[Gestion des erreurs](android-sdk-error-handling)** - Gestion des erreurs et résolution des problèmes --- # File: android-sdk-error-handling --- --- title: "Gérer les erreurs dans le SDK Android" description: "Gérez efficacement les erreurs du SDK Android grâce au guide de dépannage d'Adapty." --- Chaque erreur renvoyée par le SDK est de type `AdaptyError`. :::tip **Activez les journaux détaillés avant de déboguer.** La plupart des `AdaptyError` encapsulent une erreur sous-jacente de Play Billing, du réseau ou du backend. Avec les journaux détaillés activés (`Adapty.logLevel = AdaptyLogLevel.VERBOSE` — voir [Journalisation](sdk-installation-android#logging)), cette erreur encapsulée s'affiche dans la console, ce qui indique généralement la cause réelle. ::: :::important Si ces solutions ne résolvent pas votre problème, consultez [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support afin de nous permettre de vous aider plus efficacement. ::: | Erreur | Solution | |----------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | UNKNOWN | Cette erreur indique qu'une erreur inconnue ou inattendue s'est produite. | | [ITEM_UNAVAILABLE](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_UNAVAILABLE()) | Cette erreur survient principalement en phase de test. Elle peut signifier que les produits sont absents de la production ou que l'utilisateur n'appartient pas au groupe Testeurs dans Google Play. | | ADAPTY_NOT_INITIALIZED | Le SDK Adapty n'est pas activé.
Ce cas se présente le plus souvent quand un écran de démarrage ou un hook d'interface précoce appelle des méthodes Adapty avant que `Adapty.activate` ait terminé. Le symptôme est intermittent et peut ne pas se reproduire sur un émulateur, car le timing diffère d'un appareil réel. Attendez que `Adapty.activate` soit terminé avant de planifier tout autre appel SDK. Consultez [l'ordre des appels dans le SDK Android](android-sdk-call-order) pour la séquence complète. Vous devez également [configurer le SDK Adapty](sdk-installation-android#activate-adapty-module-of-adapty-sdk) correctement à l'aide de la méthode `Adapty.activate`. | | PROFILE_WAS_CHANGED | Le profil utilisateur a été modifié pendant l'opération.
Cela se produit lorsqu'une méthode est appelée alors qu'`Adapty.identify` est encore en cours — l'appel en vol atterrit sur un profil sur le point d'être remplacé, et le SDK le rejette. Attendez qu'`Adapty.identify` soit terminé avant de planifier d'autres appels SDK. Consultez [l'ordre des appels dans le SDK Android](android-sdk-call-order). | | PRODUCT_NOT_FOUND | Cette erreur indique que le produit demandé à l'achat n'est pas disponible dans le store. | | INVALID_JSON |

Le JSON du paywall de secours local n'est pas valide.

Corrigez votre paywall anglais par défaut, puis remplacez les paywalls locaux invalides. Consultez la rubrique [Personnaliser le paywall avec Remote Config](customize-paywall-with-remote-config) pour savoir comment corriger un paywall, et [Définir les paywalls de secours locaux](fallback-paywalls) pour savoir comment remplacer les paywalls locaux.

| |

CURRENT_SUBSCRIPTION_TO_UPDATE

\_NOT_FOUND_IN_HISTORY

| L'abonnement d'origine à remplacer est introuvable dans les abonnements actifs. | | [BILLING_SERVICE_TIMEOUT](https://developer.android.com/google/play/billing/errors#service_timeout_error_code_-3) | Cette erreur indique que la requête a atteint le délai d'attente maximal avant que Google Play puisse répondre. Cela peut être dû, par exemple, à un retard dans l'exécution de l'action demandée par l'appel à la Play Billing Library. | | [FEATURE_NOT_SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED()) | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. | | [BILLING_SERVICE_DISCONNECTED](https://developer.android.com/google/play/billing/errors#service_disconnected_error_code_-1) | Cette erreur indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. | | [BILLING_SERVICE_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#service_unavailable_error_code_2) | Cette erreur indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau entre l'appareil client et les services Google Play Billing. | | [BILLING_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) |

Cette erreur indique qu'un problème de facturation s'est produit pendant le processus d'achat. Causes possibles :

1. L'application Play Store sur l'appareil de l'utilisateur est absente ou obsolète.

2. L'utilisateur se trouve dans un pays non pris en charge.

3. L'utilisateur fait partie d'un compte entreprise dont l'administrateur a désactivé les achats.

4. Google Play n'a pas pu débiter le moyen de paiement de l'utilisateur (par exemple, une carte de crédit expirée).

5. L'utilisateur n'est pas connecté à l'application Play Store.

| | [DEVELOPER_ERROR](https://developer.android.com/google/play/billing/errors#developer_error) | Cette erreur indique que vous utilisez une API de manière incorrecte. | | [BILLING_ERROR](https://developer.android.com/google/play/billing/errors#error_error_code_6) | Cette erreur indique un problème interne à Google Play lui-même. | | [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED()) | Le produit a déjà été acheté. | | [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED()) | Cette erreur indique que l'action demandée sur l'article a échoué car l'utilisateur n'en est pas propriétaire. | | [BILLING_NETWORK_ERROR](https://developer.android.com/google/play/billing/errors#network_error_error_code_12) | Cette erreur indique qu'un problème de connexion réseau s'est produit entre l'appareil et les systèmes Play. | | NO_PRODUCT_IDS_FOUND |

Cette erreur indique qu'aucun des produits du paywall n'est disponible dans le store.

Si vous rencontrez cette erreur, suivez les étapes ci-dessous pour la résoudre :

  1. Vérifiez que tous les produits ont bien été ajoutés à l'Adapty Dashboard.
  2. Assurez-vous que le **Package name** de votre application correspond à celui indiqué dans la Google Play Console.
  3. Vérifiez que les identifiants de produits des stores correspondent à ceux que vous avez ajoutés au Dashboard. Notez que les identifiants ne doivent pas contenir le Bundle ID, sauf s'il est déjà inclus dans le store.
  4. Confirmez que le statut payant de l'application est **Active** dans vos paramètres fiscaux Google. Assurez-vous que vos informations fiscales sont à jour et que vos certificats sont valides.
  5. Vérifiez qu'un compte bancaire est associé à l'application afin qu'elle puisse être éligible à la monétisation.
  6. Vérifiez si les produits sont disponibles dans votre région.
  7. Assurez-vous que votre application figure dans l'un des canaux de test. Le canal **Internal testing** est l'option la plus simple, car il ne nécessite pas de validation et garde l'application invisible pour les clients.
| | NO_PURCHASES_TO_RESTORE | Cette erreur indique que Google Play n'a trouvé aucun achat à restaurer. | | AUTHENTICATION_ERROR | Vous devez [configurer le SDK Adapty](sdk-installation-android#activate-adapty-module-of-adapty-sdk) correctement à l'aide de la méthode `Adapty.activate`. | | BAD_REQUEST | Requête incorrecte.
Assurez-vous d'avoir effectué toutes les étapes nécessaires à l'[intégration avec Google Play](google-play-store-connection-configuration). | | SERVER_ERROR | Erreur serveur. | | REQUEST_FAILED | Cette erreur indique un problème réseau qui ne peut pas être défini précisément. | | DECODING_FAILED | Nous n'avons pas pu décoder la réponse.
Vérifiez votre code et assurez-vous que les paramètres que vous envoyez sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. | | ANALYTICS_DISABLED | Nous ne pouvons pas traiter les événements d'analyse, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). | | WRONG_PARAMETER | Cette erreur indique que certains de vos paramètres sont incorrects : vide alors qu'il ne peut pas l'être, mauvais type, etc. | ## Autres problèmes \{#other-issues\} Si vous n'avez pas encore trouvé de solution, voici les prochaines étapes possibles : - **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de passer à la dernière version du SDK, car elle est plus stable et inclut des correctifs pour les problèmes connus. - **Contacter l'équipe support ou obtenir de l'aide auprès d'autres développeurs** dans le [forum d'assistance](https://adapty.featurebase.app/). - **Contacter l'équipe support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou si cela n'a pas résolu le problème, contactez notre équipe support. Notez que votre problème sera résolu plus rapidement si vous [activez la journalisation verbeuse](sdk-installation-android#logging) et partagez les logs avec l'équipe. Vous pouvez également joindre des extraits de code pertinents. --- # File: android-sdk-migration-guides --- --- title: "Guides de migration du SDK Android" description: "Guides de migration pour les versions du SDK Android Adapty." --- Cette page regroupe tous les guides de migration pour le SDK Android Adapty. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir les instructions détaillées : - **[Migrer vers la v4.0](migration-to-android-sdk-v4)** - **[Migrer vers la v3.12](migration-to-android-312)** - **[Migrer vers la v3.10](migration-to-android-310)** - **[Migrer vers la v3.4](migration-to-android-sdk-34)** - **[Migrer vers la v3.3](migration-to-android330)** - **[Migrer vers la v3.0](migration-to-android-sdk-v3)** --- # File: migration-to-android-sdk-v4 --- --- title: "Migrer le SDK Android Adapty vers la v. 4.0" description: "Migrez vers le SDK Android Adapty v4.0 en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK Android Adapty 4.0 introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucun changement de configuration n'est nécessaire côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` | | `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` | | `AdaptyUI.getViewConfiguration(paywall)` | `AdaptyUI.getFlowConfiguration(flow, locale)` | | `AdaptyUI.LocalizedViewConfiguration` | `AdaptyUI.FlowConfiguration` | | `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` | | `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` | | `AdaptyPaywall` | `AdaptyFlow` | | `AdaptyUI.getPaywallView(...)` | `AdaptyUI.getFlowView(...)` | | `AdaptyPaywallView` | `AdaptyFlowView` | | `AdaptyPaywallScreen` (Compose) | `AdaptyFlowScreen` | | `showPaywall(...)` | `showFlow(...)` | | `AdaptyPaywallInsets` | `AdaptyFlowInsets` | | `AdaptyUiEventListener` | `AdaptyFlowEventListener` | | `AdaptyUiDefaultEventListener` | `AdaptyFlowDefaultEventListener` | | `onPaywallShown` / `onPaywallClosed` | `onFlowShown` / `onFlowClosed` | | `onRenderingError` | `onError` | | `Adapty.updateAttribution(attribution, source)` (`source: String`) | `Adapty.updateAttribution(attribution, source)` (`source: AdaptyAttributionSource`) | | `Adapty.setIntegrationIdentifier(key, value)` | `Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier)` | `AdaptyPaywallProduct` garde son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` prend désormais un `AdaptyFlow`. Les autres méthodes de `AdaptyFlowEventListener` (`onProductSelected`, `onPurchaseStarted`, `onPurchaseFinished`, `onPurchaseFailure`, `onRestoreSuccess`, `onRestoreFailure`, `onActionPerformed`, `onAwaitingPurchaseParams`, `onLoadingProductsFailure`, etc.) conservent leurs noms et signatures. ## Installation \{#installation\} Définissez la version `adapty-bom` sur `4.0.1` (ou ultérieure) et synchronisez le projet. Le BOM résout automatiquement les versions correspondantes de `android-sdk` et `android-ui`. Consultez [Installer le SDK Adapty](sdk-installation-android) pour les déclarations de dépendances. ## API supprimées et dépréciées \{#removed-and-deprecated-apis\} - **`Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized, callback)`** — supprimée. Cette surcharge était dépréciée en v3. Passez les mêmes options via `AdaptyPurchaseParameters` à la place : ```diff showLineNumbers - Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized) { result -> /* ... */ } + val params = AdaptyPurchaseParameters.Builder() + .withSubscriptionUpdateParams(subscriptionUpdateParams) + .withOfferPersonalized(isOfferPersonalized) + .build() + Adapty.makePurchase(activity, product, params) { result -> /* ... */ } ``` - **Les onboardings sont obsolètes.** `AdaptyUI.getOnboardingView` et `AdaptyUI.getOnboardingConfiguration` sont marqués `@Deprecated` dans la version 4.0 — migrez vos onboardings vers des flows créés dans le [Flow Builder](adapty-flow-builder). ## Récupération des flows \{#fetching-flows\} ### getPaywall + getViewConfiguration → getFlow + getFlowConfiguration Le type de retour de la récupération passe de `AdaptyPaywall` à `AdaptyFlow`, et le chargeur de configuration est renommé de `AdaptyUI.getViewConfiguration` en `AdaptyUI.getFlowConfiguration` (retournant `AdaptyUI.FlowConfiguration` au lieu de `AdaptyUI.LocalizedViewConfiguration`). Le paramètre `locale` sort de l'appel de récupération et passe dans `getFlowConfiguration` : ```diff showLineNumbers - Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> + Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> if (result is AdaptyResult.Success) { - val paywall = result.value - if (!paywall.hasViewConfiguration) return@getPaywall - AdaptyUI.getViewConfiguration(paywall) { configResult -> + val flow = result.value + if (!flow.hasViewConfiguration) return@getFlow + AdaptyUI.getFlowConfiguration(flow, locale = "en") { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value } } } } ``` `locale` reste optionnel dans `getFlowConfiguration` : omettez-le et la vue s'affiche en `en`, ou dans la langue par défaut du flow si celui-ci ne dispose pas de `en`. Voir [Localisations et codes de langue](android-localizations-and-locale-codes). ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` prend désormais un `AdaptyFlow` retourné par `Adapty.getFlow` : ```diff showLineNumbers - Adapty.getPaywallProducts(paywall) { result -> /* products */ } + Adapty.getPaywallProducts(flow) { result -> /* products */ } ``` ### Fichiers de secours \{#fallback-files\} Le format du fichier de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le dans votre application. ## Suivi des vues de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` est renommé `logShowFlow` et prend désormais un `AdaptyFlow` à la place d'un `AdaptyPaywall`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord. ```diff showLineNumbers - Adapty.logShowPaywall(paywall) + Adapty.logShowFlow(flow) ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode pour afficher des flows ou des paywalls générés par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement. ## Afficher des flows \{#displaying-flows\} ### getPaywallView / AdaptyPaywallView → getFlowView / AdaptyFlowView Renommez la méthode factory et le type de vue, et transmettez la `AdaptyUI.FlowConfiguration` : ```diff showLineNumbers - val paywallView = AdaptyUI.getPaywallView( - activity, - viewConfiguration, - products, - eventListener, - ) + val flowView = AdaptyUI.getFlowView( + activity, + flowConfiguration, + products, + eventListener, + ) ``` Si vous créez la vue directement, la méthode show est également renommée : ```diff showLineNumbers - val paywallView = AdaptyPaywallView(activity) - paywallView.showPaywall(viewConfiguration, products, eventListener) + val flowView = AdaptyFlowView(activity) + flowView.showFlow(flowConfiguration, products, eventListener) ``` Dans les layouts XML, mettez à jour le tag de la vue : ```diff showLineNumbers - + ``` Le paramètre optionnel `personalizedOfferResolver` a été supprimé de `getFlowView` / `showFlow` / `AdaptyFlowScreen`. Pour indiquer un prix personnalisé, définissez-le par produit via `onAwaitingPurchaseParams` (`AdaptyPurchaseParameters.Builder().withOfferPersonalized(true)`). Un nouveau paramètre optionnel `customAssets` vous permet de remplacer des images et des vidéos à l'exécution — voir [Personnaliser les assets](android-get-pb-paywalls#customize-assets). ### AdaptyPaywallScreen → AdaptyFlowScreen Dans Jetpack Compose, renommez le composable et mettez à jour le paramètre de configuration : ```diff showLineNumbers - AdaptyPaywallScreen( - viewConfiguration, + AdaptyFlowScreen( + flowConfiguration, products, eventListener, ) ``` ## Gestion des événements \{#handling-events\} L'écouteur d'événements est renommé de `AdaptyUiEventListener` en `AdaptyFlowEventListener` (et `AdaptyUiDefaultEventListener` en `AdaptyFlowDefaultEventListener`). La plupart des noms de méthodes restent inchangés ; les callbacks de cycle de vie et de rendu sont renommés : ```diff showLineNumbers - class YourListener : AdaptyUiDefaultEventListener() { + class YourListener : AdaptyFlowDefaultEventListener() { - override fun onPaywallShown(context: Context) {} - override fun onPaywallClosed() {} + override fun onFlowShown(context: Context) {} + override fun onFlowClosed() {} - override fun onRenderingError(error: AdaptyError, context: Context) {} + override fun onError(error: AdaptyError, context: Context) {} } ``` Les corps des gestionnaires existants ne nécessitent pas de modifications du code — il suffit de renommer le type et les surcharges. `onError` se déclenche pour les mêmes erreurs de rendu que `onRenderingError`, plus d'autres erreurs d'exécution non liées aux achats. Consultez [Gérer les événements de flow et de paywall](android-handling-events) pour la liste complète des callbacks. v4 ajoute également un callback `onBackPressed(context): Boolean`, et son comportement par défaut change la façon dont le bouton Retour du système fonctionne. Auparavant, le bouton Retour (ou le geste de retour) était transmis à votre activité ou fragment, ce qui fermait généralement le paywall. Dans v4, l'implémentation par défaut consomme l'appui, donc **le bouton Retour du système ne ferme plus un flow tout seul** — ce qui correspond au comportement iOS, où un flow ne peut pas être fermé par un geste système. Donnez aux utilisateurs un moyen explicite de quitter (un bouton **Close** ou une action `on_device_back`), ou surchargez `onBackPressed` pour retourner `false` afin de restaurer l'ancien comportement. Consultez [Bouton Retour du système](android-handling-events#system-back-button) pour plus de détails. Le gestionnaire d'achat par défaut ne ferme plus non plus l'écran. Dans la v3, le `onPurchaseFinished` par défaut fermait le paywall après tout achat terminé qui n'était pas une annulation de l'utilisateur (achat réussi ou en attente). Dans la v4, c'est un no-op, donc **un flow reste ouvert après un achat jusqu'à ce que vous le fermiez vous-même** — ce qui correspond au comportement iOS. Si vous comptiez sur cette fermeture automatique, fermez l'écran vous-même une fois l'achat terminé. Consultez [Achat réussi, annulé ou en attente](android-handling-events#successful-canceled-or-pending-purchase) pour un exemple. ## Identifiants d'attribution et d'intégration \{#attribution-and-integration-identifiers\} ### updateAttribution Le paramètre `source` passe de `String` au nouveau type `AdaptyAttributionSource`, et `attribution` est désormais un `Map` (une surcharge `String` JSON est également disponible). Utilisez l'une des sources prédéfinies : ```diff showLineNumbers - Adapty.updateAttribution(attribution, "appsflyer") { error -> /* handle the error */ } + Adapty.updateAttribution(attribution, AdaptyAttributionSource.APPSFLYER) { error -> /* handle the error */ } ``` Sources prédéfinies : `AdaptyAttributionSource.APPLE_ADS`, `.ADJUST`, `.APPSFLYER`, `.BRANCH`, `.TENJIN`. Pour toute autre source, créez-en une à partir d'une chaîne : `AdaptyAttributionSource("your_source")`. ### setIntegrationIdentifier `setIntegrationIdentifier(key, value)` est remplacé par une méthode qui accepte une ou plusieurs valeurs `AdaptyIntegrationIdentifier`. Construisez chaque identifiant avec une méthode utilitaire plutôt que de passer une clé brute en chaîne de caractères : ```diff showLineNumbers - Adapty.setIntegrationIdentifier("appsflyer_id", appsFlyerId) { error -> /* handle the error */ } + Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId)) { error -> /* handle the error */ } ``` Vous pouvez définir plusieurs identifiants en un seul appel : ```kotlin showLineNumbers Adapty.setIntegrationIdentifier( listOf( AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId), AdaptyIntegrationIdentifier.adjustDeviceId(adjustDeviceId), ) ) { error -> /* handle the error */ } ``` Remplacez chaque ancienne chaîne de clé par sa méthode pratique correspondante : | Clé v3 | Méthode `AdaptyIntegrationIdentifier` v4 | |---|---| | `"adjust_device_id"` | `adjustDeviceId(value)` | | `"airbridge_device_id"` | `airbridgeDeviceId(value)` | | `"amplitude_user_id"` | `amplitudeUserId(value)` | | `"amplitude_device_id"` | `amplitudeDeviceId(value)` | | `"appmetrica_device_id"` | `appmetricaDeviceId(value)` | | `"appmetrica_profile_id"` | `appmetricaProfileId(value)` | | `"appsflyer_id"` | `appsflyerId(value)` | | `"branch_id"` | `branchId(value)` | | `"facebook_anonymous_id"` | `facebookAnonymousId(value)` | | `"firebase_app_instance_id"` | `firebaseAppInstanceId(value)` | | `"mixpanel_user_id"` | `mixpanelUserId(value)` | | `"one_signal_subscription_id"` | `oneSignalSubscriptionId(value)` | | `"one_signal_player_id"` | `oneSignalPlayerId(value)` | | `"posthog_distinct_user_id"` | `posthogDistinctUserId(value)` | | `"pushwoosh_hwid"` | `pushwooshHWID(value)` | | `"tenjin_analytics_installation_id"` | `tenjinAnalyticsInstallationId(value)` | Pour une clé qui ne figure pas dans cette liste, construisez l'identifiant directement à partir d'une `Key` personnalisée : `AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key("custom"), customValue)`. --- # File: migration-to-android-312 --- --- title: "Migrer le SDK Android Adapty vers la v3.12" description: "Migrez vers le SDK Android Adapty v3.12 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Dans le SDK Adapty 3.12.0, nous avons supprimé la méthode `logShowOnboarding` du SDK. Si vous utilisiez cette méthode, elle ne sera plus disponible lorsque vous mettrez à jour le SDK vers la version 3.12 ou ultérieure. À la place, vous pouvez [créer des onboardings dans le générateur d'onboarding no-code d'Adapty](onboardings). Les analyses de ces onboardings sont suivies automatiquement, et vous disposez de nombreuses options de personnalisation. --- # File: migration-to-android-310 --- --- title: "Guide de migration vers Android Adapty SDK 3.10.0" description: "" --- Adapty SDK 3.10.0 est une version majeure qui apporte des améliorations nécessitant toutefois quelques étapes de migration de votre part : 1. `AdaptyUiPersonalizedOfferResolver` a été supprimé. Si vous l'utilisiez, passez-le dans le callback `onAwaitingPurchaseParams`. 2. Mettez à jour la signature de la méthode `onAwaitingSubscriptionUpdateParams` pour les paywalls du Paywall Builder. ## Mettre à jour le callback des paramètres d'achat \{#update-purchase-parameters-callback\} La méthode `onAwaitingSubscriptionUpdateParams` a été renommée en `onAwaitingPurchaseParams` et utilise désormais `AdaptyPurchaseParameters` à la place de `AdaptySubscriptionUpdateParameters`. Cela vous permet de spécifier des paramètres de remplacement d'abonnement (crossgrade) et d'indiquer si le prix est personnalisé ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), ainsi que d'autres paramètres d'achat. ```diff showLineNumbers - override fun onAwaitingSubscriptionUpdateParams( - product: AdaptyPaywallProduct, - context: Context, - onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, - ) { - onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) - } + override fun onAwaitingPurchaseParams( + product: AdaptyPaywallProduct, + context: Context, + onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, + ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { + onPurchaseParamsReceived( + AdaptyPurchaseParameters.Builder() + .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) + .withOfferPersonalized(true) + .build() + ) + return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked + } ``` Si aucun paramètre supplémentaire n'est nécessaire, vous pouvez simplement utiliser : ```kotlin showLineNumbers + override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` --- # File: migration-to-android-sdk-34 --- --- title: "Migrer le SDK Adapty Android vers v3.4" description: "Migrez vers le SDK Adapty Android v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté. ## Mettre à jour les fichiers de paywall de secours \{#update-fallback-paywall-files\} Mettez à jour vos fichiers de paywall de secours pour assurer la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](android-use-fallback-paywalls) par les nouveaux fichiers. ## Mettre à jour l'implémentation du mode Observateur \{#update-implementation-of-observer-mode\} Si vous utilisez le mode Observateur, assurez-vous de mettre à jour son implémentation. Dans les versions précédentes, vous deviez restaurer les achats pour qu'Adapty puisse reconnaître les transactions effectuées via votre propre infrastructure, car Adapty n'y avait pas accès directement en mode Observateur. Si vous utilisiez des paywalls, vous deviez également associer manuellement chaque transaction au paywall qui l'avait initiée. Dans la nouvelle version, vous devez signaler explicitement chaque transaction pour qu'Adapty puisse la reconnaître. Si vous utilisez des paywalls, vous devez également transmettre l'ID de variation pour lier la transaction au paywall utilisé. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: ```diff showLineNumbers - Adapty.restorePurchases { result -> - if (result is AdaptyResult.Success) { - // success - } - } - - Adapty.setVariationId(transactionId, variationId) { error -> - if (error == null) { - // success - } - } + val transactionInfo = TransactionInfo.fromPurchase(purchase) + + Adapty.reportTransaction(transactionInfo, variationId) { result -> + if (result is AdaptyResult.Success) { + // success + } + } ``` ```diff showLineNumbers - Adapty.restorePurchases(result -> { - if (result instanceof AdaptyResult.Success) { - // success - } - }); - - Adapty.setVariationId(transactionId, variationId, error -> { - if (error == null) { - // success - } - }); + TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase); + + Adapty.reportTransaction(transactionInfo, variationId, result -> { + if (result instanceof AdaptyResult.Success) { + // success + } + }); ``` --- # File: migration-to-android330 --- --- title: "Migrer le SDK Adapty Android vers v3.3" description: "Migrez vers le SDK Adapty Android v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.3.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part. 1. Mettez à jour la façon dont vous gérez les achats dans les paywalls non créés avec le Paywall Builder. Arrêtez de traiter les codes d'erreur `USER_CANCELED` et `PENDING_PURCHASE`. Un achat annulé n'est plus considéré comme une erreur et apparaîtra désormais dans les résultats d'achat sans erreur. 2. Remplacez les événements `onPurchaseCanceled` et `onPurchaseSuccess` par le nouvel événement `onPurchaseFinished` pour les paywalls créés avec le Paywall Builder. Ce changement est dû à la même raison : les achats annulés ne sont plus traités comme des erreurs et seront inclus dans les résultats d'achat sans erreur. 3. Modifiez la signature de la méthode `onAwaitingSubscriptionUpdateParams` pour les paywalls Paywall Builder. 4. Mettez à jour la méthode utilisée pour fournir les paywalls de secours si vous passez l'URI du fichier directement. 5. Mettez à jour les configurations d'intégration pour Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase et Google Analytics, Mixpanel, OneSignal, Pushwoosh. ## Mettre à jour les achats \{#update-making-purchase\} Auparavant, les achats annulés et en attente étaient considérés comme des erreurs et retournaient respectivement les codes `USER_CANCELED` et `PENDING_PURCHASE`. Désormais, une nouvelle classe `AdaptyPurchaseResult` est utilisée pour indiquer les achats annulés, réussis et en attente. Mettez à jour le code d'achat de la façon suivante : ~~~diff Adapty.makePurchase(activity, product) { result -> when (result) { is AdaptyResult.Success -> { - val info = result.value - val profile = info?.profile - - if (profile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true) { - // Grant access to the paid features - } + when (val purchaseResult = result.value) { + is AdaptyPurchaseResult.Success -> { + val profile = purchaseResult.profile + if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { + // Grant access to the paid features + } + } + + is AdaptyPurchaseResult.UserCanceled -> { + // Handle the case where the user canceled the purchase + } + + is AdaptyPurchaseResult.Pending -> { + // Handle deferred purchases (e.g., the user will pay offline with cash + } + } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ~~~ Pour un exemple de code complet, consultez la page [Effectuer des achats dans l'application mobile](android-making-purchases#make-purchase). ## Modifier les événements d'achat du Paywall Builder \{#modify-paywall-builder-purchase-events\} 1. Ajoutez l'événement `onPurchaseFinished` : ```diff showLineNumbers + public override fun onPurchaseFinished( + purchaseResult: AdaptyPurchaseResult, + product: AdaptyPaywallProduct, + context: Context, + ) { + when (purchaseResult) { + is AdaptyPurchaseResult.Success -> { + // Grant access to the paid features + } + is AdaptyPurchaseResult.UserCanceled -> { + // Handle the case where the user canceled the purchase + } + is AdaptyPurchaseResult.Pending -> { + // Handle deferred purchases (e.g., the user will pay offline with cash) + } + } + } ``` Pour un exemple de code complet, consultez [Achat réussi, annulé ou en attente](android-handling-events#successful-canceled-or-pending-purchase) et la description de l'événement. 2. Supprimez le traitement de l'événement `onPurchaseCancelled` : ```diff showLineNumbers - public override fun onPurchaseCanceled( - product: AdaptyPaywallProduct, - context: Context, - ) {} ``` 3. Supprimez `onPurchaseSuccess` : ```diff showLineNumbers - public override fun onPurchaseSuccess( - profile: AdaptyProfile?, - product: AdaptyPaywallProduct, - context: Context, - ) { - // Your logic on successful purchase - } ``` ## Modifier la signature de la méthode onAwaitingSubscriptionUpdateParams \{#change-the-signature-of--onawaitingsubscriptionupdateparams-method\} Désormais, si un nouvel abonnement est souscrit alors qu'un autre est encore actif, appelez `onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters...))` si le nouvel abonnement doit remplacer l'abonnement actif, ou `onSubscriptionUpdateParamsReceived(null)` si l'abonnement actif doit rester actif et le nouveau être ajouté séparément : ```diff showLineNumbers - public override fun onAwaitingSubscriptionUpdateParams( - product: AdaptyPaywallProduct, - context: Context, - ): AdaptySubscriptionUpdateParameters? { - return AdaptySubscriptionUpdateParameters(...) - } + public override fun onAwaitingSubscriptionUpdateParams( + product: AdaptyPaywallProduct, + context: Context, + onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, + ) { + onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) + } ``` Consultez la section [Mettre à niveau un abonnement](android-handling-events#upgrade-subscription) pour l'exemple de code final. ## Mettre à jour la fourniture des paywalls de secours \{#update-providing-fallback-paywalls\} Si vous passez l'URI d'un fichier pour fournir des paywalls de secours, mettez à jour votre code de la façon suivante : ```diff showLineNumbers val fileUri: Uri = // Get the URI for the file with fallback paywalls - Adapty.setFallbackPaywalls(fileUri, callback) + Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback) ``` ```diff showLineNumbers Uri fileUri = // Get the URI for the file with fallback paywalls - Adapty.setFallbackPaywalls(fileUri, callback); + Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback); ``` ## Mettre à jour la configuration du SDK des intégrations tierces \{#update-third-party-integration-sdk-configuration\} Pour garantir le bon fonctionnement des intégrations avec le SDK Adapty Android 3.3.0 et versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes comme décrit dans les sections ci-dessous. ### Adjust \{#adjust\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers - Adjust.getAttribution { attribution -> - if (attribution == null) return@getAttribution - - Adjust.getAdid { adid -> - if (adid == null) return@getAdid - - Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST, adid) { error -> - // Handle the error - } - } - } + Adjust.getAdid { adid -> + if (adid == null) return@getAdid + + Adapty.setIntegrationIdentifier("adjust_device_id", adid) { error -> + if (error != null) { + // Handle the error + } + } + } + + Adjust.getAttribution { attribution -> + if (attribution == null) return@getAttribution + + Adapty.updateAttribution(attribution, "adjust") { error -> + if (error != null) { + // Handle the error + } + } + } ``` ```diff showLineNumbers val config = AdjustConfig(context, adjustAppToken, environment) config.setOnAttributionChangedListener { attribution -> attribution?.let { attribution -> - Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST) { error -> + Adapty.updateAttribution(attribution, "adjust") { error -> if (error != null) { // Handle the error } } } } Adjust.onCreate(config) ``` ### AirBridge \{#airbridge\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers Airbridge.getDeviceInfo().getUUID(object: AirbridgeCallback.SimpleCallback() { override fun onSuccess(result: String) { - val params = AdaptyProfileParameters.Builder() - .withAirbridgeDeviceId(result) - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("airbridge_device_id", result) { error -> + if (error != null) { + // Handle the error + } + } } override fun onFailure(throwable: Throwable) { } }) ``` ### Amplitude \{#amplitude\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers // For Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeDeviceId = amplitude.store.deviceId val amplitudeUserId = amplitude.store.userId // - val params = AdaptyProfileParameters.Builder() - .withAmplitudeDeviceId(amplitudeDeviceId) - .withAmplitudeUserId(amplitudeUserId) - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("amplitude_user_id", amplitudeUserId) { error -> + if (error != null) { + // Handle the error + } + } + Adapty.setIntegrationIdentifier("amplitude_device_id", amplitudeDeviceId) { error -> + if (error != null) { + // Handle the error + } + } ``` ### AppMetrica \{#appmetrica\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceId = result?.deviceId ?: return - val params = AdaptyProfileParameters.Builder() - .withAppmetricaDeviceId(deviceId) - .withAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID") - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId) { error -> + if (error != null) { + // Handle the error + } + } + + Adapty.setIntegrationIdentifier("appmetrica_profile_id", "YOUR_ADAPTY_CUSTOMER_USER_ID") { error -> + if (error != null) { + // Handle the error + } + } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { // Handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID)) ``` ### AppsFlyer \{#appsflyer\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers val conversionListener: AppsFlyerConversionListener = object : AppsFlyerConversionListener { override fun onConversionDataSuccess(conversionData: Map) { - Adapty.updateAttribution( - conversionData, - AdaptyAttributionSource.APPSFLYER, - AppsFlyerLib.getInstance().getAppsFlyerUID(context) - ) { error -> - if (error != null) { - // Handle the error - } - } + val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(context) + Adapty.setIntegrationIdentifier("appsflyer_id", uid) { error -> + if (error != null) { + // Handle the error + } + } + Adapty.updateAttribution(conversionData, "appsflyer") { error -> + if (error != null) { + // Handle the error + } + } } } ``` ### Branch \{#branch\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers // Login and update attribution Branch.getAutoInstance(this) .setIdentity("YOUR_USER_ID") { referringParams, error -> referringParams?.let { data -> - Adapty.updateAttribution(data, AdaptyAttributionSource.BRANCH) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.updateAttribution(data, "branch") { error -> + if (error != null) { + // Handle the error + } + } } } // Logout Branch.getAutoInstance(context).logout() ``` ### Facebook Ads \{#facebook-ads\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads). ```diff showLineNumbers - val builder = AdaptyProfileParameters.Builder() - .withFacebookAnonymousId(AppEventsLogger.getAnonymousAppDeviceGUID(context)) - - Adapty.updateProfile(builder.build()) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier( + "facebook_anonymous_id", + AppEventsLogger.getAnonymousAppDeviceGUID(context) + ) { error -> + if (error != null) { + // Handle the error + } + } ``` ### Firebase et Google Analytics \{#firebase-and-google-analytics\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Firebase et Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers // After Adapty.activate() FirebaseAnalytics.getInstance(context).appInstanceId.addOnSuccessListener { appInstanceId -> - Adapty.updateProfile( - AdaptyProfileParameters.Builder() - .withFirebaseAppInstanceId(appInstanceId) - .build() - ) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId) { error -> + if (error != null) { + // Handle the error + } + } } ``` ```diff showLineNumbers // After Adapty.activate() - FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withFirebaseAppInstanceId(appInstanceId) - .build(); - - Adapty.updateProfile(params, error -> { - if (error != null) { - // Handle the error - } - }); - }); + FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { + Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId, error -> { + if (error != null) { + // Handle the error + } + }); + }); ``` ### Mixpanel \{#mixpanel\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers - val params = AdaptyProfileParameters.Builder() - .withMixpanelUserId(mixpanelAPI.distinctId) - .build() - - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelAPI.distinctId) { error -> + if (error != null) { + // Handle the error + } + } ``` ### OneSignal \{#onesignal\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration OneSignal](onesignal#sdk-configuration). ```diff showLineNumbers // SubscriptionID val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver { override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) { - val params = AdaptyProfileParameters.Builder() - .withOneSignalSubscriptionId(state.current.id) - .build() - - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.current.id) { error -> if (error != null) { // Handle the error } } } } ``` ```diff showLineNumbers // SubscriptionID IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> { - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withOneSignalSubscriptionId(state.getCurrent().getId()) - .build(); - Adapty.updateProfile(params, error -> { + Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.getCurrent().getId(), error -> { if (error != null) { // Handle the error } }); }; ``` ```diff showLineNumbers // PlayerID val osSubscriptionObserver = OSSubscriptionObserver { stateChanges -> stateChanges?.to?.userId?.let { playerId -> - val params = AdaptyProfileParameters.Builder() - .withOneSignalPlayerId(playerId) - .build() - - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("one_signal_player_id", playerId) { error -> if (error != null) { // Handle the error } - } } } ``` ```diff showLineNumbers // PlayerID OSSubscriptionObserver osSubscriptionObserver = stateChanges -> { OSSubscriptionState to = stateChanges != null ? stateChanges.getTo() : null; String playerId = to != null ? to.getUserId() : null; if (playerId != null) { - AdaptyProfileParameters params1 = new AdaptyProfileParameters.Builder() - .withOneSignalPlayerId(playerId) - .build(); - - Adapty.updateProfile(params1, error -> { + Adapty.setIntegrationIdentifier("one_signal_player_id", playerId, error -> { if (error != null) { // Handle the error } - }); } }; ``` ### Pushwoosh \{#pushwoosh\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers - val params = AdaptyProfileParameters.Builder() - .withPushwooshHwid(Pushwoosh.getInstance().hwid) - .build() - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().hwid) { error -> if (error != null) { // Handle the error } } ``` ```diff showLineNumbers - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withPushwooshHwid(Pushwoosh.getInstance().getHwid()) - .build(); - - Adapty.updateProfile(params, error -> { + Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().getHwid(), error -> { if (error != null) { // Handle the error } }); ``` --- # File: migration-to-android-sdk-v3 --- --- title: "Migrer le SDK Adapty Android vers la v3.0" description: "Migrez vers le SDK Adapty Android v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Adapty Paywall Builder](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et ses riches capacités de design, vos paywalls deviendront plus efficaces et rentables. Les SDK Adapty sont distribués sous forme de BoM (Bill of Materials), ce qui garantit la cohérence des versions du SDK Adapty et du SDK AdaptyUI dans votre application. Pour migrer vers la v3.0, mettez à jour votre code comme suit : ```diff showLineNumbers dependencies { ... - implementation 'io.adapty:android-sdk:2.11.5' - implementation 'io.adapty:android-ui:2.11.3' + implementation platform('io.adapty:adapty-bom:3.0.4') + implementation 'io.adapty:android-sdk' + implementation 'io.adapty:android-ui' } ``` ```diff showLineNumbers dependencies { ... - implementation("io.adapty:android-sdk:2.11.5") - implementation("io.adapty:android-ui:2.11.3") + implementation(platform("io.adapty:adapty-bom:3.0.4")) + implementation("io.adapty:android-sdk") + implementation("io.adapty:android-ui") } ``` ```diff showLineNumbers //libs.versions.toml [versions] .. - adapty = "2.11.5" - adaptyUi = "2.11.3" + adaptyBom = "3.0.4" [libraries] .. - adapty = { group = "io.adapty", name = "android-sdk", version.ref = "adapty" } - adapty-ui = { group = "io.adapty", name = "android-ui", version.ref = "adaptyUi" } + adapty-bom = { module = "io.adapty:adapty-bom", version.ref = "adaptyBom" } + adapty = { module = "io.adapty:android-sdk" } + adapty-ui = { module = "io.adapty:android-ui" } //module-level build.gradle.kts dependencies { ... + implementation(libs.adapty.bom) implementation(libs.adapty) implementation(libs.adapty.ui) } ``` --- # End of Documentation _Generated on: 2026-08-04T15:08:25.903Z_ _Successfully processed: 49/49 files_ # API - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:25.906Z Total files: 18 --- # File: developer-cli --- --- title: "Developer CLI" description: "Overview of the Adapty Developer CLI." --- The **Adapty Developer CLI** is a command-line tool for managing your Adapty account without opening the Dashboard. It provides the main configuration capabilities, accessible from your terminal or automated environments. **What you can do with the CLI:** - Create and configure iOS and Android apps in your Adapty account - Define access levels — the subscription tiers your app checks at runtime - Set up products and map them to App Store and Google Play store IDs - Create paywalls and assign products to them - Configure placements to fetch paywalls via the SDK :::link Using an AI assistant or MCP client? An [Adapty CLI skill](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) is available to help LLMs work with the CLI. ::: --- # File: developer-cli-quickstart --- --- title: "Guide de démarrage rapide pour le CLI développeur Adapty" description: "Configurez votre compte Adapty de bout en bout avec le CLI développeur — de la création de l'application à un placement en production, en quelques commandes." --- :::link Vous utilisez un assistant IA ? Une [compétence CLI Adapty](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) est disponible pour aider les LLM à travailler avec le CLI. ::: L'Adapty CLI vous permet de configurer entièrement votre application depuis la ligne de commande. Utilisez-le comme alternative au [démarrage rapide via le tableau de bord](integrate-payments) si vous préférez les outils en terminal ou les [clients MCP](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli). :::note La connexion d'Adapty à App Store Connect et Google Play nécessite une configuration unique dans le tableau de bord — couverte à l'étape 3. ::: À la fin, votre application, votre niveau d'accès, votre produit, votre paywall et votre placement sont tous visibles dans l'[Adapty Dashboard](https://app.adapty.io). ## 1. Installer la CLI \{#1-install-the-cli\} Nécessite [Node.js](https://nodejs.org/en/download) 18 ou version ultérieure. Pour installer la CLI, exécutez la commande : ```bash npm install -g adapty ``` Ou, directement : ```bash npx adapty auth login ``` ## 2. S'authentifier \{#2-authenticate\} Lancez la commande de connexion pour relier le CLI à votre compte Adapty. ```bash adapty auth login ``` Le CLI ouvre un onglet dans le navigateur. Vérifiez que le code affiché dans le terminal correspond à celui affiché dans le navigateur, puis cliquez sur **Authorize**. Le terminal confirme lorsque l'authentification est terminée. ## 3. Créez votre application \{#3-create-your-app\} Une application dans Adapty représente votre application mobile. Une seule application Adapty se connecte à la fois à l'App Store et au Google Play — vous n'avez besoin d'en créer qu'une seule, quel que soit le nombre de stores sur lesquels vous publiez. ```bash adapty apps create --title "My App" --platform ios --platform android --apple-bundle-id com.example.app --google-bundle-id com.example.app ``` ```bash adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app ``` ```bash adapty apps create --title "My App" --platform android --google-bundle-id com.example.app ``` La commande retourne un ``. Utilisez cet ID dans toutes les commandes suivantes. :::important Avant de continuer, connectez votre app à App Store Connect et Google Play dans le tableau de bord Adapty. Les ID de produits des deux stores sont nécessaires à l'étape 5. - [Connecter App Store Connect](app-store-connection-configuration) - [Connecter Google Play](google-play-store-connection-configuration) ::: ## 4. Créer un niveau d'accès (facultatif) \{#4-create-an-access-level-optional\} Les [niveaux d'accès](access-level) contrôlent ce à quoi les utilisateurs peuvent accéder après un achat. Plutôt que de vérifier si un utilisateur a acheté un produit spécifique, votre application vérifie si l'utilisateur dispose d'un niveau d'accès donné. Cela découple la logique de votre application des identifiants de produits spécifiques. Un niveau d'accès `premium` est automatiquement créé avec chaque nouvelle application. **Pour la plupart des applications, vous pouvez passer cette étape.** Utilisez `premium` comme identifiant de niveau d'accès à l'étape 5. Only run this command if different products unlock different features for different user groups — for example, if a "Basic" subscriber and a "Pro" subscriber get access to different parts of the app. ```bash adapty access-levels create --app --sdk-id "pro" --title "Pro" ``` - `--sdk-id` est l'identifiant que vous utiliserez dans le code de votre app pour vérifier si une fonctionnalité doit être accessible à l'utilisateur (par exemple, `if user.hasAccessLevel("pro")`). Si vous ignorez cette étape et utilisez le niveau d'accès par défaut, son `--sdk-id` est `premium`. - `--title` est un libellé d'affichage pour votre propre référence dans l'Adapty Dashboard. La commande renvoie un ``. ## 5. Créer un produit \{#create-a-product\} Dans Adapty, un [produit](product) représente tout ce que votre application vend — un abonnement ou un achat unique. Les articles d'App Store Connect et de Google Play peuvent être regroupés en un seul produit Adapty et gérés depuis un seul endroit. Vous aurez besoin des identifiants de produit de chaque store : l'identifiant Apple depuis App Store Connect, et l'identifiant de produit Android ainsi que l'identifiant de plan de base depuis Google Play Console. Consultez [Produits](quickstart-products) pour savoir où les trouver. Si vous avez sauté l'étape 4, utilisez le `default_access_level.id` retourné par la commande `apps create` à l'étape 3 comme ``. :::important Les identifiants de produits store que vous associez ici ne peuvent pas être modifiés après la création. Pour utiliser des identifiants différents, créez un nouveau produit. ::: ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --ios-product-id --android-product-id --android-base-plan-id ``` ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --ios-product-id ``` ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --android-product-id --android-base-plan-id ``` La commande retourne un ``. Si vous vendez également ce produit sur le web via Stripe ou Paddle, ajoutez ces identifiants à la même commande. Voir [products create](developer-cli-reference#adapty-products-create) dans la référence complète. ## 6. Créer un paywall \{#create-a-paywall\} Un [paywall](paywalls) est le conteneur qui regroupe vos produits. Dans Adapty, les paywalls sont le seul moyen de proposer des produits aux utilisateurs. Chaque produit doit être dans un paywall avant de pouvoir apparaître dans votre application. :::important Une fois qu'un paywall est associé à un placement, ses produits ne peuvent plus être modifiés. Pour utiliser des produits différents, créez un nouveau paywall et mettez à jour le placement pour qu'il pointe vers celui-ci. ::: ```bash adapty paywalls create --app --title "My Paywall" --product-id ``` ```bash adapty paywalls create --app --title "My Paywall" --product-id --product-id ``` La commande retourne un ``. ## 7. Créer un placement \{#create-a-placement\} Un [placement](placements) est l'endroit dans votre application où vous affichez un paywall. La seule chose que vous codez en dur dans votre code est l'identifiant du placement. Tout le reste — quel paywall afficher et à quels utilisateurs — est géré depuis le tableau de bord sans avoir à publier une nouvelle version de l'application. `--developer-id` est la chaîne que vous référencerez plus tard dans votre code quand vous demanderez à Adapty quel paywall afficher à cet endroit. Choisissez quelque chose qui décrit l'emplacement, comme `"main"`, `"onboarding"`, ou `"settings"`. ```bash adapty placements create --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` Le flag `--audiences` contrôle quel paywall est affiché à quels utilisateurs. L'exemple ci-dessus définit une audience par défaut unique — tous les utilisateurs à ce placement voient le même paywall. ## Et maintenant ? Toutes les entités sont désormais visibles dans l'[Adapty Dashboard](https://app.adapty.io). Prochaines étapes : - [Créer votre paywall](adapty-paywall-builder) — utilisez le Paywall Builder sans code pour ajouter des visuels, une mise en page et du contenu au paywall que vous venez de créer. - [Intégrer le SDK Adapty](quickstart-sdk) — ajoutez le SDK à votre application pour récupérer et afficher le placement. - Dirigez différents [segments](segments) d'utilisateurs vers différents paywalls — consultez [`placements update`](developer-cli-reference#adapty-placements-update) et [`segments list`](developer-cli-reference#adapty-segments-list) dans la référence complète. --- # File: developer-cli-authentication --- --- title: "Authentication in the Adapty Developer CLI" description: "How to authenticate with the Adapty Developer CLI." --- :::link Using an AI assistant? An [Adapty CLI skill](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) is available to help LLMs work with the CLI. ::: The CLI requires authentication to call the Adapty API. ## Log in To log in: 1. In your terminal, run: ```bash adapty auth login ``` 2. The CLI prints a verification code in `XXXX-XXXX` format and opens the Adapty Dashboard in your browser. 3. On the authorization page, confirm the code matches your terminal output. 4. Click **Authorize**. The browser shows "CLI authorized! You can close this tab." 5. Back in the terminal, the CLI confirms you are authenticated. If the code expires before you authorize, or if you click **Deny**, run the following command again to restart the flow: ```bash adapty auth login ``` ## Manage authentication ### Check authentication status To see your current authentication state, run: ```bash adapty auth status ``` When authenticated, the output shows your email, a masked token prefix, and the path to the local config file: ``` Email: you@example.com Token: abcd1234**** Config: ~/.config/adapty/config.json ``` When not authenticated: ``` Not authenticated. Run `adapty auth login`. ``` ### Verify your token To confirm your token is valid and see your account details, run: ```bash adapty auth whoami ``` Unlike `adapty auth status`, this command makes a live request to the server to verify the token. ### Log out To clear your stored credentials locally, run: ```bash adapty auth logout ``` This clears `~/.config/adapty/config.json`. The token remains valid server-side until it expires — if you need to invalidate it immediately, use `adapty auth revoke` instead. ### Revoke your token To invalidate the token on the server and clear it locally, run: ```bash adapty auth revoke ``` Use this when you want to fully invalidate a token — for example, if your credentials may have been compromised. After revoking, run `adapty auth login` to authenticate again. ## Token errors If a token is revoked or becomes invalid, CLI commands return a 401 error. To re-authenticate, run: ```bash adapty auth login ``` --- # File: developer-cli-reference --- --- title: "Référence complète du CLI Développeur Adapty" description: "Référence complète de toutes les commandes du CLI Développeur Adapty." --- :::link Vous utilisez un assistant IA ? Une [compétence Adapty CLI](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) est disponible pour aider les LLM à utiliser le CLI. ::: Cet article liste toutes les commandes du CLI Adapty avec leurs arguments, options et valeurs acceptées. :::link Pour la configuration de l'authentification et la gestion des tokens, consultez [Authentification](developer-cli-authentication). ::: ## Indicateurs globaux \{#global-flags\} Ces indicateurs sont disponibles sur toutes les commandes. | Indicateur | Description | |---|---| | `--json` | Afficher en JSON plutôt qu'en texte formaté | | `--help` | Afficher l'aide de la commande | Toutes les commandes `list` acceptent également des indicateurs de pagination : | Indicateur | Défaut | Description | |---|---|---| | `--page` | `1` | Numéro de page | | `--page-size` | `20` | Éléments par page (max : 100) | ## Applications \{#apps\} Gérez les applications de votre compte Adapty. Pour la configuration via le tableau de bord, consultez [Paramètres de l'application](general). ### adapty apps list Listez toutes les applications de votre compte Adapty. ```bash adapty apps list ``` Accepte les [options de pagination](#global-flags). ### adapty apps get Obtenez les détails d'une application spécifique. ```bash adapty apps get ``` | Argument | Description | |---|---| | `app-id` | ID de l'application (UUID) | ### adapty apps create Créer une nouvelle application. ```bash adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app ``` | Flag | Required | Description | |---|---|---| | `--title` | Yes | Titre de l'application | | `--platform` | Yes | Plateforme : `ios` ou `android`. Répéter pour les deux : `--platform ios --platform android` | | `--apple-bundle-id` | Required with `--platform ios` | Bundle ID Apple | | `--google-bundle-id` | Required with `--platform android` | Bundle ID Google | ### adapty apps update Mettre à jour une application existante. ```bash adapty apps update --title "New Name" ``` | Argument | Description | |---|---| | `app-id` | ID de l'application (UUID) | | Flag | Description | |---|---| | `--title` | Nouveau titre de l'application | | `--apple-bundle-id` | Nouvel Apple bundle ID | | `--google-bundle-id` | Nouvel Google bundle ID | Au moins un flag est requis. `--platform` ne peut pas être modifié après la création. ## Niveaux d'accès \{#access-levels\} ### adapty access-levels list Liste tous les [niveaux d'accès](access-level) d'une application. ```bash adapty access-levels list --app ``` | Flag | Required | Description | |---|---|---| | `--app` | Yes | App ID (UUID) | Accepte les [options de pagination](#global-flags). ### adapty access-levels get Obtenez les détails d'un [niveau d'accès](access-level) spécifique. ```bash adapty access-levels get --app ``` | Argument | Description | |---|---| | `access-level-id` | ID du niveau d'accès (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | ### adapty access-levels create Créer un nouveau [niveau d'accès](access-level). ```bash adapty access-levels create --app --sdk-id "pro" --title "Pro" ``` | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | | `--sdk-id` | Oui | Identifiant utilisé dans le code de l'app pour vérifier l'accès (par exemple, `"pro"` ou `"premium"`) | | `--title` | Oui | Libellé d'affichage dans l'Adapty Dashboard | ### adapty access-levels update Mettez à jour un [niveau d'accès](access-level) existant. ```bash adapty access-levels update --app --title "Pro Access" ``` | Argument | Description | |---|---| | `access-level-id` | ID du niveau d'accès (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | | `--title` | Oui | Nouveau libellé d'affichage | `--sdk-id` ne peut pas être modifié après la création. ## Produits \{#products\} ### Liste des produits Adapty \{#adapty-products-list\} Listez tous les [produits](product) d'une application. ```bash adapty products list --app ``` | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | Accepte les [flags de pagination](#global-flags). ### adapty products get Obtenez les détails d'un [produit](product) spécifique. ```bash adapty products get --app ``` | Argument | Description | |---|---| | `product-id` | ID du produit (UUID) | | Indicateur | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | ### adapty products create Créez un nouveau [produit](product). :::important Les identifiants de produit et de prix du store ne peuvent pas être modifiés après la création. Pour utiliser d'autres identifiants de store, créez un nouveau produit. ::: ```bash adapty products create --app --title "Monthly" --access-level-id --period monthly --ios-product-id com.example.monthly ``` | Paramètre | Obligatoire | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | | `--title` | Oui | Titre du produit | | `--access-level-id` | Oui | ID (UUID) du [niveau d'accès](access-level) que ce produit débloque | | `--period` | Oui | Période d'abonnement : `weekly`, `monthly`, `two_months`, `trimonthly`, `semiannual`, `annual`, `lifetime` | | `--ios-product-id` | Au moins un store requis | ID du produit dans App Store Connect | | `--android-product-id` | Au moins un store requis | ID du produit dans Google Play Console | | `--android-base-plan-id` | Obligatoire avec `--android-product-id` sauf si `--period lifetime` | ID du plan de base dans Google Play Console | | `--stripe-product-id` | Au moins un store requis | ID du produit dans Stripe | | `--stripe-price-id` | Obligatoire avec `--stripe-product-id` | ID du prix dans Stripe | | `--paddle-product-id` | Au moins un store requis | ID du produit dans Paddle | | `--paddle-price-id` | Obligatoire avec `--paddle-product-id` | ID du prix dans Paddle | Chaque produit nécessite au moins un store : `--ios-product-id`, `--android-product-id`, `--stripe-product-id` ou `--paddle-product-id`. Un même produit peut avoir des identifiants pour plusieurs stores à la fois. Pour vendre un produit sur le web via Stripe ou Paddle, connectez d'abord le fournisseur de paiement à Adapty : voir [Stripe](stripe) et [Paddle](paddle). Pour chacun de ces stores, passez l'identifiant du produit et l'identifiant du prix ensemble. La commande échoue si vous ne passez qu'un seul des deux. ```bash adapty products create --app --title "Monthly" --access-level-id --period monthly --stripe-product-id prod_xxx --stripe-price-id price_xxx ``` Un produit web uniquement est valide : vous pouvez créer un produit avec des identifiants Stripe ou Paddle sans identifiants App Store ou Google Play. ### adapty products update Mettez à jour un [produit](product) existant. Les identifiants de produit et de prix du store ne peuvent pas être modifiés après la création et ne sont pas disponibles dans cette commande. Pour utiliser des identifiants de store différents, créez un nouveau produit. ```bash adapty products update --app --title "Monthly" --access-level-id ``` | Argument | Description | |---|---| | `product-id` | ID du produit (UUID) | | Indicateur | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | | `--title` | Non | Titre du produit | | `--access-level-id` | Non | ID (UUID) du [niveau d'accès](access-level) que ce produit déverrouille | ## Paywalls \{#paywalls\} ### Liste des paywalls Adapty \{#adapty-paywalls-list\} Listez tous les [paywalls](paywalls) d'une application. ```bash adapty paywalls list --app ``` | Indicateur | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | Accepte les [indicateurs de pagination](#global-flags). ### adapty paywalls get Obtenir les détails d'un [paywall](paywalls) spécifique. ```bash adapty paywalls get --app ``` | Argument | Description | |---|---| | `paywall-id` | ID du paywall (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | ### adapty paywalls create Crée un nouveau [paywall](paywalls). ```bash adapty paywalls create --app --title "Default Paywall" --product-id ``` | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | | `--title` | Oui | Titre du paywall | | `--product-id` | Oui | ID du [produit](product) (UUID). Répétez pour plusieurs produits : `--product-id --product-id ` | ### adapty paywalls update Remplacez tous les champs d'un [paywall](paywalls) existant. :::important Une fois qu'un paywall est lié à un placement, ses produits ne peuvent plus être modifiés. Pour utiliser des produits différents dans un paywall actif, créez un nouveau paywall et mettez à jour le placement pour qu'il pointe vers celui-ci. ::: ```bash adapty paywalls update --app --title "Default Paywall" --product-id ``` Cette commande remplace tous les champs du paywall, y compris la liste complète des produits. | Argument | Description | |---|---| | `paywall-id` | ID du paywall (UUID) | | Indicateur | Obligatoire | Description | |---|---|---| | `--app` | Oui | ID d'application (UUID) | | `--title` | Oui | Titre du paywall | | `--product-id` | Oui | ID de [produit](product) (UUID). Répéter pour plusieurs produits : `--product-id --product-id ` | ### adapty paywalls placements Liste tous les [placements](placements) qui utilisent actuellement un [paywall](paywalls) donné. ```bash adapty paywalls placements --app ``` | Argument | Description | |---|---| | `paywall-id` | ID du paywall (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | Utilisez cette commande avant de remplacer un paywall pour voir quels placements seraient affectés. ## Placements \{#placements\} ### Liste des placements Adapty \{#adapty-placements-list\} Listez tous les [placements](placements) d'une application. ```bash adapty placements list --app ``` | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | Accepte les [flags de pagination](#global-flags). ### adapty placements get Récupère les détails d'un [placement](placements) spécifique. ```bash adapty placements get --app ``` | Argument | Description | |---|---| | `placement-id` | ID du placement (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | Le tableau `audiences` contient un tableau de résultats. Chaque entrée est composée de `{segment_ids, paywall_id, priority}`. L'audience par défaut a `segment_ids: []` et la valeur de priorité la plus élevée (évaluée en dernier). La sortie formatée pour l'humain affiche également un `Paywall ID` de niveau supérieur, dérivé de l'audience par défaut pour plus de commodité. `--json` renvoie la structure brute de l'API sans modification. ### adapty placements create Créez un nouveau [placement](placements). ```bash adapty placements create --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` | Indicateur | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | | `--title` | Oui | Titre du placement | | `--developer-id` | Oui | Identifiant de chaîne utilisé dans le code de l'application pour demander ce [placement](placements) | | `--audiences` | L'un des deux | Tableau JSON d'entrées `{segment_ids, paywall_id, priority}`. Voir [Structure des audiences](#audiences-shape) | | `--paywall-id` | L'un des deux | **Déprécié.** ID de [paywall](paywalls) (UUID). Encapsulé côté client dans une audience par défaut unique | Passez exactement l'un de `--audiences` ou `--paywall-id`. Passer les deux ou aucun provoque une erreur. :::warning `--paywall-id` est obsolète et sera supprimé. Lorsqu'il est passé, le CLI affiche un avertissement sur stderr et convertit la valeur en audience par défaut. Utilisez `--audiences` pour les nouvelles automatisations. ::: ### adapty placements update Remplace tous les champs d'un [placement](placements) existant. ```bash adapty placements update --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` Cette commande remplace tous les champs du placement, y compris la liste complète des audiences. | Argument | Description | |---|---| | `placement-id` | ID du placement (UUID) | | Indicateur | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'app (UUID) | | `--title` | Oui | Titre du placement | | `--developer-id` | Oui | Identifiant string utilisé dans le code de l'app pour requêter ce [placement](placements) | | `--audiences` | L'un des deux | Tableau JSON d'entrées `{segment_ids, paywall_id, priority}`. Voir [Format des audiences](#audiences-shape) | | `--paywall-id` | L'un des deux | **Déprécié.** ID du [paywall](paywalls) (UUID). Remplace toutes les audiences par une seule audience par défaut | :::warning Passer `--paywall-id` réécrit toutes les audiences du placement. Les audiences spécifiques à un segment sont supprimées. Pour les conserver, utilisez `--audiences` et incluez toutes les entrées que vous souhaitez garder. ::: #### Structure des audiences \{#audiences-shape\} Le paramètre `--audiences` prend un tableau JSON. Chaque entrée contient : | Champ | Type | Description | |---|---|---| | `segment_ids` | `string[]` | IDs de [segment](segments) ciblés par cette audience. Longueur 0 ou 1. Un tableau vide marque l'**audience par défaut** — le repli pour les utilisateurs qui ne correspondent à aucun autre segment | | `paywall_id` | `string` | ID de [paywall](paywalls) (UUID) affiché aux utilisateurs de cette audience | | `priority` | `number` | Base 0, unique au sein du placement. Les audiences sont évaluées de la plus basse à la plus haute ; l'audience par défaut doit avoir la valeur la plus élevée | Un placement doit avoir exactement une audience par défaut. Exemple avec une audience ciblée et une audience par défaut : ```bash adapty placements update --app --title "Main" --developer-id "main" \ --audiences '[{"segment_ids":[""],"paywall_id":"","priority":0},{"segment_ids":[],"paywall_id":"","priority":1}]' ``` Pour remplacer un paywall dans plusieurs placements sans perdre le routage par segment : 1. Trouvez les placements concernés : ```bash adapty paywalls placements --app ``` 2. Pour chacun, lisez le tableau `audiences` complet : ```bash adapty placements get --app --json ``` 3. Remplacez les valeurs `paywall_id` correspondantes côté client. 4. Réécrivez le payload modifié : ```bash adapty placements update --app --title "" --developer-id "<developer-id>" --audiences '<modified-payload>' ``` ## Segments \{#segments\} Les [segments](segments) sont en lecture seule via la CLI. Créez-les et modifiez-les dans l'[Adapty Dashboard](https://app.adapty.io). Utilisez ces commandes pour rechercher les ID de segment lors de la composition des audiences de placement. ### adapty segments list Liste tous les [segments](segments) d'une application. ```bash adapty segments list --app <app-id> ``` | Flag | Required | Description | |---|---|---| | `--app` | Yes | App ID (UUID) | Accepte les [drapeaux de pagination](#global-flags). ### adapty segments get Obtenez les détails d'un [segment](segments) spécifique. ```bash adapty segments get --app <app-id> <segment-id> ``` | Argument | Description | |---|---| | `segment-id` | ID du segment (UUID) | | Flag | Requis | Description | |---|---|---| | `--app` | Oui | ID de l'application (UUID) | La réponse contient `id`, `title` et `description`. Les règles de filtrage ne sont pas exposées via cette API. ## Auth \{#auth\} | Commande | Description | |---|---| | `adapty auth login` | S'authentifier via le navigateur en utilisant le flow de l'appareil | | `adapty auth logout` | Supprimer les identifiants stockés localement | | `adapty auth whoami` | Vérifier le token auprès du serveur et afficher les informations de l'utilisateur | | `adapty auth status` | Afficher l'état d'authentification local sans appel au serveur | | `adapty auth revoke` | Révoquer le token côté serveur et le supprimer localement | Consultez [Authentification](developer-cli-authentication) pour tous les détails sur chaque commande. --- # File: getting-started-with-server-side-api --- --- title: "API côté serveur" description: "Démarrez avec l'API côté serveur d'Adapty pour la gestion des abonnements." --- :::tip Vous utilisez un agent de codage IA ? Consultez [Vérifier et accorder l'accès aux abonnements depuis votre backend](server-side-api-with-ai) pour un guide complet en une seule page. ::: Avec l'API, vous pouvez : 1. Vérifier le statut d'abonnement d'un utilisateur. 2. Activer l'abonnement d'un utilisateur avec un niveau d'accès. 3. Récupérer les attributs d'un utilisateur. 4. Définir les attributs d'un utilisateur. 5. Récupérer et mettre à jour les configurations de paywall. <img src="/assets/shared/img/server.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note Pour suivre les événements d'abonnement, utilisez l'intégration [Webhook](webhook) dans Adapty ou intégrez directement votre service existant. ::: ## Cas 1 : Synchroniser les abonnés entre web et mobile \{#case-1-sync-subscribers-between-web-and-mobile\} Si vous utilisez des prestataires de paiement web comme Stripe, ChargeBee ou autres, vous pouvez synchroniser vos abonnés facilement. Voici comment : 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Vérifiez leur statut d'abonnement](api-adapty/operations/getProfile) via l'API. 3. Si un utilisateur est sur un plan freemium, affichez un paywall sur votre site web. 4. Après un paiement réussi, [mettez à jour le statut d'abonnement](api-adapty/operations/setTransaction) dans Adapty via l'API. 5. Vos abonnés resteront automatiquement synchronisés avec votre application mobile. ## Cas 2 : Accorder un abonnement \{#case-2-grant-a-subscription\} :::note Pour des raisons de sécurité, vous ne pouvez pas accorder un abonnement via le SDK. ::: Si vous vendez via votre propre boutique en ligne, l'Amazon Appstore, le Microsoft Store ou toute autre plateforme en dehors de Google Play et de l'App Store, vous devrez synchroniser ces transactions avec Adapty pour fournir l'accès et suivre la transaction dans les analyses. 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Configurez un store personnalisé pour vos produits dans l'Adapty Dashboard](custom-store). 3. Synchronisez la transaction avec Adapty via la requête API [Set transaction](api-adapty/operations/setTransaction). ## Cas 3 : Accorder un niveau d'accès \{#case-3-grant-an-access-level\} Imaginons que vous organisez une promotion offrant un essai gratuit de 7 jours et que vous souhaitez une expérience cohérente sur toutes les plateformes. Pour synchroniser cela avec l'application mobile : 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. Utilisez l'API pour [accorder un accès premium](api-adapty/operations/grantAccessLevel) pendant 7 jours. Après les 7 jours, les utilisateurs qui ne s'abonnent pas seront rétrogradés au niveau gratuit. ## Cas 4 : Synchroniser les propriétés et attributs personnalisés des utilisateurs \{#case-4-sync-users-properties-and-custom-attributes\} Si vous avez des attributs personnalisés pour vos utilisateurs — comme le nombre de mots appris dans une application d'apprentissage des langues — vous pouvez également les synchroniser. 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Mettez à jour l'attribut](api-adapty/operations/updateProfile) via l'API ou le SDK. Ces attributs personnalisés peuvent être utilisés pour créer des segments et lancer des tests A/B. ## Cas 5 : Gérer les configurations de paywall \{#case-5-manage-paywall-configurations\} Vous pouvez [mettre à jour les Remote Configs dans les paywalls](api-adapty/operations/updatePaywall) pour ajuster dynamiquement l'apparence et le comportement de votre paywall sans redéployer votre application. --- **Prochaines étapes :** - Poursuivez avec [l'autorisation pour l'API côté serveur](ss-authorization) - Requêtes : - [Obtenir un profil](api-adapty/operations/getProfile) - [Créer un profil](api-adapty/operations/createProfile) - [Mettre à jour un profil](api-adapty/operations/updateProfile) - [Supprimer un profil](api-adapty/operations/deleteProfile) - [Accorder un niveau d'accès](api-adapty/operations/grantAccessLevel) - [Révoquer un niveau d'accès](api-adapty/operations/revokeAccessLevel) - [Définir une transaction](api-adapty/operations/setTransaction) - [Valider un achat, accorder un niveau d'accès au client et importer son historique de transactions](api-adapty/operations/validateStripePurchase) - [Ajouter des identifiants d'intégration](api-adapty/operations/setIntegrationIdentifiers) - [Obtenir un paywall](api-adapty/operations/getPaywall) - [Lister les paywalls](api-adapty/operations/listPaywalls) - [Mettre à jour un paywall](api-adapty/operations/updatePaywall) --- # File: ss-authorization --- --- title: "Server-side API Authorization and request format" description: "" --- ## Authorization API requests must be authenticated with either your secret or your public API key as an Authorization header. You can find them in the [**App Settings**](https://app.adapty.io/settings/general). The format of the value is `Api-Key {your-secret-api-key}`, for example, `Api-Key secret_live_...`. :::important API keys are app-specific. If you have several apps, ensure you are using different keys for each of them. ::: ## Request format **Headers** The server-side API requests require specific headers and a JSON body. Use the details below to structure your requests. | **Header** | **Description** | | --------------------------- | ------------------------------------------------------------ | | **adapty-profile-id** | <p>The user’s Adapty profile ID. Visible in the **Adapty ID** field in the [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> specific profile page. </p><p>Interchangeable with **adapty-customer-user-id**, use any of them.</p> | | **adapty-customer-user-id** | <p>The user's ID in your system. Visible in the **Customer user ID** field in the [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> specific profile page. </p><p>Interchangeable with **adapty-profile-id**, use any of them.</p><p> ⚠️ Works only if you <InlineTooltip tooltip="identify users in your app">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), and [Unity](unity-identifying-users)</InlineTooltip> in your app code using the Adapty SDK.</p> | | **adapty-platform** | (optional) Specify the platform of the device on which the app is installed. We recommend setting this parameter in the [Create profile](api-adapty/operations/createProfile) and [Update profile](api-adapty/operations/updateProfile) requests when modifying the [Installation Meta](server-side-api-objects#installation-meta) object, as it depends on the device the user is using, and a single user may have multiple devices. Possible values: `iOS`, `macOS`, `iPadOS`, `visionOS`, `Android`, or `web`. | | **Content-Type** | Set to `application/json` for the API to process the request. | **Body** The API expects a JSON-formatted body with the necessary data for the request. ## Rate limits To avoid throttling, ensure that the number of requests (per app) stays below 40,000 per minute. If this limit is exceeded, the system may slow down or temporarily block further requests to maintain optimal performance for all users. ## Rotate API keys If you need to rotate secret API keys: 1. In **Settings → General**, click **Generate new key**, then click the trash icon next to the old key. 2. Update the key used in your app. --- **What's next: requests:** - [Get profile](api-adapty/operations/getProfile) - [Create profile](api-adapty/operations/createProfile) - [Update profile](api-adapty/operations/updateProfile) - [Delete profile](api-adapty/operations/deleteProfile) - [Grant access level](api-adapty/operations/grantAccessLevel) - [Revoke access level](api-adapty/operations/revokeAccessLevel) - [Set transaction](api-adapty/operations/setTransaction) - [Validate purchase, provide access level to customer, and import their transaction history](api-adapty/operations/validateStripePurchase) - [Get paywall](api-adapty/operations/getPaywall) - [List paywalls](api-adapty/operations/listPaywalls) - [Update paywall](api-adapty/operations/updatePaywall) --- # File: server-side-api-specs --- --- title: "Server-side API requests" description: "Explore Adapty’s server-side API specifications for advanced integration." --- Adapty's server-side API empowers you to programmatically access and manage your subscription data, enabling seamless integration with your existing services and infrastructure. Whether you're syncing data across platforms, granting access levels, or validating purchases in Stripe, this API provides the tools to keep your systems in sync and your users engaged. ## Postman collection and environment To simplify using our server-side API, we've prepared a Postman collection and an environment file you can download and import into Postman. - **Request Collection**: Includes all requests available in the Adapty server-side API. Note that it uses variables that you can define in the environment. - **Environment**: Contains a list of variables where you can define values once. We've prepared a unified environment for the server-side API, web API, and analytics export API to make things easier for you. After making this environment active, Postman will automatically substitute the defined variable values in your requests. :::tip [Download the collection and environment](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_server_side_API_postman_collection.zip) ::: For info on how to import a collection and environment to Postman, please refer to the [Postman documentation](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/). ### Variables used We've created a unified environment for the server-side API, web API, and analytics export API to simplify your workflow. Below are the variables specific to the server-side API: | Variable | Description | Example Value | | ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | secret_api_key | You can find it in the **Secret key** field in the [**App settings**](https://app.adapty.io/settings/general). | `secret_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | | adapty-customer-user-id | The user ID used in your system. In the Adapty Dashboard, you can find it in the **Customer user ID** field of the Profile. | `john.doe@example.com` | | adapty-profile-id | The user ID assigned in Adapty. In the Adapty Dashboard, you can find it in the **Adapty ID** field of the Profile. | `3286abd3-48b0-4e9c-a5f6-ac0a006333a6` | | Adapty-platform | The platform used by the user for your app. Possible values: `iOS`, `macOS`, `iPadOS`, `visionOS`, `Android`, `web`. | `iOS` | | stripe_token | Token of a Stripe object representing a unique purchase, such as a Subscription (`sub_XXX`) or Payment Intent (`pi_XXX`). | `sub_1JY8xLLy6P12345a` | **What's next: Requests:** - [Get profile](api-adapty/operations/getProfile) - [Create profile](api-adapty/operations/createProfile) - [Update profile](api-adapty/operations/updateProfile) - [Delete profile](api-adapty/operations/deleteProfile) - [Grant access level](api-adapty/operations/grantAccessLevel) - [Revoke access level](api-adapty/operations/revokeAccessLevel) - [Set transaction](api-adapty/operations/setTransaction) - [Validate purchase, provide access level to customer, and import their transaction history](api-adapty/operations/validateStripePurchase) - [Add integration identifiers](api-adapty/operations/setIntegrationIdentifiers) - [Get paywall](api-adapty/operations/getPaywall) - [List paywalls](api-adapty/operations/listPaywalls) - [Update paywall](api-adapty/operations/updatePaywall) - [Create virtual currency transaction](api-adapty/operations/createVirtualCurrencyTransaction) - [List virtual currency transactions](api-adapty/operations/listVirtualCurrencyTransactions) - [List virtual currency balances](api-adapty/operations/listVirtualCurrencyBalances) --- # File: api-guides --- --- title: "API guides" description: "Learn how to perform specific tasks using the server-side API." --- In this section, you can find guides that cover different use cases and help you perform specific tasks using the server-side API and the Adapty SDK. <CustomDocCardList /> --- # File: sync-subscribers-from-web --- --- title: "Sync purchases between web and mobile" description: "Sync subscribers on web and mobile." --- If your users can purchase a product on your **website**, you can keep their access levels automatically synced with your **mobile app**. In this guide, you will learn how to do it using the Adapty API and SDK. #### Sample use case Let's say, in your app, sers can sign up for a freemium plan on both mobile and web. You allow them to upgrade to a Premium plan on your website via Stripe or Chargebee. Once a user subscribes on the web, you want them to immediately get Premium access in the mobile app — without waiting or re-logging. That’s what Adapty helps you automate. ## Step 1. Identify users Adapty uses `customer_user_id` to identify users across platforms. You should create this ID once and pass it to both your mobile SDK and web backend. ### Sign up from web When your users sign up on your website, you need to create a profile for them in Adapty using the server-side API. See the method reference [here](api-adapty/operations/createProfile). ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/profile/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_CUSTOMER_USER_ID' ``` ### Sign up from app When your users first sign up from the app, you can pass their customer user ID during the SDK activation, or if you have activated the Adapty SDK before the signup stage, use the `identify` method to create a new profile and assign it a customer user ID. :::important If you identify new users after the SDK activation, first, the SDK will create an anonymous profile, as it can't work without any profile at all. Next, when you identify the user and assign them a new customer user ID, a new profile will be created. This behavior is completely normal, and it won't affect the analytics accuracy. Read more [here](ios-quickstart-identify). ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## Step 2. Check subscription status via API When a user logs in on your website, fetch their Adapty profile using the API. If the user doesn’t have an active subscription, you can display a paywall. See the method reference [here](api-adapty/operations/getProfile). ```bash curl --request GET \ --url https://api.adapty.io/api/v2/server-side-api/profile/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'adapty-customer-user-id: YOUR_USER_ID' \ ``` ## Step 3. Display a paywall on your website On your website, show a paywall for freemium users. You can use any payment provider (Stripe, Chargebee, LemonSqueezy, etc.). ## Step 4. Update subscription status in Adapty After the payment is completed on your website, call Adapty API to update the user’s access level according to the product they bought. See the method reference [here](api-adapty/operations/grantAccessLevel). ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_USER_ID' \ --data '{ "access_level_id": "YOUR_ACCESS_LEVEL" }' ``` ## Step 5. Sync status in the app When the user opens your mobile app, pull the updated profile and unlock paid features. You need to either get their profile or sync it automatically. Then, get the access level from it. Below, you see how to get the profile and check its status. For more details, go [here](ios-check-subscription-status). <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: sync-purchases-from-custom-stores --- --- title: "Sync transactions from custom stores" description: "Sync transactions from custom stores to Adapty to provide access and track revenue." --- If you're selling subscriptions or in-app purchases through **custom stores** like Amazon Appstore, Microsoft Store, or your own payment platform, you can sync those transactions with Adapty to automatically manage access levels and track revenue in your analytics. In this guide, you'll learn how to connect custom store purchases with Adapty using the SDK and API. #### Sample use case Let's say you're distributing your app on Amazon Appstore, or you've built your own web store for direct purchases. When a user completes a purchase through these platforms, you want to: - Automatically grant them access to premium features in your mobile app - Track the transaction in Adapty analytics alongside your App Store and Google Play revenue - Trigger integrations and webhooks just like any other subscription That's what this integration helps you achieve. ## Step 1. Identify users Adapty uses `customer_user_id` to identify users across platforms. You need to create this ID once and pass it to both your mobile SDK and web backend. When your users first sign up from the app, you can pass their customer user ID during the SDK activation, or if you have activated the Adapty SDK before the signup stage, use the `identify` method to create a new profile and assign it a customer user ID. :::important If you identify new users after SDK activation, the SDK will first create an anonymous profile (it can't work without one). When you call `identify` with a customer user ID, a new profile will be created. This behavior is normal and won't affect analytics accuracy. Read more [here](ios-quickstart-identify). ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## Step 2. Create products in a custom store in Adapty Dashboard For Adapty to match custom store transactions with your products, you need to add products and and set up the custom store details for them. 1. Go to [**Products**](https://app.adapty.io/settings/general) from the left menu in the Adapty Dashboard and click **Create product**. Or, click an existing product to edit it. 2. Ensure you have selected an [access level](access-level) you want to grant users purchasing the product. 3. Click **+** and select **Add a custom store**. 4. Click **Create new custom store**. 5. Give your store a name (e.g., "Amazon Appstore", "Microsoft Store", or "Web Store") and ID. Click **Create custom store**. 6. Then, click **Save changes** to link the product to the custom store. 7. Enter **Store product ID** for the product, so you map it with some product in that store. Then, click **Save**. ## Step 3. Sync transactions via API When a purchase is completed in your custom store, you need to sync it to Adapty using the server-side API. This API call will: - Record the transaction in Adapty - Grant the corresponding access level to the user - Trigger any integrations and webhooks you've configured - Make the transaction appear in your analytics See the full method reference [here](api-adapty/operations/setTransaction). ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/set/transaction/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_CUSTOMER_USER_ID' \ --data '{ "purchase_type": "PRODUCT_PERIOD", "store": "YOUR_CUSTOM_STORE", "environment": "production", "store_product_id": "YOUR_STORE_PRODUCT_ID", "store_transaction_id": "STORE_TRANSACTION_ID", "store_original_transaction_id": "ORIGINAL_TRANSACTION_ID", "price": { "country": "COUNTRY_CODE", "currency": "CURRENCY_CODE", "value": "YOUR_PRICE" }, "purchased_at": "2024-01-15T10:30:00Z" }' ``` :::important Important parameters: - **store**: The ID of your custom store from Step 2 - **store_product_id**: Store product ID from Step 2 - **store_transaction_id**: A unique identifier for this transaction - **purchased_at**: ISO 8601 timestamp when the purchase occurred - **price**: The amount paid by the user ::: ## Step 4. Verify access in the app Once the transaction is synced, the user's profile will be automatically updated with the new access level. When the user opens your mobile app, fetch their profile to check their subscription status and unlock premium features. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: grant-access-level --- --- title: "Grant access levels manually" description: "Unlock paid features manually for specific users or user groups" --- If you need to **manually unlock premium features** for specific users or user groups, you can do it using the Adapty API. This is useful for promotional campaigns, investor access, or special customer support cases. In this guide, you'll learn how to identify users and grant them access levels programmatically. #### Sample use cases - **Promo codes**: When users enter a valid promo code in your app, automatically grant them access to premium features. - **Investor/beta tester access**: Provide premium access to investors or beta testers by checking their custom attributes. :::note **Google Play promo codes**: A purchase made by redeeming a Google Play promotional code can arrive without an `orderId`. Adapty's one-time (non-subscription) purchase validation requires an `orderId`, so these redemptions aren't validated or granted automatically. Grant access manually with the steps below — the Server-Side API doesn't depend on an `orderId`. ::: ## Step 1. Identify users Adapty uses `customer_user_id` to identify users across platforms and devices. This is crucial for ensuring users keep their access after reinstalling the app or switching devices. You need to create this ID once. When users first sign up from the app, you can pass their customer user ID during SDK activation, or use the `identify` method if the SDK was activated before signup. :::important If you identify new users after SDK activation, the SDK will first create an anonymous profile (it can't work without one). When you call `identify` with a customer user ID, a new profile will be created. This behavior is normal and won't affect analytics accuracy. Read more [here](ios-quickstart-identify). ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## Step 2. Grant access level via API Once a user is identified with a `customer_user_id`, you can grant them access levels using the server-side API. This API call will grant the access level to the user, so they can access paid features without actually paying. See the full method reference [here](api-adapty/operations/grantAccessLevel). :::tip You can control user access by adding a custom attribute (e.g., Beta tester or Investor) in the Adapty dashboard. When your app launches, [check this attribute in the user’s profile](subscription-status) to grant access automatically. To update access, just change the attribute in the dashboard. ::: ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: CUSTOMER_USER_ID' \ --data '{ "access_level_id": "YOUR_ACCESS_LEVEL" }' ``` ## Step 3. Verify access in the app After granting access via API, the user's profile will be automatically updated. Fetch their profile to check their subscription status and unlock premium features. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL_ID"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: web-api --- --- title: Adapty Web API description: "" --- The Web API is an extension of the server-side API designed for use with web apps. It allows you to retrieve the correct paywall using its related placement ID and record paywall views for accurate conversion tracking. This helps you use the A/B testing and paywall personalization available within Adapty, as well as track which paywalls work the best. ## Use case: Record a transaction from your web app and link it to the used paywall Let's say you sell products in your web app. You need to display a paywall to your users, let them purchase a product, and then add the transaction details to Adapty. It’s essential to link these transactions to the specific paywalls through which the user made the purchase so that your analytics reflects accurate data. This can be easily accomplished using the Adapty API ### Prerequisites 1. [Create the products](create-product) you’ll use in the paywall within the Adapty Dashboard. 2. [Create the paywall](create-paywall) in the Adapty Dashboard. [Use remote config](customize-paywall-with-remote-config) to design your web paywall. 3. [Set up a placement](create-placement) and link the paywall to it in the Adapty Dashboard. ### Steps with Adapty API 1. **Create a user profile:** Adapty relies on having a profile before requesting a paywall to personalize the end result to the user who requested it. Use the [Create profile](api-adapty/operations/createProfile) request to create a user profile. 2. **Fetch and display the paywall:** When the user reaches the placement in your web app where the paywall should be shown, use the [Get paywall](api-web/operations/getPaywall) request to retrieve the paywall via the [placement ID](placements). As a result, you'll get a paywall for the [audience](audience) corresponding to your user. Display the paywall with your code, using the returned products and (optionally) this paywall's [remote config](customize-paywall-with-remote-config). 3. **Record the paywall view:** Use the [Record paywall view](api-web/operations/recordPaywallView) to log the paywall view with Adapty to ensure your analytics accurately reflect the event. This is vital to track conversions correctly. 4. **Record the purchase:** If the user completes a purchase, send the transaction details to Adapty using the Adapty API. Include the **variation ID** in this request to link the transaction to the specific paywall displayed. For guidance, check out our page on [associating paywalls with transactions in mobile apps](report-transactions-observer-mode)—the same approach applies to web apps. 5. **Add marketing attribution data (if applicable):** If you have any marketing attribution data (e.g., campaign or ad details), use the [Add attribution](api-web/operations/addAttribution) to merge it into the user profile to enrich the analytics and learn more about your ad performance in Adapty. --- **What's next:** - Proceed with [Web API authorization](web-api-authorization) - Requests: - [Add attribution](api-web/operations/addAttribution) - [Get paywall](api-web/operations/getPaywall) - [Record paywall view](api-web/operations/recordPaywallView) --- # File: web-api-authorization --- --- title: Authorization and Request format for Web API description: "" --- ## Authorization API requests must be authenticated by your public API key as the **Authorization** header with the value `Api-Key {your_public_api_key}`, for example, `Api-Key public_live_...`. Find this key in the [Adapty Dashboard -> **App Settings** -> **General** tab -> **API keys** section](https://app.adapty.io/settings/general). :::important API keys are app-specific. If you have several apps, ensure you are using different keys for each of them. ::: ## Request format - **Content-Type header**: Set the **Content-Type** header to `application/json` for the API to process your request. - **Body**: The API expects the request to use the body as JSON. --- # File: web-api-requests --- --- title: " Web API Requests" description: "" --- Adapty's server-side API empowers you to programmatically access and manage your subscription data, enabling seamless integration with your existing services and infrastructure. Whether you're syncing data across platforms, granting access levels, or validating purchases in Stripe, this API provides the tools to keep your systems in sync and your users engaged. ## Postman collection and environment To simplify using our web API, we've prepared a Postman collection and an environment file you can download and import into Postman. - **Request Collection**: Includes all requests available in the Adapty web API. Note that it uses variables that you can define in the environment. - **Environment**: Contains a list of variables where you can define values once. We've prepared a unified environment for the server-side API, web API, and analytics export API to make things easier for you. After making this environment active, Postman will automatically substitute the defined variable values in your requests. :::tip [Download the collection and environment](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_Web_API_postman_collection.zip) ::: For info on how to import a collection and environment to Postman, please refer to the [Postman documentation](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/). ## Variables used We've created a unified environment for the server-side API, web API, and analytics export API to simplify your workflow. Below are the variables specific to the web API: | Variable | Description | Example Value | | ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | public_api_key | You can find it in the **Public SDK key** field in the [**App settings**](https://app.adapty.io/settings/general). | `public_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | | adapty-customer-user-id | The user ID used in your system. In the Adapty Dashboard, you can find it in the **Customer user ID** field of the Profile. | `john.doe@example.com` | | adapty-profile-id | The user ID assigned in Adapty. In the Adapty Dashboard, you can find it in the **Adapty ID** field of the Profile. | `3286abd3-48b0-4e9c-a5f6-ac0a006333a6` | **What's next: Requests:** - [Get paywall](api-web/operations/getPaywall) - [Record paywall view](api-web/operations/recordPaywallView) - [Add attribution](api-web/operations/addAttribution) --- # File: export-analytics-api --- --- title: Exporting analytics with API --- Exporting your analytics data to CSV gives you the flexibility to dive deeper into your app’s performance metrics, customize reports, and analyze trends over time. With the Adapty API, you can easily pull detailed analytics into a CSV format, making it convenient to track, share, and refine your data insights as needed. :::tip Using an AI agent or LLM to pull analytics? See [Export your analytics with an AI agent](export-analytics-with-ai). ::: ## Getting started with the API for analytics export With the analytics export API, you can, for example: 1. **Analyze MRR from Marketing Campaigns**: Measure the impact of last year's marketing campaigns in a specific country to see which ones brought in the highest revenue, with weekly tracking. Use the [Retrieve analytics data](api-export-analytics/operations/retrieveAnalyticsData) method for this. 2. **Track Cohort Retention Over Time**: Follow retention by cohort to spot drop-off points and compare cohorts over time, revealing trends and key moments where engagement strategies could boost retention. Limited to a specific app store, a specific country, and a particular product. Use the [Retrieve cohort data](api-export-analytics/operations/retrieveCohortData) method for this. 3. **Evaluate Conversion Rates Across Channels**: Analyze conversion rates for key acquisition channels to see which are most effective in driving first-time purchases. This helps prioritize marketing spending on high-performing channels. Use the [Retrieve conversion data](api-export-analytics/operations/retrieveConversionData) method for this. 4. **Review Churn Rate**: Monitor how quickly users are unsubscribing to uncover churn patterns or gauge the success of retention efforts, focusing on a specific country and a specific product. Use the [Retrieve funnel data](api-export-analytics/operations/retrieveFunnelData) method for this. 5. **Assess LTV by User Segment**: Identify the lifetime value of different user segments to understand which groups bring in the highest revenue over time. Focus on high-value segments like long-term subscribers, and use the results to refine acquisition strategies. Use the [Retrieve LTV data](api-export-analytics/operations/retrieveLTVData) method for this. 6. **Check Retention by Country**: Look at retention rates by region to find high-engagement markets and guide localization or regional strategies. Use the [Retrieve retention data](api-export-analytics/operations/retrieveRetentionData) method for this. --- **What's next**: - [Authorization and request format](export-analytics-api-authorization) - [Exporting analytics API requests](export-analytics-api-requests) --- # File: export-analytics-api-authorization --- --- title: Authorization and request format for Exporting analytics API --- ## Authorization You need to authenticate your API requests with your secret API key as an Authorization header. You can find it in the [App Settings](https://app.adapty.io/settings/general). The format is `Api-Key {YOUR_SECRET_API_KEY}`, for example: `Api-Key secret_live_...`. :::important API keys are app-specific. If you have several apps, ensure you are using different keys for each of them. ::: ## Request format **Headers** The server-side API requests require specific headers and a JSON body. Use the details below to structure your requests: | Header | Description | | ------------ | ------------------------------------------------------------ | | Content-Type | (Required) Set to `application/json` for the API to process the request. | | Adapty-Tz | (Optional) Set the timezone to define how the data is grouped and displayed. Use the [IANA Time Zone Database format](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g., `Europe/Berlin`). | ## Body The API expects a JSON-formatted body with the necessary data for the request. ## Rate limits The maximum is 2 requests per second per API key. Exceeding this limit returns a `429 Too Many Requests` error. ## Rotate API keys If you need to rotate secret API keys: 1. In **Settings → General**, click **Generate new key**, then click the trash icon next to the old key. 2. Update the key used in your app. --- **What's next: Requests:** - [Retrieve analytics data](api-export-analytics/operations/retrieveAnalyticsData) - [Retrieve cohort data](api-export-analytics/operations/retrieveCohortData) - [Retrieve conversion data](api-export-analytics/operations/retrieveConversionData) - [Retrieve funnel data](api-export-analytics/operations/retrieveFunnelData) - [Retrieve Lifetime Value (LTV) data](api-export-analytics/operations/retrieveLTVData) - [Retrieve retention data](api-export-analytics/operations/retrieveRetentionData) --- # File: export-analytics-api-requests --- --- title: Exporting analytics API requests --- Exporting your analytics data to CSV gives you the flexibility to dive deeper into your app’s performance metrics, customize reports, and analyze trends over time. With the Adapty API, you can easily pull detailed analytics into a CSV format, making it convenient to track, share, and refine your data insights as needed. ## Postman collection and environment To simplify using our API for exporting analytics data, we've prepared a Postman collection and an environment file you can download and import into Postman. - **Request Collection**: Includes all requests available in the Adapty analytics export API. Note that it uses variables that you can define in the environment. - **Environment**: Contains a list of variables where you can define values once. We've prepared a unified environment for the server-side API, web API, and analytics export API to make things easier for you. After making this environment active, Postman will automatically substitute the defined variable values in your requests. :::tip [Download the collection and environment](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_export_analytics_API_postman_collection.zip) ::: For info on how to import a collection and environment to Postman, please refer to the [Postman documentation](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/). ### Variables used We've created a unified environment for the server-side API, web API, and analytics export API to simplify your workflow. Below are the variables specific to the analytics export API: | Variable | Description | Example Value | | ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | secret_api_key | You can find it in the **Secret key** field in the [**App settings**](https://app.adapty.io/settings/general). | `secret_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | **Requests:** - [Retrieve analytics data](api-export-analytics/operations/retrieveAnalyticsData) - [Retrieve cohort data](api-export-analytics/operations/retrieveCohortData) - [Retrieve conversion data](api-export-analytics/operations/retrieveConversionData) - [Retrieve funnel data](api-export-analytics/operations/retrieveFunnelData) - [Retrieve Lifetime Value (LTV) data](api-export-analytics/operations/retrieveLTVData) - [Retrieve retention data](api-export-analytics/operations/retrieveRetentionData) --- # End of Documentation _Generated on: 2026-08-04T15:08:25.937Z_ _Successfully processed: 17/18 files_ # CAPACITOR - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:25.938Z Total files: 45 --- # File: capacitor-sdk-overview --- --- title: "Présentation du SDK Capacitor" description: "Découvrez le SDK Adapty pour Capacitor et ses principales fonctionnalités." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Capacitor.svg?style=flat&logo=capacitor)](https://github.com/adaptyteam/AdaptySDK-Capacitor/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le [SDK Adapty pour Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/) pour vous libérer des contraintes liées aux achats intégrés, afin que vous puissiez vous concentrer sur ce que vous faites le mieux — créer des applications exceptionnelles. Voici ce que nous gérons pour vous : - Gestion des achats, validation des reçus et gestion des abonnements clés en main - Création et test de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans configuration — cohortes, LTV, taux de désabonnement et analyse de l'entonnoir inclus - Maintien du statut d'abonnement de l'utilisateur toujours à jour entre les sessions et les appareils - Intégration de votre application avec des services d'attribution marketing et d'analyse en une seule ligne de code :::note Avant de plonger dans le code, vous devrez intégrer Adapty avec App Store Connect et Google Play Console, puis configurer des produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Démarrer \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons aborder dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-capacitor) : Ajoutez le SDK comme [dépendance](https://www.npmjs.com/package/@adapty/capacitor) à votre projet et activez-le dans le code. 2. [Activer les achats via les paywalls](capacitor-quickstart-paywalls) : Configurez le flux d'achat pour que les utilisateurs puissent acheter des produits. 3. [Vérifier le statut de l'abonnement](capacitor-check-subscription-status) : Vérifiez automatiquement l'état d'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (optionnel)](capacitor-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir la cohérence de leurs données sur tous les appareils. ### Voir en action \{#see-it-in-action\} Vous voulez voir comment tout s'assemble ? Nous avons ce qu'il vous faut : **Exemples d'applications** : Consultez nos exemples complets qui illustrent la configuration complète : - [React](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example) - [Vue.js](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example) - [Angular](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example) - [Outils de développement avancés](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools) ## Concepts principaux \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts clés qui font fonctionner Adapty. L'approche d'Adapty repose sur le fait que seuls les placements sont codés en dur dans votre application. Tout le reste — produits, designs de paywalls, tarification et offres — peut être géré de manière flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. **Produit** - Tout ce qui est disponible à l'achat dans votre application — abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Des produits regroupés avec une configuration, rattachés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, créée dans le Flow Builder. Adapty affiche l'interface utilisateur et gère l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous créez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](capacitor-quickstart-manual). Dans le code du SDK, les deux sont récupérés via la même méthode `getFlow`. 3. **Placement** - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un paywall. Considérez les placements comme le « où » et le « quand » de votre stratégie de monétisation. Les placements courants incluent : - `main` - Votre emplacement de paywall principal - `onboarding` - Affiché pendant le flow d'onboarding utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis réfléchissez aux autres endroits dans votre application où les utilisateurs pourraient être prêts à acheter. 4. **Profil** - Lorsque les utilisateurs achètent un produit, leur profil se voit attribuer un **niveau d'accès** que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-capacitor --- --- title: "Capacitor - Installation & configuration du SDK Adapty" description: "Guide étape par étape pour installer le SDK Adapty sur Capacitor pour les applications basées sur des abonnements." --- Le SDK Adapty comprend deux modules essentiels pour une intégration fluide dans votre application Capacitor : - **Core Adapty** : Ce module est indispensable au bon fonctionnement d'Adapty dans votre application. - **AdaptyUI** : Ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. AdaptyUI est automatiquement activé avec le module principal. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et autres fonctionnalités de base. ::: ## Prérequis \{#requirements\} Le [SDK Adapty Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/) requiert les versions suivantes : | Version du SDK Adapty | Version de Capacitor | Version iOS | |-----------------------|----------------------|-------------| | 3.16.0+ | 8 | 15.0+ | | 3.15 | 7 | 14.0+ | Les versions 6 et inférieures de Capacitor ne sont pas prises en charge. La création pour iOS avec Adapty SDK v4 (bêta) nécessite **Xcode 26** ou version ultérieure — le SDK iOS natif qu'il utilise est compilé avec Swift tools 6.2. Les exigences iOS 15.0+, Capacitor 8 et Android minSdk 24 sont identiques à celles du SDK 3.16+. :::info À partir du SDK v3.17, Adapty SDK utilise Google Play Billing Library v8.0.0 par défaut. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} :::important Les étapes ci-dessous installent le SDK Adapty 3.x. Le SDK v4 (bêta) — requis pour le [Flow Builder](adapty-flow-builder) et utilisé par le [démarrage rapide](capacitor-quickstart-paywalls) — s'installe différemment : suivez [SDK Adapty 4.0 (bêta)](#adapty-sdk-40-beta) ci-dessous, ou consultez le [guide de migration](migration-to-capacitor-sdk-v4). ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Capacitor.svg?style=flat&logo=capacitor)](https://github.com/adaptyteam/AdaptySDK-Capacitor/releases) Installez le SDK Adapty : ```sh npm install @adapty/capacitor npx cap sync ``` ### Adapty SDK 4.0 (beta) Capacitor SDK 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — est une version préliminaire. Installez la version exacte (npm ne résout pas les pré-versions via les plages caret/tilde), puis synchronisez : ```sh npm install @adapty/capacitor@4.0.1-beta.1 ``` ```sh npx cap sync ``` Sur iOS, la v4 récupère les SDK natifs Adapty via **Swift Package Manager uniquement** — le podspec CocoaPods a été supprimé ([le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). Le projet iOS de votre application doit utiliser l'intégration SPM de Capacitor : - Pour les nouvelles applications, ajoutez la plateforme iOS avec le gestionnaire de paquets SPM : ```sh npx cap add ios --packagemanager SPM ``` - Pour les applications existantes, migrez le projet iOS de CocoaPods vers SPM en suivant [le guide Capacitor pour utiliser SPM dans un projet existant](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project). Pour la liste complète des changements d'API en v4, consultez [Migrer le SDK Adapty Capacitor vers la v4](migration-to-capacitor-sdk-v4). ## Activer le module Adapty du SDK \{#activate-adapty-module-of-adapty-sdk\} :::note Le SDK n'a besoin d'être activé qu'une seule fois dans votre application. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. Copiez le code suivant dans n'importe quel fichier de l'application pour activer Adapty : ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // verbose logging is recommended for the development purposes and for the first production release logLevel: 'verbose', // in the development environment, use this variable to avoid multiple activation errors. Set it to your development environment variable __ignoreActivationOnFastRefresh: true, } }); console.log('Adapty activated successfully!'); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` :::important Attendez que `activate` soit résolu avant d'appeler toute autre méthode du SDK Adapty. Consultez [L'ordre des appels dans le SDK Capacitor](capacitor-sdk-call-order) pour la séquence complète. ::: :::tip Pour éviter les erreurs d'activation en environnement de développement, utilisez les [conseils](#development-environment-tips). ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), suivez le [démarrage rapide avec Paywall Builder](capacitor-quickstart-paywalls). - Si vous construisez votre propre interface de paywall, consultez le [démarrage rapide pour les paywalls personnalisés](capacitor-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder), vous avez besoin du module AdaptyUI. Il est activé automatiquement lors de l'activation du module principal ; vous n'avez rien d'autre à faire. ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux disponibles sont les suivants : | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Seules les erreurs seront enregistrées | | `warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais qui méritent attention, seront enregistrés | | `info` | Les erreurs, avertissements et divers messages d'information seront enregistrés | | `verbose` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera enregistrée | Vous pouvez définir le niveau de log dans votre application avant ou pendant la configuration d'Adapty : ```typescript showLineNumbers // Set log level before activation adapty.setLogLevel({ logLevel: 'verbose' }); // Or set it during configuration await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { logLevel: 'verbose', } }); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs, sauf si vous les envoyez explicitement. Vous pouvez toutefois mettre en place des politiques de sécurité des données supplémentaires pour respecter les directives du store ou de votre pays. #### Désactiver la collecte et le partage des adresses IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` à `true` pour désactiver la collecte et le partage des adresses IP des utilisateurs. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutile lorsque les fonctionnalités basées sur l'IP ne sont pas requises pour votre application. ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ipAddressCollectionDisabled: true, } }); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ios.idfaCollectionDisabled` (iOS) ou `android.adIdCollectionDisabled` (Android) sur `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour respecter les politiques de l'App Store/Play Store, éviter de déclencher la demande App Tracking Transparency, ou si votre application n'a pas besoin d'attribution publicitaire ni d'analytics basée sur des identifiants publicitaires. ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, } }); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire l'utilisation du réseau. Vous pouvez personnaliser ces paramètres en fournissant une configuration personnalisée. Utilisez `mediaCache` pour remplacer les paramètres de cache par défaut : ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, } }); ``` | Paramètre | Requis | Description | |-----------|--------|-------------| | memoryStorageTotalCostLimit | optionnel | Taille totale du cache en mémoire, en octets. Valeur par défaut spécifique à la plateforme. | | memoryStorageCountLimit | optionnel | Limite du nombre d'éléments dans le stockage en mémoire. Valeur par défaut spécifique à la plateforme. | | diskStorageSizeLimit | optionnel | Limite de taille des fichiers sur le disque, en octets. Valeur par défaut spécifique à la plateforme. | ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont activés sur iOS et désactivés sur Android. Pour les activer également sur Android, définissez `localAccessLevelAllowed` sur `true` : ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { localAccessLevelAllowed: true, }, } }); ``` ### Effacer les données lors d'une restauration depuis une sauvegarde \{#clear-data-on-backup-restore\} Lorsque `clearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, notamment les informations de profil mises en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état vierge. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ios: { clearDataOnBackup: true, }, } }); ``` ## Conseils pour l'environnement de développement \{#development-environment-tips\} #### Résoudre les erreurs d'activation du SDK avec le rechargement en direct de Capacitor \{#troubleshoot-sdk-activation-errors-on-capacitors-live-reload\} Lors du développement avec le SDK Adapty dans Capacitor, vous pouvez rencontrer l'erreur : `Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` Ce problème survient car la fonctionnalité de rechargement en direct de Capacitor déclenche plusieurs appels d'activation pendant le développement. Pour l'éviter, utilisez l'option `__ignoreActivationOnFastRefresh` définie sur l'indicateur de mode développement de Capacitor – il diffère selon le bundle que vous utilisez. ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // Set your development environment variable __ignoreActivationOnFastRefresh: true, } }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` ## Dépannage \{#troubleshooting\} #### Erreur de version iOS minimale \{#minimum-ios-version-error\} :::note Ceci s'applique aux projets basés sur CocoaPods avec le **SDK 3.x**. Le SDK 4.0 s'installe sur iOS via Swift Package Manager uniquement (il n'y a pas de `Podfile`) et nécessite iOS 15.0 — définissez votre cible de déploiement sur 15.0 dans Xcode. ::: Si vous obtenez une erreur de version iOS minimale avec le SDK 3.x, mettez à jour votre Podfile : ```diff -platform :ios, min_ios_version_supported +platform :ios, '15.0' ``` #### Règles de sauvegarde Android (configuration Auto Backup) \{#android-backup-rules-auto-backup-configuration\} Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules` ou `android:allowBackup`. Symptômes typiques : `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 Ces modifications doivent être effectuées dans votre répertoire de la plateforme Android (généralement situé dans le dossier `android/` de votre projet). ::: Pour résoudre ce problème, vous devez : - Indiquer au gestionnaire de fusion de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Créer des fichiers de règles de sauvegarde qui fusionnent les règles d'Adapty avec celles des autres SDKs. #### 1. Ajoutez l'espace de noms `tools` à votre manifeste \{#1-add-the-tools-namespace-to-your-manifest\} Dans votre fichier `AndroidManifest.xml`, assurez-vous que la balise racine `<manifest>` inclut tools : ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. Remplacez les attributs de sauvegarde dans `<application>` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `<application>` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion de remplacer les valeurs des bibliothèques : ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez les fichiers de règles de sauvegarde fusionnés \{#3-create-merged-backup-rules-files\} Créez des fichiers XML dans le répertoire `res/xml/` de votre projet Android, en combinant les règles d'Adapty avec celles des autres SDKs. Android utilise des formats de règles de sauvegarde différents selon la version de l'OS, donc créer les deux fichiers garantit la compatibilité avec toutes les versions d'Android prises en charge par votre application. :::note Les exemples ci-dessous utilisent AppsFlyer comme exemple de SDK tiers. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::tip Après avoir modifié des fichiers Android natifs, exécutez `npx cap sync android` pour que Capacitor prenne en compte les ressources mises à jour si vous regénérez la plateforme. ::: #### Les achats échouent au retour d'une autre application sur Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si l'Activity qui démarre le flow d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser incorrectement lorsque l'utilisateur revient de Google Play, d'une application bancaire ou d'un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son interprétation comme une annulation. Pour vous assurer que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flux d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui démarre le flux d'achat est configurée sur `standard` ou `singleTop` : ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Erreurs de build Swift 6 causées par la substitution de SWIFT_VERSION dans le Podfile :::note Cela s'applique aux projets basés sur CocoaPods avec le **SDK 3.x**. Le SDK 4.0 installe les SDK natifs via Swift Package Manager, il n'y a donc pas de `Podfile` à modifier. ::: Lors de la compilation de votre application Capacitor pour iOS, vous pouvez rencontrer des erreurs de compilation Swift 6 sur les targets de pods Adapty. Les symptômes typiques incluent des incompatibilités `@Sendable` dans `AdaptyUIBuilderLogic`, une conformité `Sendable` manquante sur les types Adapty, ou des erreurs d'isolation d'acteur. Les pods Adapty déclarent `s.swift_version = '6.0'` et nécessitent Swift 6 pour compiler. Votre propre code d'application peut rester en Swift 5 — seuls les targets des pods Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`, `AdaptyLogger`, `AdaptyPlugin`) ont besoin d'être compilés avec Swift 6. La cause la plus fréquente est un hook `post_install` dans `ios/App/Podfile` qui réécrit `SWIFT_VERSION` pour chaque target de pod : ```ruby showLineNumbers title="ios/App/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` **Correctif** : Excluez les cibles de pod Adapty de la surcharge : ```ruby showLineNumbers title="ios/App/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name) target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` Ensuite, exécutez `npx cap sync ios` et recompilez. Pour vérifier, ouvrez `ios/App/Pods/Pods.xcodeproj`, sélectionnez la cible du pod `Adapty` → **Build Settings** → **Swift Language Version**. La valeur devrait être **Swift 6**. --- # File: capacitor-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK Capacitor" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – séquences d'écrans qui présentent des produits aux utilisateurs, construites dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez un paywall à la place — voir [Implémenter des paywalls manuellement](capacitor-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez des flows dans votre application (comme `main`, `onboarding`, `settings`). Vous associez des flows à des placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond le mieux à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty l'affiche automatiquement et gère tout le processus d'achat, la validation des reçus et la gestion des abonnements en coulisses. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez votre interface de paywall dans le code de votre application, mais récupérez quand même l'objet flow depuis Adapty pour garder de la flexibilité sur les offres de produits. Voir le [guide](capacitor-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limitations dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.** Si vous préférez construire vous-même l'interface du paywall, voir [Implémenter des paywalls manuellement](capacitor-quickstart-manual). ::: Pour afficher un flow créé dans Adapty Flow Builder, vous n'avez besoin que de : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et Adapty gérera les achats à votre place** : Affichez la vue dans votre application. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans l'Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez-y votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-capacitor) dans le code de votre application. Ce guide utilise les API Adapty Capacitor SDK v4. ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter différents flows pour différentes audiences ou de lancer des [tests A/B](ab-tests). Pour obtenir un flow créé dans Adapty Flow Builder, récupérez l'objet `flow` par l'ID de [placement](placements) à l'aide de la méthode `getFlow`. Le flow contient les éléments d'interface et le style nécessaires à son affichage. ```typescript showLineNumbers title="Capacitor" try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow } catch (error) { // handle the error } ``` ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez le flow, quelques lignes suffisent pour l'afficher. Créez une `view` avec la méthode `createFlowView`, définissez ses gestionnaires d'événements, puis appelez `view.present()`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. ```typescript showLineNumbers title="Capacitor" try { const view = await createFlowView(flow); await view.setEventHandlers({ onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases }, }); await view.present(); } catch (error) { // handle the error } ``` :::tip Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](capacitor-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Capacitor gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des URL. Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent de gérer les actions dans votre code. Vous pouvez également vouloir remplacer leur comportement par défaut. Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire. ```typescript showLineNumbers title="Capacitor" const unsubscribe = await view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` :::tip Consultez nos guides sur la gestion des [actions](capacitor-handle-paywall-actions) et des [événements](capacitor-handling-events) des boutons. ::: ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'application. [Testez vos achats](capacitor-test) pour vous assurer de pouvoir effectuer un achat test depuis le flow. Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](capacitor-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment intégrer ensemble toutes les étapes de ce guide dans votre application. ```typescript showLineNumbers title="Capacitor" export async function showFlow() { try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); const view = await createFlowView(flow); await view.setEventHandlers({ onCloseButtonPress() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases }, }); await view.present(); } catch (error) { // handle any error that may occur during the process console.warn('Error showing flow:', error); } } ``` --- # File: capacitor-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK Capacitor" description: "Apprenez à vérifier le statut d'abonnement dans votre app Capacitor avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil afin de déterminer ce que l'utilisateur doit voir — lui afficher un paywall ou lui donner accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appelez `getProfile` si vous avez besoin des dernières données du profil immédiatement (par exemple au démarrage de l'app) ou si vous souhaitez forcer une mise à jour. - Configurez des **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement dès que le statut d'abonnement change. ### Récupérer le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour du profil dans votre app : 1. Utilisez `adapty.addListener('onLatestProfileLoad')` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode chaque fois que le statut d'abonnement de l'utilisateur change. 2. Stockez les données du profil mis à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser partout dans votre app sans effectuer de requêtes réseau supplémentaires. ```typescript showLineNumbers class SubscriptionManager { private currentProfile: any = null; constructor() { // Listen for profile updates adapty.addListener('onLatestProfileLoad', (data) => { this.currentProfile = data.profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() hasAccess(): boolean { return this.currentProfile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive ?? false; } } ``` :::note Adapty appelle automatiquement le listener d'événement `onLatestProfileLoad` au démarrage de votre app, fournissant les données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Connecter le profil avec la logique de paywall \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates concernant l'affichage de paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier le profil de l'utilisateur directement. Cette approche est utile dans des scénarios comme le démarrage de l'app, l'accès aux sections premium ou l'affichage de contenus spécifiques. ```typescript showLineNumbers const checkAccessLevel = async () => { try { const profile = await adapty.getProfile(); return profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive === true; } catch (error) { console.warn('Error checking access level:', error); return false; // Show paywall if access check fails } }; const getAccessLevel = (profile: AdaptyProfile) => { return profile.accessLevels?.['YOUR_ACCESS_LEVEL']; }; const initializePaywall = async () => { try { await loadPaywall(); const hasAccess = await checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } catch (error) { console.warn('Error initializing paywall:', error); } }; ``` ## Étapes suivantes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](capacitor-quickstart-identify) pour vous assurer qu'ils ont accès à ce pour quoi ils ont payé. --- # File: capacitor-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK Capacitor" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans Capacitor." --- La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). :::tip **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. Ils peuvent être anonymes (sans identifiant utilisateur client) ou identifiés (avec un identifiant utilisateur client). - Les **identifiants utilisateur client** sont des identifiants optionnels **que vous créez** pour permettre à Adapty de lier vos utilisateurs à leurs profils Adapty. ::: Voici les différences entre les utilisateurs anonymes et les utilisateurs identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |-----------------------------|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats maintenu sur tous les appareils via leur identifiant utilisateur client | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil entre les sessions et les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'appareil/installation | Les données des utilisateurs identifiés persistent entre les appareils et les sessions | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lors de l'activation du SDK au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, cet achat est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil vide lors de l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, ceux-ci sont, par défaut, automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. :::note Les restaurations depuis une sauvegarde se comportent différemment des réinstallations. Par défaut, lorsqu'un utilisateur restaure depuis une sauvegarde, le SDK conserve les données en cache et ne crée pas de nouveau profil. Vous pouvez configurer ce comportement via le paramètre `clearDataOnBackup`. [En savoir plus](sdk-installation-capacitor#clear-data-on-backup-restore). ::: ## Utilisateurs identifiés \{#identified-users\} - Si un profil n'a pas encore d'identifiant utilisateur client (c'est-à-dire que **l'utilisateur n'est pas connecté**), lorsque vous envoyez un identifiant utilisateur client, celui-ci est associé à ce profil. - S'il s'agit d'une **réinstallation, d'une connexion ou d'une installation sur un nouvel appareil**, et que vous avez déjà envoyé l'identifiant utilisateur client auparavant, aucun nouveau profil n'est créé. On bascule plutôt vers le profil existant associé à cet identifiant. Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un identifiant utilisateur client lors de leur authentification. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un identifiant utilisateur client au moment du lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un identifiant utilisateur client qui est actuellement associé à un autre identifiant utilisateur client, le niveau d'accès est partagé, de sorte que les deux profils disposent d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après leur connexion ou leur inscription), utilisez la méthode `identify` pour définir leur identifiant utilisateur client. - Si vous **n'avez jamais utilisé cet identifiant utilisateur client auparavant**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé cet identifiant utilisateur client pour identifier l'utilisateur**, Adapty basculera vers le profil associé à cet identifiant. :::tip Lors de la création d'un identifiant utilisateur client, enregistrez-le avec les données de votre utilisateur afin de pouvoir envoyer le même identifiant lorsqu'il se connecte depuis de nouveaux appareils ou réinstalle votre application. ::: Utilisez toujours `await` avec `identify` avant d'appeler d'autres méthodes du SDK. Les appels simultanés produisent `#3006 profileWasChanged` ou atterrissent sur le profil anonyme. Voir [Ordre des appels dans le SDK Capacitor](capacitor-sdk-call-order). ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un identifiant utilisateur client au moment d'activer le SDK, vous pouvez le transmettre dans la méthode `activate` plutôt que d'appeler `identify` séparément. Si vous connaissez un identifiant utilisateur client mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil vide et ne basculera vers le profil existant qu'après l'appel à `identify`. Vous pouvez passer soit un identifiant utilisateur client existant (que vous avez déjà utilisé) soit un nouveau. Si vous en passez un nouveau, le profil créé lors de l'activation sera automatiquement lié à cet identifiant. :::tip Pour exclure les profils vides créés des analyses du tableau de bord, accédez à **App settings** et configurez la [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```typescript showLineNumbers await adapty.activate({ apiKey: "YOUR_PUBLIC_SDK_KEY", params: { customerUserId: "YOUR_USER_ID" } }); ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si votre application comporte un bouton de déconnexion, utilisez la méthode `logout`. Cela crée un nouvel identifiant de profil anonyme pour l'utilisateur. ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the error } ``` :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, aucune configuration supplémentaire n'est nécessaire : Voici comment cela fonctionne : 1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty l'associe à son identifiant de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un identifiant utilisateur client existant (déjà lié à un profil), Adapty synchronise automatiquement ses transactions. - S'il s'agit d'un nouvel identifiant utilisateur client (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue l'identifiant utilisateur client au profil actuel, de sorte que tout l'historique des achats est conservé. --- # File: adapty-sdk-integration-skill-capacitor --- --- title: "Intégrer Adapty dans votre application Capacitor avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Capacitor de bout en bout avec votre outil de codage IA." --- :::important La compétence est en version bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-capacitor) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-capacitor --- --- title: "Intégrer Adapty dans votre application Capacitor avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre application Capacitor en utilisant Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Capacitor à l'aide d'un outil de codage IA — il vous suffit de lui fournir la bonne documentation Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite quelques étapes de configuration dans le tableau de bord avant d'écrire du code avec le SDK. Vous pouvez le faire avec un skill LLM interactif, ou manuellement via le Dashboard. ### Approche par compétence (recommandée) \{#skill-approach-recommended\} La compétence Adapty CLI permet à votre LLM de configurer votre application, vos produits, vos niveaux d'accès, vos paywalls et vos placements directement — sans ouvrir le Dashboard à chaque étape. Il vous suffit de [connecter vos stores](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois la compétence ajoutée, exécutez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris lorsqu'il faudra ouvrir le Dashboard pour connecter vos stores. ### Approche via le tableau de bord \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas rechercher les valeurs du tableau de bord à votre place — vous devrez les fournir vous-même. 1. **Connectez vos stores** : Dans l'Adapty Dashboard, accédez à **App settings → General**. Connectez l'App Store et Google Play si votre application Capacitor cible les deux plateformes. C'est indispensable pour que les achats fonctionnent. [Connecter les stores](integrate-payments) 2. **Copiez votre clé SDK publique** : dans l'Adapty Dashboard, rendez-vous dans **App settings → General**, puis repérez la section **API keys**. Dans le code, c'est la chaîne que vous passez à `adapty.activate()`. 3. **Créez au moins un produit** : dans l'Adapty Dashboard, accédez à la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les transmet via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : Dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID du placement est la chaîne que vous passez à `adapty.getFlow()`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : Dans l'Adapty Dashboard, configurez chaque produit sur la page **Products**. Dans le code, la chaîne vérifiée est `profile.accessLevels['premium']?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants ont accès à différentes fonctionnalités selon le produit (par exemple, un plan `basic` ou un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois que vous avez les cinq éléments, vous êtes prêt à écrire du code. Dites à votre LLM : « Ma clé SDK publique est X, mon identifiant de placement est Y » pour qu'il génère le code d'initialisation et de récupération de flow correct. ::: ### Configurez quand vous êtes prêt \{#set-up-when-ready\} Ces éléments ne sont pas obligatoires pour commencer à coder, mais vous en aurez besoin au fil de l'évolution de votre intégration : - **Tests A/B** : Configurez-les sur la page **Placements**. Aucune modification de code requise. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : Ajoutez d'autres appels `getFlow` avec des ID de placement différents. - **Intégrations analytiques** : Configurez-les sur la page **Integrations**. La configuration varie selon l'intégration. Consultez les [intégrations analytiques](analytics-integration) et les [intégrations d'attribution](attribution-integration). ## Alimentez votre LLM avec la documentation Adapty \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs en fonction de vos questions — aucun collage d'URL manuel nécessaire. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez : ``` npx ctx7 setup ``` Cela détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the Capacitor SDK ``` :::warning Même si Context7 supprime le besoin de coller manuellement des liens vers la documentation, l'ordre d'implémentation est important. Suivez le [guide d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne. ::: ### Utilisez les docs en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle doc Adapty en texte brut Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-capacitor.md](https://adapty.io/docs/fr/adapty-cursor-capacitor.md). Chaque étape du [guide d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc « Envoyer à votre LLM » avec des liens `.md` à coller. Pour accéder à plus de documentation en une seule fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Implémentation pas à pas \{#implementation-walkthrough\} Le reste de ce guide vous accompagne à travers l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut la documentation à envoyer à votre LLM, ce que vous devriez obtenir une fois terminé, et les problèmes courants. ### Planifiez votre intégration \{#plan-your-integration\} Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode planification (comme le mode plan de Cursor ou de Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire quoi que ce soit. Indiquez à votre LLM l'approche que vous utilisez pour les achats — cela détermine les guides qu'il devra suivre : - [**Adapty Flow Builder**](adapty-flow-builder) : vous créez des flows dans le builder no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](capacitor-making-purchases) : vous construisez votre propre interface de paywall dans le code, mais utilisez toujours Adapty pour récupérer les produits et gérer les achats. - [**Mode observateur**](observer-vs-full-mode) : vous conservez votre infrastructure d'achats existante et utilisez Adapty uniquement pour les analyses et les intégrations. Vous ne savez pas lequel choisir ? Consultez le [tableau comparatif dans le guide de démarrage rapide](capacitor-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez la dépendance du SDK Adapty via npm et activez-la avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans elle. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-capacitor) :::info Ce guide cible le SDK Adapty Capacitor v4 (beta) — l'API présentée dans le [quickstart](capacitor-quickstart-paywalls). La v4 est une version préliminaire, alors assurez-vous que votre LLM utilise la version exacte (`npm install @adapty/capacitor@4.0.1-beta.1`) plutôt que la dernière version stable 3.x. Consultez la [section d'installation du SDK 4.0](sdk-installation-capacitor#adapty-sdk-40-beta) et le [guide de migration](migration-to-capacitor-sdk-v4). ::: Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-capacitor.md ``` :::tip[Checkpoint] - **Expected :** L'app se compile et s'exécute sur iOS et Android. La console affiche le log d'activation d'Adapty. - **Gotcha :** "Public API key is missing" → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis **App settings**. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par identifiant de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de la façon dont vous gérez les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Flow Builder" default> **Guides :** - [Activer les achats avec des flows (démarrage rapide)](capacitor-quickstart-paywalls) - [Récupérer les flows et paywalls](capacitor-get-pb-paywalls) - [Afficher les flows et paywalls](capacitor-present-paywalls) - [Gérer les événements](capacitor-handling-events) - [Répondre aux actions](capacitor-handle-paywall-actions) ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/capacitor-quickstart-paywalls.md - https://adapty.io/docs/fr/capacitor-get-pb-paywalls.md - https://adapty.io/docs/fr/capacitor-present-paywalls.md - https://adapty.io/docs/fr/capacitor-handling-events.md - https://adapty.io/docs/fr/capacitor-handle-paywall-actions.md ``` :::tip[Checkpoint] - **Attendu :** Le flow s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **À surveiller :** Flow vide ou erreur `getFlow` → vérifiez que l'ID du placement correspond exactement à celui du tableau de bord et qu'une audience est bien assignée au placement. ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **Guides :** - [Activer les achats dans votre paywall personnalisé (démarrage rapide)](capacitor-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-capacitor) - [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-capacitor) - [Effectuer des achats](capacitor-making-purchases) - [Restaurer des achats](capacitor-restore-purchase) ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/capacitor-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-capacitor.md - https://adapty.io/docs/fr/present-remote-config-paywalls-capacitor.md - https://adapty.io/docs/fr/capacitor-making-purchases.md - https://adapty.io/docs/fr/capacitor-restore-purchase.md ``` :::tip[Checkpoint] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Problème fréquent :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Observer mode"> **Guides :** - [Présentation du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode-capacitor) - [Signaler les transactions en mode Observer](report-transactions-observer-mode-capacitor) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-capacitor.md - https://adapty.io/docs/fr/report-transactions-observer-mode-capacitor.md ``` :::tip[Checkpoint] - **Résultat attendu :** Après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans l'**Event Feed** du tableau de bord Adapty. - **Piège courant :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez le profil utilisateur pour un niveau d'accès actif afin de contrôler l'accès au contenu premium. **Guide :** [Vérifier le statut de l'abonnement](capacitor-check-subscription-status) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/capacitor-check-subscription-status.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox, `profile.accessLevels['premium']?.isActive` renvoie `true`. - **Point d'attention :** `accessLevels` vide après un achat → vérifiez que le produit a bien un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Associez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent d'un appareil à l'autre. :::important Ignorez cette étape si votre application ne nécessite pas d'authentification. ::: **Guide :** [Identifier les utilisateurs](capacitor-quickstart-identify) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/capacitor-quickstart-identify.md ``` :::tip[Checkpoint] - **Attendu :** Après avoir appelé `adapty.identify()`, la section **Profiles** du tableau de bord affiche votre identifiant utilisateur personnalisé. - **Attention :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution de profil anonyme. ::: ### Préparer la mise en production \{#prepare-for-release\} Une fois votre intégration validée en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt. **Guide :** [Checklist de mise en production](release-checklist) Envoyez ceci à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Checkpoint] - **Attendu :** Tous les éléments de la liste de contrôle sont confirmés : connexions au store, notifications serveur, flux d'achat, vérifications du niveau d'accès et exigences de confidentialité. - **Point d'attention :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**. ::: ## Fichiers d'index en texte brut \{#plain-text-doc-index-files\} Si vous souhaitez fournir à votre LLM un contexte plus large au-delà des pages individuelles, nous hébergeons des fichiers d'index qui listent ou regroupent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : Liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par ex. ChatGPT), vous devrez télécharger `llms.txt` et le joindre à la conversation en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : L'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement lorsque vous avez besoin d'une vue d'ensemble complète. - Fichiers spécifiques à Capacitor [`capacitor-llms.txt`](https://adapty.io/docs/fr/capacitor-llms.txt) et [`capacitor-llms-full.txt`](https://adapty.io/docs/fr/capacitor-llms-full.txt) : Sous-ensembles propres à la plateforme, moins lourds en tokens que le site complet. --- # File: capacitor-paywalls --- --- title: "Flows et paywalls - Capacitor" description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre application Capacitor." --- ## Afficher des paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['capacitor-get-pb-paywalls', 'capacitor-present-paywalls', 'capacitor-handling-events', 'capacitor-handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les flows et paywalls Adapty, consultez notre [guide de démarrage rapide](capacitor-quickstart-paywalls). ::: ### Implémenter des paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['capacitor-quickstart-manual', 'fetch-paywalls-and-products-capacitor', 'present-remote-config-paywalls-capacitor', 'capacitor-making-purchases']} /> Pour d'autres guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](capacitor-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['capacitor-use-fallback-paywalls', 'capacitor-web-paywall']} /> --- # File: capacitor-get-pb-paywalls --- --- title: "Obtenir des flows et des paywalls - Capacitor" description: "Récupérez les flows et les paywalls depuis Adapty dans votre application Capacitor." --- <SDKv4> <MethodPromo method="getFlow" /> Après avoir [conçu votre flow ou votre paywall dans le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement et à sa configuration de vue, comme décrit ci-dessous. Notez que cette rubrique concerne les flows et les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez la rubrique [Récupérer les paywalls et les produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-capacitor). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des flows et des paywalls dans votre application mobile (cliquez pour agrandir)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-capacitor) dans votre application mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. Vous devez néanmoins récupérer son ID via le placement, sa configuration de vue, puis le présenter dans votre application mobile. Récupérez le flow ou le paywall et créez sa [vue](capacitor-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible — idéalement bien avant de l'afficher. La méthode `createFlowView` charge la configuration de la vue et lance le téléchargement et la mise en cache de ses images en arrière-plan. Plus tôt vous l'appelez, plus ces téléchargements ont de temps pour se terminer. Au moment où vous affichez le flow ou le paywall, sa configuration et ses images peuvent déjà être en cache et prêtes à être affichées. Pour obtenir un flow ou un paywall, utilisez la méthode `getFlow` : ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |-------------------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | par défaut : `'reload_revalidating_cache_data'` | <p>Passé dans l'objet optionnel `params`. Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé qu'à la réinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | par défaut : 5 sec | <p>Passé dans l'objet optionnel `params`. Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont retournés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeoutMs`, car l'opération peut comprendre différentes requêtes en coulisse.</p> | **N'inscrivez pas les IDs de produits en dur dans le code.** Le seul ID à coder en dur est l'ID de placement. Les flows et les paywalls étant configurés à distance, le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements de manière dynamique — si un paywall retourne deux produits aujourd'hui et trois demain, tous doivent s'afficher sans modification du code. Paramètres de réponse : | Paramètre | Description | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objet `AdaptyFlow` contenant les identifiants du flow (`id`, `variationId`), son nom, son placement, ses variantes de paywall (`paywalls`), ainsi que les Remote Configs éventuels (`remoteConfigs`). | ## Récupérer la configuration de la vue \{#fetch-the-view-configuration\} :::important Assurez-vous d'activer le bouton **Show on device** dans le builder. Si cette option n'est pas activée, la configuration de la vue ne sera pas disponible à la récupération. ::: Si le placement a été conçu dans le **Flow Builder** ou le **Paywall Builder**, Adapty génère l'interface utilisateur pour vous. Créez la vue avec `createFlowView`, puis [affichez le flow ou le paywall](capacitor-present-paywalls). Si le placement est un paywall personnalisé sans interface Builder, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-capacitor) à la place. Dans le SDK Capacitor, appelez directement `createFlowView` — il n'est pas nécessaire de récupérer d'abord la configuration de la vue. :::warning Le résultat de la méthode `createFlowView` ne peut être utilisé qu'une seule fois. Si vous en avez besoin à nouveau, appelez de nouveau la méthode `createFlowView`. L'appeler deux fois sans recréer la vue peut entraîner une erreur. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | obligatoire | Un objet `AdaptyFlow` permettant d'obtenir un contrôleur pour le flow/paywall souhaité. | | **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) à utiliser pour afficher la vue — par exemple, `en` ou `pt-br`. Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de version `en`. Voir [Localisations et codes de langue](capacitor-localizations-and-locale-codes). | | **customTags** | optionnel | Définit un dictionnaire de balises personnalisées et leurs valeurs résolues. Les balises personnalisées servent de placeholders dans le contenu, remplacées dynamiquement par des chaînes spécifiques pour personnaliser le contenu du flow/paywall. Consultez la rubrique sur les balises personnalisées dans le Paywall Builder pour plus de détails. | | **prefetchProducts** | optionnel | Activez cette option pour optimiser le moment d'affichage des produits à l'écran. Lorsque la valeur est `true`, AdaptyUI récupère automatiquement les produits nécessaires. Par défaut : `true`. | | **android.enableSafeArea** | optionnel | Android uniquement (ignoré sur iOS). Imbriqué sous la clé `android`. Lorsque la valeur est `true`, la vue du flow applique les marges de zone sécurisée. Par défaut : `true`. La valeur par défaut convient à la plupart des cas. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation de flow](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](capacitor-localizations-and-locale-codes). ::: Une fois que vous avez la vue, [affichez le flow/paywall](capacitor-present-paywalls). ## Récupérer un flow ou un paywall pour l'audience par défaut afin d'accélérer le chargement \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et les paywalls sont récupérés presque instantanément, donc vous n'avez pas à vous inquiéter d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `getFlow`, comme décrit dans la section [Récupérer le flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de rétrocompatibilité** : si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et futures versions), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls qui ne s'affichent pas. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération de flow ou de paywall plus rapide, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | défaut : `'reload_revalidating_cache_data'` | <p>Passé dans l'objet optionnel `params`. Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou par un nettoyage manuel.</p> | ## Personnaliser les assets \{#customize-assets\} Pour personnaliser les images et vidéos de votre flow/paywall, implémentez des assets personnalisés. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle d'assets personnalisé, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via un dictionnaire simple : ```typescript showLineNumbers const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; const view = await createFlowView(flow, { customAssets }); ``` :::note Si un asset est introuvable, le flow/paywall reviendra à son apparence par défaut. ::: </SDKv4> <SDKv3> Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape de ce processus consiste à récupérer le paywall associé au placement et sa configuration d'affichage, comme décrit ci-dessous. Veuillez noter que cette rubrique concerne les paywalls personnalisées avec Paywall Builder. Pour savoir comment récupérer les paywalls avec Remote Config, consultez la rubrique [Récupérer les paywalls et produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-capacitor). <details> <summary>Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-capacitor) dans votre application mobile. </details> ## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](capacitor-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour obtenir un paywall, utilisez la méthode `getPaywall` : ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et leur utilisation recommandée.</p> | | **params** | optionnel | Paramètres supplémentaires pour récupérer le paywall. | **Ne codez pas en dur les ID de produits.** Le seul ID à coder en dur est l'ID de placement. Les paywalls étant configurés à distance, le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements de façon dynamique — si un paywall renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. Paramètres de réponse : | Paramètre | Description | | :-------- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objet [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) contenant une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer la configuration d'affichage d'un paywall conçu avec le Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration d'affichage ne pourra pas être récupérée. ::: Après avoir récupéré le paywall, vérifiez s'il inclut une `ViewConfiguration`, ce qui indique qu'il a été créé avec Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si la `ViewConfiguration` est présente, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-capacitor). Dans le SDK Capacitor, appelez directement la méthode `createPaywallView` sans récupérer manuellement la configuration de vue au préalable. :::warning Le résultat de la méthode `createPaywallView` ne peut être utilisé qu'une seule fois. Si vous avez besoin de l'utiliser à nouveau, appelez à nouveau la méthode `createPaywallView`. ::: ```typescript showLineNumbers if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { // use your custom logic } ``` Paramètres : | Paramètre | Présence | Description | | :------------------- | :------- | :----------------------------------------------------------- | | **paywall** | required | Un objet `AdaptyPaywall` pour obtenir un contrôleur pour le paywall souhaité. | | **customTags** | optional | Définit un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu du paywall, remplacés dynamiquement par des chaînes spécifiques pour un contenu personnalisé. Consultez la rubrique Custom tags in paywall builder pour plus de détails. | | **prefetchProducts** | optional | Activez cette option pour optimiser le moment d'affichage des produits à l'écran. Lorsque la valeur est `true`, AdaptyUI récupère automatiquement les produits nécessaires. Par défaut : `false`. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de locale [ici](capacitor-localizations-and-locale-codes). ::: Une fois la vue disponible, [affichez le paywall](capacitor-present-paywalls). ## Obtenir un paywall pour l'audience par défaut afin de l'afficher plus rapidement \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls se chargent presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, le chargement d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité descendante** : si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (y compris par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, utilisez `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](capacitor-localizations-and-locale-codes) pour en savoir plus sur les codes de langue et nos recommandations d'utilisation.</p> | | **params** | optionnel | Paramètres supplémentaires pour récupérer le paywall. | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos de votre paywall, utilisez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leur identifiant pour personnaliser leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via un simple dictionnaire : ```typescript showLineNumbers const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createPaywallView(paywall, { customAssets }); ``` :::note Si une ressource est introuvable, le paywall affichera son apparence par défaut. ::: </SDKv3> --- # File: capacitor-present-paywalls --- --- title: "Afficher les flows et les paywalls - Capacitor" description: "Présentez des flows et des paywalls aux utilisateurs dans votre app Capacitor avec Adapty." --- <SDKv4> Si vous avez créé un flow ou un paywall dans le Flow Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre app mobile pour l'afficher à l'utilisateur. Un tel flow contient à la fois ce qui doit être affiché et la façon dont cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez [créé un flow ou un paywall](create-paywall). 2. Vous l'avez ajouté à un [placement](placements). 3. Vous avez [récupéré le flow et préparé la vue](capacitor-get-pb-paywalls). :::warning Ce guide concerne uniquement les **flows et les paywalls créés avec le Paywall Builder**, qui nécessitent le SDK v4.0 ou une version ultérieure. La procédure pour présenter des flows diffère pour les paywalls à Remote Config. - Pour présenter des **paywalls à Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-capacitor). ::: Pour afficher un flow ou un paywall en tant qu'écran autonome, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createFlowView`](capacitor-get-pb-paywalls#fetch-the-view-configuration). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer est interdit. Cela provoquera une erreur. ::: ```typescript showLineNumbers const view = await createFlowView(flow); // Optional: handle flow events (close, purchase, restore, etc) // await view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important Appeler `setEventHandlers` plusieurs fois écrasera les gestionnaires que vous fournissez, remplaçant à la fois les gestionnaires par défaut et ceux précédemment définis pour ces événements spécifiques. ::: ## Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le flow est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. Sur Android, les flows sont toujours affichés en plein écran. ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## Utiliser un timer défini par le développeur \{#use-developer-defined-timer\} Pour utiliser des timers définis par le développeur dans votre app mobile, utilisez le `timerId`, dans cet exemple `CUSTOM_TIMER_NY`, le **Timer ID** du timer défini par le développeur que vous avez configuré dans le tableau de bord Adapty. Cela garantit que votre app met à jour dynamiquement le timer avec la valeur correcte — par exemple `13j 09h 03m 34s` (calculée comme l'heure de fin du timer, telle que le Jour de l'An, moins l'heure actuelle). ```typescript showLineNumbers const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createFlowView(flow, { customTimers }); ``` Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** du timer défini par le développeur que vous avez configuré dans le tableau de bord Adapty. Le timer garantit que votre app met à jour dynamiquement le timer avec la valeur correcte — par exemple `13j 09h 03m 34s` (calculée comme l'heure de fin du timer, telle que le Jour de l'An, moins l'heure actuelle). ## Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'une vue de flow est présentée sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du flow, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du flow sur toutes les plateformes. ```typescript showLineNumbers try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the flow await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## Remplacer un abonnement par un autre \{#replace-one-subscription-with-another\} Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre abonnement est actif sur Android, vous pouvez contrôler la façon dont le nouvel achat doit être traité en passant des paramètres de mise à jour d'abonnement lors de la création de la vue du flow. Pour remplacer l'abonnement actuel par le nouveau, utilisez `productPurchaseParams` dans `createFlowView` avec les paramètres `oldSubVendorProductId` et `prorationMode`. ```typescript showLineNumbers const productPurchaseParams = flow.paywalls .flatMap((paywall) => paywall.productIdentifiers) .map((productId) => { const params: MakePurchaseParamsInput = {}; if (Capacitor.getPlatform() === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createFlowView(flow, { productPurchaseParams }); ``` </SDKv4> <SDKv3> Si vous avez personnalisé un paywall à l'aide du Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre app mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la façon dont cela doit l'être. :::warning Ce guide concerne uniquement les **paywalls créés avec le Paywall Builder**. La procédure pour présenter des paywalls diffère pour les paywalls à Remote Config. Pour présenter des **paywalls à Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls). ::: Pour afficher un paywall, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createPaywallView`](capacitor-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `createPaywallView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut provoquer une erreur. ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); view.setEventHandlers({ onUrlPress(url) { window.open(url, '_blank'); return false; }, }); try { await view.present(); } catch (error) { // handle the error } ``` ## Utiliser un timer défini par le développeur \{#use-developer-defined-timer\} Pour utiliser des timers définis par le développeur dans votre app mobile, utilisez le `timerId`, dans cet exemple `CUSTOM_TIMER_NY`, le **Timer ID** du timer défini par le développeur que vous avez configuré dans le tableau de bord Adapty. Cela garantit que votre app met à jour dynamiquement le timer avec la valeur correcte — par exemple `13j 09h 03m 34s` (calculée comme l'heure de fin du timer, telle que le Jour de l'An, moins l'heure actuelle). ```typescript showLineNumbers const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createPaywallView(paywall, { customTimers }); ``` Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** du timer défini par le développeur que vous avez configuré dans le tableau de bord Adapty. Le timer garantit que votre app met à jour dynamiquement le timer avec la valeur correcte — par exemple `13j 09h 03m 34s` (calculée comme l'heure de fin du timer, telle que le Jour de l'An, moins l'heure actuelle). ## Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'une vue de paywall est présentée sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes. ```typescript showLineNumbers title="Capacitor" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` </SDKv3> --- # File: capacitor-handle-paywall-actions --- --- title: "Répondre aux actions de flow - Capacitor" description: "Gérez les actions de boutons depuis les flows et paywalls dans Capacitor avec Adapty pour une meilleure monétisation." --- <SDKv4> Si vous créez des flows ou des paywalls avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code. :::warning **Les achats, restaurations, fermetures de flows et paywalls, ainsi que l'ouverture d'URL sont gérés automatiquement.** Vous pouvez configurer leur comportement par défaut ou implémenter des réponses pour les actions personnalisées. ::: :::note Définir un handler pour un événement remplace entièrement son comportement par défaut. Les handlers que vous ne définissez pas conservent leurs valeurs par défaut. ::: ## Fermer les flows et paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui fermera votre flow ou paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre application, implémentez un handler pour l'action `close` qui ferme le flow ou le paywall. :::info Dans le SDK Capacitor, l'action `close` déclenche par défaut la fermeture du flow ou du paywall. Vous pouvez cependant modifier ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un flow peut déclencher l'ouverture d'un autre. ::: ```typescript showLineNumbers const view = await createFlowView(flow); const unsubscribe = await view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` Sur Android, le bouton système **Back** et le geste retour déclenchent un événement `onAndroidSystemBack` distinct. Dans le SDK v4, il ne ferme plus le flow par défaut. Retournez `true` depuis le handler si vous voulez que le bouton **Back** ferme le flow : ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onAndroidSystemBack() { return true; // close the flow when the Back button is pressed }, }); ``` ## Ouvrir des URL depuis les flows et paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par ex., conditions d'utilisation et restauration d'achat), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par ex., **Conditions d'utilisation** ou **Politique de confidentialité**) : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Si nécessaire, dans le code de votre application, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue à votre façon. :::info Dans le SDK Capacitor, le fait d'appuyer sur une URL l'ouvre par défaut dans le navigateur natif : le SDK appelle `adapty.openWebUrl({ url, openIn })`, en respectant l'option **Open in** définie dans le builder, et conserve le flow ouvert. Vous pouvez cependant modifier ce comportement dans votre code si nécessaire. ::: ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onUrlPress(url) { // Open the URL your own way, e.g. with the Capacitor Browser plugin Browser.open({ url }); return false; // keep the flow open }, }); ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre application, implémentez un handler pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall : ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, }); ``` </SDKv4> <SDKv3> Si vous créez des paywalls avec le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code. ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui fermera votre paywall : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre application, implémentez un handler pour l'action `close` qui ferme le paywall. :::info Dans le SDK Capacitor, l'action `close` déclenche par défaut la fermeture du paywall. Vous pouvez cependant modifier ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un paywall peut déclencher l'ouverture d'un autre. ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { console.log('User closed paywall'); return true; // Allow the paywall to close } }); ``` ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par ex., conditions d'utilisation et restauration d'achat), ajoutez un élément **Link** dans le Paywall Builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par ex., **Conditions d'utilisation** ou **Politique de confidentialité**) : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre application, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK Capacitor, l'action `window.open` déclenche par défaut l'ouverture de l'URL. Vous pouvez cependant modifier ce comportement dans votre code si nécessaire. ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { window.open(url, '_blank'); return false; // Don't close the paywall }, }); ``` ## Se connecter à l'application \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre application : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre application, implémentez un handler pour l'action `login` qui identifie votre utilisateur. ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'login') { // Navigate to login screen console.log('User requested login'); } } }); ``` ## Gérer les actions personnalisées \{#handle-custom-actions-1\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre application, implémentez un handler pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre paywall : ```typescript showLineNumbers const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another paywall } }, }); ``` </SDKv3> --- # File: capacitor-handling-events --- --- title: "Gérer les événements de flow et de paywall - Capacitor" description: "Gérez les événements de flow et de paywall dans votre application Capacitor avec le SDK d'Adapty." --- <SDKv4> :::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 de boutons](capacitor-handle-paywall-actions) pour plus de détails. ::: Les flows et paywalls créés avec le [Flow Builder](adapty-flow-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Ils génèrent cependant des é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 flow. Découvrez comment répondre à ces événements ci-dessous. 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 définis précédemment pour ces événements spécifiques. Les gestionnaires non définis conservent leur comportement par défaut. `setEventHandlers` retourne une fonction de désinscription, et `view.dismiss()` supprime tous les gestionnaires. ::: ```typescript showLineNumbers 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() { /***/ }, onDisappeared() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> Les exemples ci-dessous montrent les propriétés disponibles dans chaque gestionnaire, avec des valeurs illustratives en commentaires. ```typescript // onUrlPress url; // 'https://example.com/terms' openIn; // 'browser_in_app' or 'browser_out_app' // onCustomAction actionId; // 'login' // onProductSelected productId; // 'premium_monthly' // 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' ``` </Details> Vous pouvez enregistrer uniquement les gestionnaires d'événements dont vous avez besoin, et ignorer les autres. Dans ce cas, les écouteurs d'événements inutilisés ne seront pas créés. 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 de 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 appuyé. - `onUrlPress` : ouvre l'URL dans le navigateur natif via `adapty.openWebUrl`, en respectant l'option **Open in** définie dans le builder, et maintient le flow ouvert. - `onAndroidSystemBack` : maintient le flow ouvert lorsque le bouton **Retour** est appuyé. Retournez `true` pour le fermer. - `onPurchaseCompleted` : maintient le flow ouvert après la fin d'un achat. Retournez `true` pour le fermer. - `onRestoreCompleted` : maintient 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 \{#event-handlers\} | Gestionnaire d'événement | Description | |:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | Déclenché lorsqu'un utilisateur effectue une action personnalisée, par exemple en cliquant sur un [bouton personnalisé](paywall-buttons). | | **onUrlPress** | Déclenché lorsqu'un utilisateur clique sur une URL dans votre flow. | | **onAndroidSystemBack** | Dé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. | | **onCloseButtonPress** | Dé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. | | **onPurchaseCompleted** | Dé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 par l'utilisateur et les paiements en attente (ex. : approbation parentale requise) déclenchent cet événement, pas `onPurchaseFailed`. | | **onPurchaseStarted** | Déclenché lorsqu'un utilisateur appuie sur le bouton d'action "Acheter" pour lancer le processus d'achat. | | **onPurchaseFailed** | Déclenché lorsqu'un achat échoue en raison d'erreurs (ex. : restrictions de paiement, produits invalides, pannes réseau, échecs de vérification des transactions). Non déclenché pour les annulations par l'utilisateur ou les paiements en attente, qui déclenchent `onPurchaseCompleted` à la place. | | **onRestoreStarted** | Déclenché lorsqu'un utilisateur lance un processus de restauration d'achat. | | **onRestoreCompleted** | Dé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 de l'abonnement](capacitor-listen-subscription-changes) pour savoir comment le vérifier. | | **onRestoreFailed** | Déclenché lorsque le processus de restauration échoue et fournit une `AdaptyError`. | | **onProductSelected** | Déclenché lorsqu'un produit dans la vue du flow est sélectionné, vous permettant de surveiller ce que l'utilisateur sélectionne avant l'achat. | | **onError** | Dé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 le signaler. | | **onLoadingProductsFailed** | Dé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 les objets nécessaires depuis le serveur par lui-même. | | **onAppeared** | Déclenché lorsque le flow est affiché à l'utilisateur. Sur iOS, également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un flow, et qu'un paywall web s'ouvre dans un navigateur intégré. | | **onDisappeared** | Déclenché lorsque le flow est fermé par l'utilisateur. Sur iOS, également déclenché lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un flow dans un navigateur intégré disparaît de l'écran. | | **onWebPaymentNavigationFinished** | Déclenché après une tentative d'ouverture d'un [paywall web](web-paywall) pour un achat, qu'elle ait réussi ou échoué. | | **onRequestAppReview** | Réservé aux demandes d'évaluation de l'application depuis un flow. Les flows ne déclenchent pas encore de demandes d'évaluation, vous n'avez donc pas besoin de l'implémenter. | | **onAnalytics** | Réservé aux événements analytiques personnalisés depuis un flow. Les flows n'émettent pas encore ces événements vers votre code, vous n'avez donc pas besoin de l'implémenter. | | **onRequestPermission** | Ré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. | | **onObserverPurchaseInitiated** | Mode 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](#handle-purchases-in-observer-mode) ci-dessous. | | **onObserverRestoreInitiated** | Mode 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](#handle-purchases-in-observer-mode) ci-dessous. | ### Gérer les achats en mode observateur \{#handle-purchases-in-observer-mode\} Si vous avez activé le SDK en [mode observateur](implement-observer-mode-capacitor) (`observerMode: true`) et que vous affichez un flow rendu par Adapty, le SDK n'effectue pas les achats pour vous. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration, le SDK déclenche `onObserverPurchaseInitiated` ou `onObserverRestoreInitiated` à la place, afin que vous puissiez effectuer l'achat ou la restauration avec votre propre code. Consultez [Afficher les flows en mode observateur](capacitor-present-flows-in-observer-mode) pour la configuration complète. </SDKv4> <SDKv3> :::important 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](capacitor-handle-paywall-actions) pour plus de détails. ::: Les paywalls configurés avec le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Ils génèrent cependant des é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 comment répondre à ces événements ci-dessous. 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` : ```typescript showLineNumbers 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 }, }); ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```typescript // 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" } } } ``` </Details> Vous pouvez enregistrer uniquement les gestionnaires d'événements dont vous avez besoin, et ignorer les autres. Dans ce cas, les écouteurs d'événements inutilisés ne seront pas créés. 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 paywall se ferme et les écouteurs d'événements de 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 appuyé. - `onAndroidSystemBack` : ferme le paywall lorsque le bouton **Retour** 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. - `onUrlPress` : ouvre les URLs dans le navigateur système et maintient le paywall ouvert. ### Gestionnaires d'événements \{#event-handlers\} | Gestionnaire d'événement | Description | |:----------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | Déclenché lorsqu'un utilisateur effectue une action personnalisée, par exemple en cliquant sur un [bouton personnalisé](paywall-buttons). | | **onUrlPress** | Déclenché lorsqu'un utilisateur clique sur une URL dans votre paywall. | | **onAndroidSystemBack** | Déclenché lorsqu'un utilisateur appuie sur le bouton système **Retour** d'Android. | | **onCloseButtonPress** | Dé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. | | **onPurchaseCompleted** | Dé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 par l'utilisateur et les paiements en attente (ex. : approbation parentale requise) déclenchent cet événement, pas `onPurchaseFailed`. | | **onPurchaseStarted** | Déclenché lorsqu'un utilisateur appuie sur le bouton d'action "Acheter" pour lancer le processus d'achat. | | **onPurchaseCancelled** | Déclenché lorsqu'un utilisateur lance le processus d'achat et l'interrompt manuellement (annule la boîte de dialogue de paiement). | | **onPurchaseFailed** | Déclenché lorsqu'un achat échoue en raison d'erreurs (ex. : restrictions de paiement, produits invalides, pannes réseau, échecs de vérification des transactions). Non déclenché pour les annulations par l'utilisateur ou les paiements en attente, qui déclenchent `onPurchaseCompleted` à la place. | | **onRestoreStarted** | Déclenché lorsqu'un utilisateur lance un processus de restauration d'achat. | | **onRestoreCompleted** | Dé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 de l'abonnement](capacitor-listen-subscription-changes) pour savoir comment le vérifier. | | **onRestoreFailed** | Déclenché lorsque le processus de restauration échoue et fournit une `AdaptyError`. | | **onProductSelected** | Déclenché lorsqu'un produit dans la vue du paywall est sélectionné, vous permettant de surveiller ce que l'utilisateur sélectionne avant l'achat. | | **onAppeared** | Déclenché lorsque la vue du paywall apparaît à l'écran. Sur iOS, également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré. | | **onDisappeared** | Déclenché lorsque la vue du paywall disparaît de l'écran. Sur iOS, également déclenché lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. | | **onRenderingFailed** | Dé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 le signaler. | | **onLoadingProductsFailed** | Dé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 les objets nécessaires depuis le serveur par lui-même. | </SDKv3> --- # File: capacitor-use-fallback-paywalls --- --- title: "Capacitor - Use fallback paywalls" description: "Handle cases when users are offline or Adapty servers aren't available" --- To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} ### Android \{#android\} 1. Ajoutez le fichier de configuration de secours à votre application. Sélectionnez l'un des répertoires suivants : * **android/app/src/main/assets/** * **android/app/src/main/res/raw/** Remarque : le dossier `res/raw` suit une convention de nommage particulière (commencer par une lettre, pas de majuscules, pas de caractères spéciaux sauf le tiret bas, et pas d'espaces dans les noms). 2. Mettez à jour la propriété `android` de la constante `FileLocation` : * Si le fichier se trouve dans le répertoire `assets`, passez le chemin du fichier relatif à ce répertoire. * Si le fichier se trouve dans le répertoire `res/raw`, passez le nom du fichier sans l'extension. ### iOS \{#ios\} 1. Ajoutez le fichier JSON de secours à votre bundle de projet : ouvrez le menu **File** dans XCode et sélectionnez l'option **Add Files to "YourProjectName"**. 2. Passez le nom de votre fichier de configuration à la propriété `ios` de la constante `FileLocation`. ## Exemple \{#example\} ```typescript showLineNumbers const fileLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } }; await adapty.setFallback({ fileLocation }); ``` :::important `setFallback` doit être exécuté avant que le SDK ne récupère le flow, le paywall ou l'onboarding cible. ::: Paramètres : | Paramètre | Description | | :------------------- | :------------------------------------------------------- | | **fileLocation** | Objet représentant l'emplacement du fichier de configuration de secours. | --- # File: capacitor-localizations-and-locale-codes --- --- title: "Utiliser les localisations et les codes de langue dans le SDK Capacitor" description: "Apprenez à localiser les paywalls dans votre application Capacitor avec le SDK Adapty." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu lorsqu'Adapty choisit la localisation pour un flow et lorsque vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous aide à anticiper quelle localisation reçoit un utilisateur. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty recherche la localisation qui correspond à la locale d'un utilisateur, voici ce qui se passe : 1. La chaîne de locale est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, Adapty renvoie le contenu dans la locale par défaut du flow Cette approche permet à `'pt_BR'`, `pt-BR` et `pt-br` de tous correspondre à la même localisation. ## Implémentation des localisations \{#implementing-localizations\} Dans le SDK v4, vous ne transmettez pas de code de langue lorsque vous récupérez un flow — `getFlow` renvoie le flow avec toutes ses localisations, et Adapty en applique une au moment où la vue du flow est construite. - **Flows construits dans le builder** : le SDK ne lit pas la langue de l'appareil, donc déterminez-la dans votre application et transmettez-la comme option `locale` de `createFlowView`. C'est facultatif — omettez-la et le flow s'affiche en `en`, ou dans sa [langue par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow ne possède pas de localisation `en`. Si vous demandez une localisation que le flow n'a pas, la vue revient à la langue par défaut du flow sans erreur, et les chaînes manquantes dans la localisation choisie sont récupérées depuis celle par défaut. ```typescript showLineNumbers import { createFlowView } from '@adapty/capacitor'; const view = await createFlowView(flow, { locale: 'es' }); ``` `view.locale` indique la localisation avec laquelle la vue a été construite. L'option `locale` et `view.locale` nécessitent le SDK Capacitor 4.0.1-beta.1 ; `view.locale` est `undefined` sur les versions antérieures. - **Paywalls personnalisés (Remote Config)** : `getFlow` retourne toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée possède un code `lang` et un objet `data`. Sélectionnez l'entrée correspondant à l'utilisateur, avec votre propre fallback : ```typescript showLineNumbers const flow = await adapty.getFlow({ placementId: 'placement_id' }); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; // read your values from config?.data ``` Les règles de correspondance des codes de langue décrites ci-dessus expliquent comment Adapty normalise les codes `lang` stockés dans chaque Remote Config. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Il existe quelques scénarios où les codes de locale entrent en jeu — par exemple, lorsque vous essayez de récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de locale étant complexes et pouvant varier d'une plateforme à l'autre, nous nous appuyons sur un standard interne pour toutes les plateformes que nous supportons. Cependant, en raison de cette complexité, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin que vous receviez toujours ce que vous attendez. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-tags en minuscules, séparés par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty reçoit un appel du SDK client avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de locale reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. On recherche ensuite la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si aucune correspondance n'est trouvée non plus, on renvoie le contenu dans la locale par défaut du paywall De cette façon, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Implémentation des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous interrogez sur les localisations, il y a de grandes chances que vous gériez déjà des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de localisation. Récupérez ensuite la valeur de cette clé lors de l'appel au SDK, comme ceci : ```javascript showLineNumbers // 1. Modify your localization files (e.g., using react-i18next) /* 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 const MyComponent = () => { const { t } = useTranslation(); const fetchPaywall = async () => { const locale = t('adapty_paywalls_locale'); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; }; ``` De cette façon, vous êtes totalement maître de la localisation qui sera récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : une autre approche \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais non identiques) sans définir explicitement de codes de langue pour chaque localisation. Il s'agit d'extraire un code de langue depuis d'autres objets fournis par votre plateforme, comme ceci : ```javascript showLineNumbers const getLocaleCode = () => { if (Capacitor.getPlatform() === 'ios') { return navigator.language || 'en'; } else { return navigator.language || 'en'; } }; const fetchPaywall = async () => { const locale = getLocaleCode(); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; ``` Notez que nous déconseillons cette approche pour plusieurs raisons : 1. Sur iOS, les langues préférées et la locale actuelle ne sont pas identiques. Si vous voulez que la localisation soit sélectionnée correctement, vous devrez soit vous reposer sur la logique d'Apple, qui fonctionne directement si vous utilisez l'approche recommandée avec des fichiers de chaînes localisées, soit la recréer vous-même. 2. Il est difficile de prédire ce que le serveur d'Adapty recevra exactement. Par exemple, sur iOS, il est possible d'obtenir une locale comme `ar_OM@numbers='latn'` sur un appareil et de l'envoyer à notre serveur. Pour cet appel, vous obtiendrez non pas la localisation `ar-om` que vous cherchiez, mais `ar`, ce qui est probablement inattendu. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: capacitor-web-paywall --- --- title: "Implémenter les paywalls web" description: "Apprenez à implémenter les paywalls web dans votre application Capacitor avec le SDK Adapty." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé la version 3.6.1 ou ultérieure du SDK Adapty. ::: ## Ouvrir les paywalls web \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `.openWebPaywall` : 1. Génère une URL unique permettant à Adapty d'associer un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `.getProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. ```typescript showLineNumbers try { await adapty.openWebPaywall({ paywallOrProduct: product }); } catch (error) { console.error('Failed to open web paywall:', error); } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall({ paywallOrProduct: product })` qui génère des URLs par paywall et ajoute également les données du produit aux URLs. 2. `openWebPaywall({ paywallOrProduct: paywall })` qui génère des URLs par paywall sans ajouter les données du produit aux URLs. Utilisez-la quand vos produits dans le paywall Adapty diffèrent de ceux du paywall web. Dans le SDK v4, le côté paywall de `paywallOrProduct` prend un `AdaptyFlowPaywall` — une variante paywall du flow récupéré. Vérifiez que `flow.paywalls` n'est pas vide avant d'y accéder par index, par exemple `flow.paywalls[0]`. ::: #### Gérer les erreurs \{#handle-errors\} | Erreur | Description | Action recommandée | |-----------------------------------------|---------------------------------------------------------------------|----------------------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | Le paywall n'a pas d'URL d'achat web configurée | Vérifiez que le paywall a été correctement configuré dans l'Adapty Dashboard | | AdaptyError.productWithoutPurchaseUrl | Le produit n'a pas d'URL d'achat web | Vérifiez la configuration du produit dans l'Adapty Dashboard | | AdaptyError.failedOpeningWebPaywallUrl | Impossible d'ouvrir l'URL dans le navigateur | Vérifiez les paramètres de l'appareil ou proposez une autre méthode d'achat | | AdaptyError.failedDecodingWebPaywallUrl | Impossible d'encoder correctement les paramètres dans l'URL | Vérifiez que les paramètres d'URL sont valides et correctement formatés | ## Obtenir l'URL du paywall web sans l'ouvrir \{#get-the-web-paywall-url-without-opening-it\} Si vous souhaitez afficher vous-même la page d'achat web plutôt que de laisser le SDK l'ouvrir, utilisez `createWebPaywallUrl`. Elle retourne la même URL unique que celle qu'`openWebPaywall` ouvrirait, vous permettant ainsi de l'afficher dans votre propre vue web ou de gérer la redirection à votre façon. Elle accepte le même argument `paywallOrProduct` — une variante paywall du flow récupéré (`AdaptyFlowPaywall`) ou un `AdaptyPaywallProduct`. ```typescript showLineNumbers try { const url = await adapty.createWebPaywallUrl({ paywallOrProduct: product }); // open `url` in your own web view, or handle the redirect yourself } catch (error) { console.error('Failed to create web paywall URL:', error); } ``` :::note Pour ouvrir une URL arbitraire (pas un paywall web) dans le navigateur natif — par exemple, depuis le bouton d'un flow — utilisez plutôt [`adapty.openWebUrl`](capacitor-handle-paywall-actions#open-urls-from-flows-and-paywalls). ::: ## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} :::important L'ouverture des paywalls web dans un navigateur intégré est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les paywalls web s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. Cela affiche la page d'achat web directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application. Pour activer cette option, définissez `openIn` sur `WebPresentation.BrowserInApp` dans `openWebPaywall` : ```typescript showLineNumbers try { await adapty.openWebPaywall({ paywallOrProduct: product, openIn: WebPresentation.BrowserInApp, // default – WebPresentation.BrowserOutApp }); } catch (error) { console.error('Failed to open web paywall:', error); } ``` --- # File: capacitor-present-flows-in-observer-mode --- --- title: "Afficher les flows en mode Observer dans le SDK Capacitor" description: "Affichez les flows et les paywalls Paywall Builder en mode Observer dans votre application Capacitor tout en gérant les achats avec votre propre code." --- Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez la rubrique [Afficher les flows et paywalls](capacitor-present-paywalls). ::: :::info Cette fonctionnalité nécessite Adapty Capacitor SDK 4.0 ou une version ultérieure — elle n'était auparavant disponible que dans les SDK iOS et Android natifs. Consultez le [guide de migration](migration-to-capacitor-sdk-v4) pour effectuer la mise à niveau. ::: <details> <summary>Avant de commencer à afficher des flows (Cliquer pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios) et [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez le [guide d'installation du SDK Capacitor](sdk-installation-capacitor#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez les flows ou paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](capacitor-get-pb-paywalls) dans le code de votre application mobile. </details> En mode Observer, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou paywall rendu par Adapty, le SDK invoque votre gestionnaire d'événements `onObserverPurchaseInitiated` ou `onObserverRestoreInitiated` — effectuez l'achat ou la restauration avec votre propre code à cet endroit. 1. Définissez les gestionnaires d'événements du mode Observer sur la vue. Contrairement à d'autres plateformes, il n'existe pas d'objet resolver séparé — les gestionnaires font partie des [gestionnaires d'événements](capacitor-handling-events) habituels, définissez-les donc sur chaque vue que vous créez : ```typescript showLineNumbers title="Capacitor" import { adapty, createFlowView } from '@adapty/capacitor'; const view = await createFlowView(flow); const unsubscribe = await view.setEventHandlers({ onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) { onStartPurchase(); // the view shows its loading indicator myPurchaseApi(product.vendorProductId) .then((transactionId) => adapty.reportTransaction({ transactionId, variationId: flow.variationId }), ) .finally(() => onFinishPurchase()); // the view hides the loading indicator return false; // keep the flow open; dismiss it yourself after success }, onObserverRestoreInitiated(onStartRestore, onFinishRestore) { onStartRestore(); myRestoreApi().finally(() => onFinishRestore()); return false; }, }); ``` Le gestionnaire `onObserverPurchaseInitiated` vous informe que l'utilisateur a initié un achat, et `onObserverRestoreInitiated` — que l'utilisateur a initié une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse. Pensez également à invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. C'est nécessaire pour un comportement correct du flow, notamment l'affichage du loader : | Callback | Description | | :----------------- | :----------------------------------------------------------------------------------------------- | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a commencé. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a commencé. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | 2. Affichez la vue du flow comme d'habitude : [récupérez le flow et créez sa vue](capacitor-get-pb-paywalls), puis [affichez-la](capacitor-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — les gestionnaires se déclenchent uniquement lorsque le SDK a été activé avec `observerMode: true`. :::warning N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-capacitor). Sans cela, Adapty ne reconnaîtra pas la transaction et ne pourra pas identifier le paywall source de l'achat. ::: --- # File: capacitor-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement" description: "Découvrez comment implémenter les paywalls manuellement dans votre application Capacitor avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty en utilisant la méthode `makePurchase`. De cette façon, nous gérons tous les scénarios utilisateur et vous n'avez qu'à traiter les résultats des achats. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['capacitor-quickstart-manual', 'fetch-paywalls-and-products-capacitor', 'present-remote-config-paywalls-capacitor', 'capacitor-making-purchases', 'capacitor-restore-purchase']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z tout en bénéficiant des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode-capacitor', 'report-transactions-observer-mode-capacitor']} /> --- # File: capacitor-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec le SDK Capacitor" description: "Intégrez le SDK Adapty dans vos paywalls Capacitor personnalisés pour activer les achats intégrés." --- Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les achats précédents. Ce guide utilise les APIs du SDK Adapty Capacitor v4 — si vous êtes sur la v3, consultez le [guide de migration](migration-to-capacitor-sdk-v4) pour les noms de méthodes correspondants. :::important **Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la solution la plus simple pour activer les achats, utilisez le [Adapty Paywall Builder](capacitor-quickstart-paywalls). Avec le Paywall Builder, vous créez des paywalls dans un éditeur visuel sans code, Adapty gère automatiquement toute la logique d'achat, et vous pouvez tester différents designs sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. Dans le SDK v4, les variations de paywall pour un placement sont portées par un objet **flow** — vous récupérez un flow et interrogez ses produits. - [**Placements**](placements) – où et quand vous affichez les paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite les tests A/B et l'affichage de paywalls différents à différents utilisateurs. Assurez-vous de bien comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En gros, ce sont simplement votre façon de gérer les produits que vous vendez dans votre application. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](capacitor-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs. ## Étape 1. Récupérer les produits \{#step-1-get-products\} Pour récupérer les produits pour votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau de produits pour ce flow en utilisant la méthode `getPaywallProducts`. ```typescript showLineNumbers async function loadPaywall() { try { const flow: AdaptyFlow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts({ flow }); // Use products to build your custom paywall UI } catch (error) { // Handle the error } } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Quand un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le processus d'achat et retournera le profil mis à jour. ```typescript showLineNumbers async function purchaseProduct(product: AdaptyPaywallProduct) { try { const result: AdaptyPurchaseResult = await adapty.makePurchase({ product }); if (result.type === 'success') { // Purchase successful, profile updated } else if (result.type === 'user_cancelled') { // User canceled the purchase } else if (result.type === 'pending') { // Purchase is pending (e.g., user will pay offline with cash) } } catch (error) { // Handle the error } } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Les stores d'applications exigent que toutes les applications avec des abonnements fournissent un moyen pour les utilisateurs de restaurer leurs achats. Appelez la méthode `restorePurchases` quand l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et retournera le profil mis à jour. ```typescript showLineNumbers async function restorePurchases() { try { const profile: AdaptyProfile = await adapty.restorePurchases(); // Restore successful, profile updated } catch (error) { // Handle the error } } ``` ## Étape 4. Vérifier le statut de l'abonnement \{#step-4-check-the-subscription-status\} Après un achat ou une restauration, vérifiez le [niveau d'accès](access-level) de l'utilisateur pour décider d'afficher le paywall ou de déverrouiller les fonctionnalités payantes. Les méthodes `makePurchase` et `restorePurchases` retournent déjà le profil mis à jour ; chaque fois que vous avez besoin du statut actuel ailleurs dans l'application, utilisez la méthode `getProfile` : ```typescript showLineNumbers async function hasPremiumAccess(): Promise<boolean> { try { const profile = await adapty.getProfile(); return profile.accessLevels?.['premium']?.isActive ?? false; } catch (error) { // Handle the error } return false; } ``` Pour d'autres façons de vérifier et surveiller le statut de l'abonnement, y compris l'écoute des mises à jour en temps réel, consultez [Vérifier le statut de l'abonnement](capacitor-check-subscription-status). ## Prochaines étapes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans le [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez le fichier [App.tsx](https://github.com/adaptyteam/AdaptySDK-Capacitor/blob/master/examples/adapty-devtools/src/screens/app/App.tsx) dans notre application exemple, qui illustre la gestion des achats avec une gestion des erreurs appropriée, des états de chargement et une intégration complète du SDK. --- # File: fetch-paywalls-and-products-capacitor --- --- title: "Récupérer les paywalls et produits pour les paywalls Remote Config dans le SDK Capacitor" description: "Récupérez les paywalls et produits dans le SDK Adapty Capacitor pour améliorer la monétisation des utilisateurs." --- <SDKv4> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique traite du Remote Config et des paywalls personnalisés. Pour récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Récupérer les flows du Flow Builder et les paywalls du Paywall Builder ainsi que leur configuration](capacitor-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et intégrez les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-capacitor) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) regroupe des produits issus de l'App Store et de Google Play. Ces produits multi-plateformes sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) via la méthode `getFlow`. :::important **N'écrivez pas les IDs de produits en dur.** Le seul ID que vous devez coder en dur est l'ID de placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un flow retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); // the requested flow } catch (error) { console.error('Failed to fetch flow:', error); } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact au redémarrage de l'application et n'est effacé qu'en cas de réinstallation ou de nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](capacitor-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos flows tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **params.loadTimeoutMs** | <p>optionnel</p><p>par défaut : 5000 ms</p> | <p>Cette valeur limite le délai d'attente (en millisecondes) pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeoutMs`, car l'opération peut reposer sur différentes requêtes en coulisse.</p> | :::note Dans la v4, `getFlow` ne prend plus de paramètre `locale`. Pour les paywalls personnalisés, toutes les locales disponibles sont renvoyées dans le Remote Config du flow (`flow.remoteConfigs`) — choisissez celle qui correspond à la langue de l'appareil ou aux paramètres de l'application. ::: Ne codez pas en dur les identifiants de produits ! Les flows étant configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à coder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, ses variantes de paywall (`paywalls`), et un tableau `remoteConfigs` (une entrée par locale configurée). Pour récupérer les produits du flow, appelez `getPaywallProducts({ flow })`. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez interroger le tableau de produits qui lui correspond : ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ flow }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) avec : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.price?.localizedString`. Cette localisation est basée sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme de nombre avec `product.price?.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price?.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. semaine, mois, année, etc.), utilisez `product.subscription?.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscription?.subscriptionPeriod`. Vous pouvez alors accéder à la propriété `unit` pour obtenir la durée (`'day'`, `'week'`, `'month'`, `'year'` ou `'unknown'`). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `'month'` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : une chaîne avec les valeurs `'free_trial'`, `'pay_as_you_go'`, `'pay_up_front'` et `'unknown'`. Les essais gratuits correspondent au type `'free_trial'`.<br/>• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, cette valeur sera `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `'3 days'` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Son fonctionnement est identique à celui décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la locale de l'utilisateur. | ## Accélérer la récupération du flow avec le flow de l'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous inquiéter d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-capacitor#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité descendante** : Si vous avez besoin d'afficher différents flows pour différentes versions de l'application (actuelle et future), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (ancienne), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur la méthode `getFlow` décrite [ci-dessus](fetch-paywalls-and-products-capacitor#fetch-flow-information). ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); // the requested flow } catch (error) { console.error('Failed to fetch default audience flow:', error); } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données mises en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `'return_cache_data_else_load'` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs peuvent ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc fiable de l'utiliser en cours de session pour éviter des requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant de pouvoir afficher les Remote Configs et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que ce sujet porte sur les Remote Configs et les paywalls personnalisés. Pour obtenir des conseils sur la récupération des paywalls personnalisés avec le Paywall Builder, consultez [Récupérer les paywalls Paywall Builder et leur configuration](capacitor-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-capacitor) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) regroupe des produits provenant à la fois de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); // the requested paywall } catch (error) { console.error('Failed to fetch paywall:', error); } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](capacitor-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre recommandation d'utilisation.</p> | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session afin d'éviter des requêtes réseau inutiles.</p><p></p><p>Notez que le cache est conservé après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p> | | **params.loadTimeoutMs** | <p>optionnel</p><p>par défaut : 5000 ms</p> | <p>Cette valeur limite le délai d'attente (en millisecondes) pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont retournés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeoutMs`, car l'opération peut impliquer plusieurs requêtes en coulisse.</p> | **N'intégrez pas les identifiants produit en dur dans votre code.** Le seul identifiant à coder en dur est l'identifiant de placement. Les paywalls sont configurés à distance, donc le nombre de produits et d'offres disponibles peut changer à tout moment. Votre application doit gérer ces changements de façon dynamique — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config, et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous disposez du paywall, vous pouvez récupérer le tableau de produits qui lui correspond : ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ paywall }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) comprenant : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement, et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Titre** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue de l'appareil. | | **Prix** | Pour afficher une version localisée du prix, utilisez `product.price?.localizedString`. Cette localisation est basée sur les informations de langue de l'appareil. Vous pouvez également accéder au prix sous forme numérique avec `product.price?.amount`. La valeur est fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price?.currencySymbol`. | | **Période d'abonnement** | Pour afficher la période (ex. : semaine, mois, an, etc.), utilisez `product.subscription?.localizedSubscriptionPeriod`. Cette localisation est basée sur la langue de l'appareil. Pour récupérer la période d'abonnement de façon programmatique, utilisez `product.subscription?.subscriptionPeriod`. Vous pouvez ensuite accéder à la propriété `unit` pour obtenir la durée unitaire (`'day'`, `'week'`, `'month'`, `'year'` ou `'unknown'`). La valeur `numberOfUnits` indique le nombre d'unités de la période. Par exemple, pour un abonnement trimestriel, `unit` vaut `'month'` et `numberOfUnits` vaut `3`. | | **Offre de lancement** | Pour afficher un badge ou un indicateur signalant qu'un abonnement inclut une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. C'est une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : une chaîne avec les valeurs `'free_trial'`, `'pay_as_you_go'`, `'pay_up_front'` et `'unknown'`. Les essais gratuits correspondent au type `'free_trial'`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, cette valeur est `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la langue de l'appareil décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `'3 days'` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre grâce à cette propriété. Son fonctionnement est identique à celui décrit dans la section précédente pour les abonnements.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, dans la langue de l'utilisateur. | ## Accélérer la récupération des paywalls avec le paywall de l'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En règle générale, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée consiste à récupérer le paywall via la méthode `getPaywall`, comme expliqué dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-capacitor#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et futures versions), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur la méthode `getPaywall` décrite [ci-dessus](fetch-paywalls-and-products-capacitor#fetch-paywall-information). ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); // the requested paywall } catch (error) { console.error('Failed to fetch default audience paywall:', error); } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` signifie l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](capacitor-localizations-and-locale-codes) pour en savoir plus sur les codes de langue et notre façon de les utiliser.</p> | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vos utilisateurs ont souvent une connexion instable, envisagez d'utiliser `'return_cache_data_else_load'` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser au cours d'une session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé après un redémarrage de l'application et n'est effacé qu'en cas de désinstallation ou de nettoyage manuel.</p> | </SDKv3> --- # File: present-remote-config-paywalls-capacitor --- --- title: "Afficher un paywall conçu via Remote Config dans le SDK Capacitor" description: "Découvrez comment présenter des paywalls Remote Config dans le SDK Adapty Capacitor pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un flow via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et la façon dont votre vue de flow apparaît. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre flow personnalisé configuré via Remote Config. ## Récupérer la Remote Config du flow et l'afficher \{#get-flow-remote-config-and-present-it\} Dans la v4, un flow contient une entrée `AdaptyRemoteConfig` par langue configurée dans le tableau `remoteConfigs`. Choisissez la langue qui correspond à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin depuis son `data`. ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; const headerText = config?.data?.['header_text']; } catch (error) { console.error('Failed to fetch flow:', error); } ``` À ce stade, une fois toutes les valeurs nécessaires reçues, il est temps de les assembler en une page visuellement attrayante. Assurez-vous que le design s'adapte aux différentes tailles d'écran et orientations des appareils mobiles, pour une expérience fluide et conviviale sur tous les terminaux. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-capacitor#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse capturer les informations pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du flow terminé, poursuivez en configurant le flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](capacitor-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](capacitor-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos flows. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages de flows nécessite votre intervention, car vous seul savez quand un client voit un flow. Pour enregistrer un événement d'affichage de flow, appelez simplement `.logShowFlow({ flow })` — il sera alors reflété dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowFlow({ flow })` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les affichages automatiquement dans ces cas. ::: ```typescript showLineNumbers await adapty.logShowFlow({ flow }); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :------- |:-------------------------------------------------------------------------------------| | **flow** | requis | Un objet `AdaptyFlow` obtenu via `adapty.getFlow({ placementId })`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et la façon dont votre vue de paywall apparaît. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer la Remote Config du paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir la Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires. ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); const headerText = paywall.remoteConfig?.data?.['header_text']; } catch (error) { console.error('Failed to fetch paywall:', error); } ``` À ce stade, une fois toutes les valeurs nécessaires reçues, il est temps de les assembler en une page visuellement attrayante. Assurez-vous que le design s'adapte aux différentes tailles d'écran et orientations des appareils mobiles, pour une expérience fluide et conviviale sur tous les terminaux. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-capacitor#track-paywall-view-events-1) comme décrit ci-dessous, afin qu'Adapty Analytics puisse capturer les informations pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du paywall terminé, poursuivez en configurant le flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](capacitor-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](capacitor-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events-1\} Adapty vous aide à mesurer les performances de vos paywalls. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages de paywalls nécessite votre intervention, car vous seul savez quand un client voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowPaywall(paywall)` — il sera alors reflété dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```typescript showLineNumbers try { await adapty.logShowPaywall({ paywall }); } catch (error) { console.error('Failed to log paywall view:', error); } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- | :--------------------------------------------------------- | | **paywall** | requis | Un objet [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall). | </SDKv3> --- # File: capacitor-making-purchases --- --- title: "Make purchases in mobile app in Capacitor SDK" description: "Guide on handling in-app purchases and subscriptions using Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour donner aux utilisateurs accès à des contenus ou services premium. Cependant, se contenter d'afficher ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour personnaliser vos paywalls. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode distincte appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode sert de point d'entrée pour que les utilisateurs interagissent avec les paywalls et effectuent leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. Assurez-vous d'avoir effectué la [configuration initiale](quickstart) sans sauter une seule étape. Sans cela, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](capacitor-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product }); if (result.type === 'success') { const isSubscribed = result.profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features console.log('User is now subscribed!'); } } else if (result.type === 'user_cancelled') { console.log('Purchase cancelled by user'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { console.error('Purchase failed:', error); } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:----------------------------------------------------------------------------------------------------------------------------| | **product** | requis | Un objet [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) récupéré depuis le flow via `getPaywallProducts`. | Paramètres de la réponse : | Paramètre | Description | |---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **result** | Un objet [`AdaptyPurchaseResult`](https://capacitor.adapty.io/types/adaptypurchaseresult) avec un champ `type` indiquant le résultat de l'achat (`'success'`, `'user_cancelled'` ou `'pending'`) et un champ `profile` contenant l'[`AdaptyProfile`](https://capacitor.adapty.io/interfaces/adaptyprofile) mis à jour en cas d'achat réussi. | ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur opte pour un nouvel abonnement plutôt que de renouveler l'abonnement actuel, le comportement dépend du store : - Pour l'App Store, l'abonnement est mis à jour automatiquement au sein du groupe d'abonnements. Si un utilisateur achète un abonnement d'un groupe alors qu'il en a déjà un d'un autre groupe, les deux abonnements seront actifs en même temps. - Pour Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer un abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire suivant : ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product, params: { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } } }); if (result.type === 'success') { const isSubscribed = result.profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features console.log('Subscription updated successfully!'); } } else if (result.type === 'user_cancelled') { console.log('Purchase cancelled by user'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { console.error('Purchase failed:', error); } ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------- | :------- | :----------------------------------------------------------- | | **params** | optionnel | Un objet de type [`MakePurchaseParamsInput`](https://capacitor.adapty.io/types/makepurchaseparamsinput) contenant les paramètres d'achat spécifiques à chaque plateforme. | La structure `MakePurchaseParamsInput` comprend : ```typescript { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } } ``` Vous pouvez en savoir plus sur les abonnements et les modes de remplacement dans la documentation Google Developer : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode n'est disponible que pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'intervient qu'à la fin de la période de facturation de l'abonnement en cours. ### Gérer les plans prépayés (Android) \{#manage-prepaid-plans-android\} Si les utilisateurs de votre application peuvent acheter des [plans prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, souscrire un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour les plans prépayés. ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { pendingPrepaidPlansEnabled: true, }, } }); ``` ## Utiliser des codes de réduction sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie de code de réduction dans votre application : ```typescript showLineNumbers try { await adapty.presentCodeRedemptionSheet(); } catch (error) { console.error('Failed to present code redemption sheet:', error); } ``` :::danger D'après nos observations, la feuille de saisie de code de réduction peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, vous devez ouvrir une URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: --- # File: capacitor-restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec le SDK Capacitor" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats sur iOS et Android est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à du contenu précédemment acheté — abonnements ou achats intégrés — sans être facturés à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leur contenu sans payer une nouvelle fois. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat si vous n'utilisez pas le [Paywall Builder](adapty-paywall-builder) pour personnaliser votre paywall, appelez la méthode `.restorePurchases()` : ```typescript showLineNumbers try { const profile = await adapty.restorePurchases(); const isSubscribed = profile.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Restore access to paid features console.log('Access restored successfully!'); } else { console.log('No active subscriptions found'); } } catch (error) { console.error('Failed to restore purchases:', error); } ``` Paramètres de la réponse : | Paramètre | Description | |-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile** | Un objet [`AdaptyProfile`](https://capacitor.adapty.io/interfaces/adaptyprofile). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques. Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application. | --- # File: implement-observer-mode-capacitor --- --- title: "Implémenter le mode Observateur dans le SDK Capacitor" description: "Implémentez le mode Observateur dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Capacitor." --- Si vous disposez déjà de votre propre infrastructure d'achat et n'êtes pas encore prêt à basculer entièrement vers Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analytique. Si cela correspond à vos besoins, vous devez uniquement : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [Capacitor](sdk-installation-capacitor#activate-adapty-module-of-adapty-sdk). 2. [Signaler les transactions](report-transactions-observer-mode-capacitor) depuis votre infrastructure d'achat existante vers Adapty. :::tip Dans le SDK v4, vous pouvez également afficher des flows et des paywalls rendus par Adapty en mode Observateur : lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration, le SDK transmet l'action à votre code afin que vous puissiez effectuer l'achat ou la restauration vous-même. Voir [Afficher des flows en mode Observateur](capacitor-present-flows-in-observer-mode). ::: ### Configuration du mode Observateur \{#observer-mode-setup\} Activez le mode Observateur si vous gérez vous-même les achats et l'état des abonnements, et utilisez Adapty uniquement pour envoyer des événements d'abonnement et des données analytiques. :::important Lorsqu'il fonctionne en mode Observateur, le SDK Adapty ne fermera aucune transaction — assurez-vous de le gérer vous-même. ::: ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { observerMode: true // Enable observer mode } }); } catch (error) { console.error('Failed to activate Adapty:', error); } ``` Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | **observerMode** | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observateur \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observateur. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls comme d'habitude pour les [paywalls Remote Config](present-remote-config-paywalls-capacitor). 2. [Associez les paywalls](report-transactions-observer-mode-capacitor) aux transactions d'achat. --- # File: report-transactions-observer-mode-capacitor --- --- title: "Signaler les transactions en mode Observateur dans le SDK Capacitor" description: "Signalez les transactions d'achat en mode Observateur d'Adapty pour le suivi des utilisateurs et des revenus dans le SDK Capacitor." --- En mode Observateur, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre store. Il est indispensable de configurer cela **avant** de publier votre application pour éviter les erreurs dans les analyses. Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez les paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```typescript showLineNumbers const variationId = paywall.variationId; try { await adapty.reportTransaction({ transactionId: 'your_transaction_id', variationId: variationId }); } catch (error) { console.error('Failed to report transaction:', error); } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | **transactionId** | obligatoire | <ul><li> Pour iOS : Identifiant de la transaction.</li><li> Pour Android : Identifiant de type chaîne (`purchase.getOrderId`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | **variationId** | optionnel | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://capacitor.adapty.io/interfaces/adaptypaywall). | --- # File: capacitor-user --- --- title: "Utilisateurs et accès" description: "Découvrez comment gérer les utilisateurs et les niveaux d'accès dans votre application Capacitor avec le SDK Adapty." --- <CustomDocCardList /> --- # File: capacitor-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK Capacitor" description: "Découvrez comment identifier les utilisateurs dans votre application Capacitor avec le SDK Adapty." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous avez votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyé à toutes les intégrations. ### Définir le customer user ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur lors de la configuration, transmettez-le simplement en tant que paramètre `customerUserId` à la méthode `.activate()` : ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { customerUserId: 'YOUR_USER_ID' } }); } catch (error) { console.error('Failed to activate Adapty:', error); } ``` ### Définir le customer user ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous ne disposez pas d'un identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'usage les plus courants pour cette méthode sont après une inscription ou une authentification, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié. ```typescript showLineNumbers try { await adapty.identify({ customerUserId: 'YOUR_USER_ID' }); console.log('User identified successfully'); } catch (error) { console.error('Failed to identify user:', error); } ``` Paramètres de la requête : | Paramètre | Présence | Description | |---------|--------|-----------| | **customerUserId** | requis | Un identifiant utilisateur de type chaîne de caractères. | :::warning Resoumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ce cas, le SDK Adapty basculera automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, telles que des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez resoumettre ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et connexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```typescript showLineNumbers try { await adapty.logout(); console.log('User logged out successfully'); } catch (error) { console.error('Failed to logout user:', error); } ``` Vous pouvez ensuite connecter l'utilisateur en utilisant la méthode `.identify()`. ## Attribuer un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de lier les transactions App Store à votre identité utilisateur interne. StoreKit associe ce token à chaque transaction, afin que votre backend puisse faire correspondre les données App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications App Store restent correctement associés. Vous pouvez définir le token de deux façons : lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `appAccountToken` conjointement avec `customerUserId`. Si vous ne transmettez que le token, il ne sera pas inclus dans la transaction. ::: ```typescript showLineNumbers // During configuration: await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { customerUserId: 'YOUR_USER_ID', ios: { appAccountToken: "YOUR_APP_ACCOUNT_TOKEN" }, } }); // Or when identifying users await adapty.identify({ customerUserId: 'YOUR_USER_ID', params: { ios: { appAccountToken: 'YOUR_APP_ACCOUNT_TOKEN' }, } }); ``` ### Définir des identifiants de compte masqués (Android) \{#set-obfuscated-account-ids-android\} Google Play exige des identifiants de compte masqués pour certains cas d'usage afin de renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants permettent à Google Play d'identifier les achats tout en préservant l'anonymat des informations utilisateur, ce qui est particulièrement important pour la prévention des fraudes et l'analyse. Vous devrez peut-être définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous êtes tenu de respecter des réglementations spécifiques en matière de confidentialité. Les identifiants masqués permettent à Google Play de suivre les achats sans exposer les identifiants utilisateur réels. ```typescript showLineNumbers // During configuration: await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' }, } }); // Or when identifying users await adapty.identify({ customerUserId: 'YOUR_USER_ID', params: { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' }, } }); ``` ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: capacitor-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK Capacitor" description: "Découvrez comment mettre à jour les attributs utilisateur et les données de profil dans votre application Capacitor avec le SDK Adapty." --- Vous pouvez définir des attributs optionnels tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` : ```typescript showLineNumbers const params = { email: 'email@email.com', phoneNumber: '+18888888888', firstName: 'John', lastName: 'Appleseed', gender: 'other', birthday: new Date().toISOString(), }; try { await adapty.updateProfile(params); console.log('Profile updated successfully'); } catch (error) { console.error('Failed to update profile:', error); } ``` Notez que les attributs que vous avez précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés autorisées de `AdaptyProfileParameters` et leurs valeurs sont listées ci-dessous : | Clé | Valeur | |---|-----| | **email** | String | | **phoneNumber** | String | | **firstName** | String | | **lastName** | String | | **gender** | Enum, les valeurs autorisées sont : `'female'`, `'male'`, `'other'` | | **birthday** | Chaîne de date au format ISO | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés. Ceux-ci sont généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, et dans les analyses pour déterminer quelles métriques produit influencent le plus le chiffre d'affaires. ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); console.log('Custom attributes updated successfully'); } catch (error) { console.error('Failed to update custom attributes:', error); } ``` Pour supprimer des clés existantes, passez `null` comme valeur : ```typescript showLineNumbers try { // to remove keys, pass null as their values await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); console.log('Custom attributes removed successfully'); } catch (error) { console.error('Failed to remove custom attributes:', error); } ``` Il peut arriver que vous ayez besoin de savoir quels attributs personnalisés ont déjà été définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut être obsolète, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment — les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clé peuvent comporter jusqu'à 30 caractères. Ils peuvent contenir des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre flottant, avec 50 caractères maximum. --- # File: capacitor-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK Capacitor" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Capacitor." --- Avec Adapty, suivre le statut d'abonnement est simple. Pas besoin d'insérer manuellement des identifiants de produits dans votre code. Il vous suffit de vérifier la présence d'un [niveau d'accès](access-level) actif pour confirmer l'état de l'abonnement d'un utilisateur. <details> <summary>Avant de vérifier le statut d'abonnement (cliquez pour développer)</summary> - Pour iOS, configurez les [notifications serveur App Store](enable-app-store-server-notifications) - Pour Android, configurez les [notifications en temps réel pour les développeurs (RTDN)](enable-real-time-developer-notifications-rtdn) </details> ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://capacitor.adapty.io/interfaces/adaptyprofile). Nous recommandons de récupérer le profil au démarrage de l'application, par exemple lors de [l'identification d'un utilisateur](capacitor-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque changement. Ainsi, vous pouvez utiliser l'objet profil sans avoir à le redemander sans cesse. Pour être notifié des mises à jour du profil, écoutez les changements comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](capacitor-listen-subscription-changes) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); console.log('Profile retrieved successfully'); } catch (error) { console.error('Failed to get profile:', error); } ``` Paramètres de réponse : | Paramètre | Description | | --------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile** | Un objet [AdaptyProfile](https://capacitor.adapty.io/interfaces/adaptyprofile). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium. La méthode `.getProfile` renvoie le résultat le plus récent en interrogeant toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion Internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont renvoyées. Il est également important de noter que le SDK Adapty met régulièrement à jour le cache `AdaptyProfile` pour que ces informations restent aussi récentes que possible. | La méthode `.getProfile()` vous fournit le profil utilisateur depuis lequel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de presse et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer les niveaux d'accès « sports » et « science ». Mais la plupart du temps, un seul niveau d'accès suffit — dans ce cas, vous pouvez simplement utiliser le niveau d'accès « premium » par défaut. Voici un exemple pour vérifier le niveau d'accès « premium » par défaut : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.['premium']?.isActive; if (isActive) { // Grant access to premium features console.log('User has premium access'); } else { console.log('User does not have premium access'); } } catch (error) { console.error('Failed to check subscription status:', error); } ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir des messages d'Adapty, vous devez effectuer une configuration supplémentaire : ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addListener('onLatestProfileLoad', (data) => { const profile = data.profile; const isActive = profile.accessLevels?.['premium']?.isActive; if (isActive) { console.log('Subscription status updated: User has premium access'); } else { console.log('Subscription status updated: User does not have premium access'); } }); ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Cela signifie que même si le serveur est indisponible, les données mises en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil. Il est toutefois important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour détecter les mises à jour ou changements liés au profil. Si des modifications sont détectées — nouvelles transactions ou autres mises à jour — elles sont appliquées aux données en cache afin de les synchroniser avec le serveur. --- # File: capacitor-deal-with-att --- --- title: "Gérer l'ATT dans le SDK Capacitor" description: "Commencez avec Adapty sur Capacitor pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. ```typescript showLineNumbers try { await adapty.updateProfile({ appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); console.log('ATT status updated successfully'); } catch (error) { console.error('Failed to update ATT status:', error); } ``` :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de garantir que les données sont transmises en temps voulu aux intégrations que vous avez configurées. ::: --- # File: capacitor-onboardings --- --- title: "Onboardings" description: "Découvrez comment travailler avec les onboardings dans votre application Capacitor avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](capacitor-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance à un runtime WebView. Consultez [Récupérer les flows et paywalls](capacitor-get-pb-paywalls) et [Afficher les flows et paywalls](capacitor-present-paywalls) pour démarrer. ::: <CustomDocCardList /> --- # File: capacitor-get-onboardings --- --- title: "Récupérer les onboardings dans le SDK Capacitor" description: "Apprenez à récupérer les onboardings dans Adapty pour Capacitor." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne bénéficient plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](capacitor-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — avec des animations plus fluides, un rendu natif cohérent, des temps de chargement réduits et aucune dépendance à un runtime WebView. Consultez [Obtenir des flows & paywalls](capacitor-get-pb-paywalls) et [Afficher des flows & paywalls](capacitor-present-paywalls) pour démarrer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Capacitor. La première étape consiste à récupérer l'onboarding associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous de : 1. Avoir [créé un onboarding](create-onboarding). 2. Avoir ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère toute l'expérience — le contenu affiché, la manière dont il est présenté, et la façon dont les interactions utilisateur (comme les réponses à un quiz ou les saisies de formulaire) sont traitées. Le conteneur suit également automatiquement les événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi des vues séparément. Pour de meilleures performances, récupérez la configuration de l'onboarding en avance afin de laisser suffisamment de temps aux images pour se télécharger avant l'affichage. Pour obtenir un onboarding, utilisez la méthode `getOnboarding` : ```typescript showLineNumbers try { const onboarding = await adapty.getOnboarding({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); console.log('Onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch onboarding:', error); } ``` Appelez ensuite la méthode `createOnboardingView` pour créer une instance de vue. :::warning Le résultat de la méthode `createOnboardingView` ne peut être utilisé qu'une seule fois. Si vous avez besoin de l'utiliser à nouveau, appelez à nouveau la méthode `createOnboardingView`. ::: ```typescript showLineNumbers if (onboarding.hasViewConfiguration) { try { const view = await createOnboardingView(onboarding); console.log('Onboarding view created successfully'); } catch (error) { console.error('Failed to create onboarding view:', error); } } else { // Use your custom logic console.log('Onboarding does not have view configuration'); } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou via un nettoyage manuel.</p> | | **params.loadTimeoutMs** | <p>optionnel</p><p>par défaut : 5000 ms</p> | <p>Cette valeur limite le délai d'attente (en millisecondes) pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront retournés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeoutMs`, car l'opération peut impliquer différentes requêtes en arrière-plan.</p> | Paramètres de réponse : | Paramètre | Description | |:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding** | Un objet [`AdaptyOnboarding`](https://capacitor.adapty.io/interfaces/adaptyonboarding) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. | ## Accélérer la récupération de l'onboarding avec l'onboarding d'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un onboarding par défaut pour garantir une bonne expérience utilisateur plutôt que de n'afficher aucun onboarding. Pour cela, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée reste de récupérer l'onboarding avec la méthode `getOnboarding`, comme décrit dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des problèmes lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions s'affichent incorrectement. - **Pas de personnalisation** : affiche uniquement le contenu pour l'audience "All Users", sans ciblage basé sur le pays, l'attribution ou des attributs personnalisés. Si la rapidité de récupération justifie ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```typescript showLineNumbers try { const onboarding = await adapty.getOnboardingForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); console.log('Default audience onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch default audience onboarding:', error); } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **params.fetchPolicy** | <p>optionnel</p><p>par défaut : `'reload_revalidating_cache_data'`</p> | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `'return_cache_data_else_load'` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou via un nettoyage manuel.</p> | --- # File: capacitor-present-onboardings --- --- title: "Présenter les onboardings dans le SDK Capacitor" description: "Découvrez comment présenter des onboardings sur Capacitor pour augmenter les conversions et les revenus." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](capacitor-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance à l'exécution WebView. Consultez [Obtenir les flows et paywalls](capacitor-get-pb-paywalls) et [Afficher les flows et paywalls](capacitor-present-paywalls) pour commencer. ::: Si vous avez personnalisé un onboarding à l'aide du builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et la façon dont cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez [créé un onboarding](create-onboarding). 2. Vous avez ajouté l'onboarding à un [placement](placements). ## Présenter un onboarding \{#present-onboarding\} Pour afficher un onboarding, utilisez la méthode `view.present()` sur la `view` créée par la méthode `createOnboardingView`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher à nouveau l'onboarding, appelez `createOnboardingView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut entraîner une erreur. ::: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onClose: (actionId, meta) => { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom: (actionId, meta) => { console.log('Custom action:', actionId); return false; // Don't close the onboarding } }); await view.present(); console.log('Onboarding presented successfully'); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web directement dans votre application, permettant aux utilisateurs de les consulter sans changer d'application. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `openIn` sur `browser_out_app` : ```typescript showLineNumbers await view.present({ openIn: 'browser_out_app' }); // default — browser_in_app ``` ## Étapes suivantes \{#next-steps\} Une fois votre onboarding présenté, vous souhaiterez [gérer les interactions utilisateur et les événements](capacitor-handling-onboarding-events). Découvrez comment gérer les événements d'onboarding pour répondre aux actions des utilisateurs et suivre les analyses. --- # File: capacitor-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK Capacitor" description: "Gérez les événements liés à l'onboarding dans Capacitor avec Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une version future.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](capacitor-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement réduits et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows et paywalls](capacitor-get-pb-paywalls) et [Afficher des flows et paywalls](capacitor-present-paywalls) pour commencer. ::: Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Utilisez la méthode `setEventHandlers` pour gérer ces événements lors d'une présentation d'écran autonome. Avant de commencer, assurez-vous que : 1. Vous avez [créé un onboarding](create-onboarding). 2. Vous avez ajouté l'onboarding à un [placement](placements). ## Configurer les gestionnaires d'événements \{#set-up-event-handlers\} Pour gérer les événements des onboardings, utilisez la méthode `view.setEventHandlers` : ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', event); }, onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom(actionId, meta) { console.log('Custom action:', actionId); return false; // Don't close the onboarding }, onPaywall(actionId, meta) { console.log('Paywall action:', actionId); view.dismiss().then(() => { openPaywall(actionId); }); }, onStateUpdated(action, meta) { console.log('State updated:', action); }, onFinishedLoading(meta) { console.log('Onboarding finished loading'); }, onError(error) { console.error('Onboarding error:', error); }, }); await view.present(); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Types d'événements \{#event-types\} Les sections suivantes décrivent les différents types d'événements que vous pouvez gérer. ### Gérer les actions personnalisées \{#handle-custom-actions\} Dans le builder, vous pouvez ajouter une action **personnalisée** à un bouton et lui attribuer un ID. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez ensuite utiliser cet ID dans votre code et le traiter comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé, comme **Login** ou **Allow notifications**, le gestionnaire d'événements sera déclenché avec le paramètre `actionId` correspondant à l'**Action ID** défini dans le builder. Vous pouvez créer vos propres IDs, comme "allowNotifications". ```typescript showLineNumbers view.setEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': console.log('Login action triggered'); break; case 'allow_notifications': console.log('Allow notifications action triggered'); break; } return false; // Don't close the onboarding }, }); ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "actionId": "allow_notifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Cet événement est déclenché lorsqu'un onboarding termine son chargement : ```typescript showLineNumbers view.setEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton auquel l'action **Close** est assignée. <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Notez que vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: ```typescript showLineNumbers view.setEventHandlers({ onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, }); ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall si vous souhaitez l'afficher à l'intérieur de l'onboarding. Si vous voulez ouvrir un paywall après la fermeture de l'onboarding, il existe une approche plus directe : gérez l'action de fermeture et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La façon la plus fluide d'utiliser les paywalls dans les onboardings est de définir l'ID d'action égal à l'ID de placement du paywall. Notez que, sur iOS, une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous présentez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding en arrière-plan par programme. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue de l'onboarding avant de présenter le paywall. ```typescript showLineNumbers view.setEventHandlers({ onPaywall(actionId, meta) { // Dismiss onboarding before presenting paywall view.dismiss().then(() => { openPaywall(actionId); }); }, }); async function openPaywall(placementId: string) { // Implement your paywall opening logic here } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### Suivi de la navigation \{#tracking-navigation\} Vous recevez un événement d'analytics lorsque différents événements liés à la navigation se produisent pendant le flow d'onboarding : ```typescript showLineNumbers view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', event.type, meta.onboardingId); }, }); ``` L'objet `event` peut être de l'un des types suivants : |Type | Description | |------------|-------------| | `onboardingStarted` | Lorsque l'onboarding a été chargé | | `screenPresented` | Lorsqu'un écran est affiché | | `screenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et un `reply` optionnel (réponse de l'utilisateur). Déclenché quand les utilisateurs effectuent une action pour quitter l'écran. | | `secondScreenPresented` | Lorsque le deuxième écran est affiché | | `userEmailCollected` | Déclenché lorsque l'e-mail de l'utilisateur est collecté via le champ de saisie | | `onboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, [assignez l'ID `final` au dernier écran](design-onboarding). | | `unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `screensTotal` | Nombre total d'écrans dans le flow | <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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 } } ``` </Details> --- # File: capacitor-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK Capacitor" description: "Enregistrez et utilisez les données des onboardings dans votre app Capacitor avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](capacitor-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous bénéficiez ainsi d'animations plus fluides, d'un rendu natif cohérent, de temps de chargement plus rapides et d'aucune dépendance au runtime WebView. Consultez [Récupérer les flows & paywalls](capacitor-get-pb-paywalls) et [Afficher les flows & paywalls](capacitor-present-paywalls) pour démarrer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onStateUpdated` est appelée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```typescript view.setEventHandlers({ onStateUpdated(action, meta) { // Process data }, }); ``` Consultez le format des actions [ici](https://capacitor.adapty.io/types/onboardingstateupdatedaction). <Details> <summary>Exemples de données enregistrées (le format peut différer selon votre implémentation)</summary> ```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 } } } ``` </Details> ## Cas d'utilisation \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de lui demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](capacitor-setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans un champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre app, cela peut ressembler à ceci : ```typescript showLineNumbers view.setEventHandlers({ onStateUpdated(action, meta) { // Store user preferences or responses if (action.elementType === 'input') { const profileParams: any = {}; // Map elementId to appropriate profile field switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile({ params: profileParams }).catch((error) => { // handle the error }); } } }, }); ``` ### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\} En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le builder d'onboarding et attribuez des IDs significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](capacitor-setting-user-attributes) pour les utilisateurs. ```typescript showLineNumbers view.setEventHandlers({ onStateUpdated(action, meta) { // Handle quiz responses and set custom attributes if (action.elementType === 'select') { const profileParams: any = {}; // Map quiz responses to custom attributes switch (action.elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile({ params: profileParams }).catch((error) => { // handle the error }); } } }, }); ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](capacitor-paywalls) pour le placement dans le code de votre app. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](capacitor-handling-onboarding-events#opening-a-paywall). --- # File: capacitor-best-practices --- --- title: "Bonnes pratiques avec le SDK Capacitor" description: "Modèles de référence pour intégrer le SDK Adapty sur Capacitor — ordre d'appel, gestion des erreurs et autres règles de préparation à la production." --- <CustomDocCardList /> --- # File: capacitor-sdk-call-order --- --- title: "Ordre d'appel dans le SDK Capacitor" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs #2002 intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre." --- `adapty.activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant qu'il n'a pas résolu, le SDK n'a aucun état. Tout appel émis avant ou en parallèle d'`activate()` échoue avec [`#2002 notActivated`](capacitor-handle-errors#custom-network-codes). Si votre application authentifie des utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `adapty.identify()` à ce moment-là. N'appelez pas les méthodes liées aux actions utilisateur tant qu'`identify` n'a pas résolu. Les appels en concurrence avec celui-ci échouent soit avec [`#3006 profileWasChanged`](capacitor-handle-errors#custom-network-codes), soit atterrissent sur le profil anonyme créé à l'activation. Quand cela se produit, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et analytiques (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks UID avant d'appeler `adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre chemin dépend de deux choses : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou analytique. - **Étapes 2 et 5** : Obligatoires pour chaque application. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou analytique (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie des utilisateurs et récupère l'identifiant utilisateur client après le lancement. Si vous avez l'identifiant utilisateur client au lancement de l'application, passez-le directement dans `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, donc l'étape 4 est inutile. | Étape | Appel | Quand | Remarques | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou analytique (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'app, en premier | Attendez le callback UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `adapty.activate({ apiKey: '...', params: { customerUserId: '...' } })` | Lancement de l'app, après l'étape 1, si vous avez l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `adapty.activate({ apiKey: '...' })` sans `customerUserId` | Lancement de l'app, après l'étape 1, si vous n'avez pas l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `adapty.setIntegrationIdentifier({ key: '...', value: '...' })` pour chaque MMP | Après l'étape 2, avant tout appel lié à une action utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. | | 4 | `await adapty.identify({ customerUserId: 'YOUR_USER_ID' })` | Après l'étape 3 (ou l'étape 2 sans MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Toujours `await`. Les appels concurrents pendant `identify` produisent `#3006 profileWasChanged`. | | 5 | `getPaywall` (`getFlow` dans le SDK v4), `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 sans MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne une perte d'accès premium pour les utilisateurs existants, un `appsflyer_id` manquant sur les profils, et des paywalls retournés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent via un paiement web (Stripe, Paddle) et installent ensuite l'application native, le premier `activate()` de l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flow d'authentification ou le referrer d'installation), passez-le directement dans `activate()`. Sinon, l'achat web est invisible sur l'appareil tant que vous n'avez pas appelé `identify({ customerUserId: 'YOUR_USER_ID' })` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque paiement web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: capacitor-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK Capacitor" description: "Récupérez les paywalls Adapty de façon fiable : timing, mise en cache et stratégies de secours pour Capacitor." --- Une récupération fiable de paywall sur Capacitor repose sur trois principes : un affichage rapide, le retour du paywall ciblé par audience, et un repli fluide en cas de réseau lent. Les règles ci-dessous couvrent le timing, la mise en cache et les stratégies de secours pour y parvenir. :::tip Ces règles supposent que `adapty.activate()` et `adapty.identify()` ont déjà résolu. Consultez [Ordre des appels dans le SDK Capacitor](capacitor-sdk-call-order). ::: Les conseils ci-dessous utilisent les noms de méthodes de la v3. Dans le SDK v4, `getPaywall` est renommé en `getFlow` (voir le [guide de migration](migration-to-capacitor-sdk-v4)) — toutes les règles s'appliquent sans modification. ## Règles et pièges à éviter \{#rules-and-pitfalls\} | À faire | À ne pas faire | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Ne pré-récupérez pas tous les placements simultanément au lancement. | La pré-récupération en masse bloque le thread principal et provoque un écran noir pendant la rafale. | | Appelez `getPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement du listener `onLatestProfileLoad`. | N'appelez pas `getPaywall` au lancement de l'app dans `App.tsx`. | L'attribution n'est pas encore disponible. Le paywall se résout sur l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeoutMs` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | N'attendez pas indéfiniment sur `getPaywall`. | Sans timeout, les utilisateurs sur une connexion médiocre voient un écran blanc jusqu'à ce que le réseau réponde — ou ferment l'app. | Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products-capacitor) pour la référence des paramètres `fetchPolicy` et `loadTimeoutMs`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour les connexions médiocres \{#tune-for-poor-connectivity\} Pour les marchés avec une connectivité régulièrement médiocre (zones rurales, transports, régions affectées par le routage) : - Définissez `fetchPolicy: 'return_cache_data_else_load'` sur chaque récupération sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Définissez `loadTimeoutMs` entre 3 000 et 5 000 millisecondes et acceptez le paywall de secours lorsque le timeout se déclenche. - Ne bloquez pas l'affichage du paywall sur `adapty.getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: capacitor-show-aa-targeted-paywall --- --- title: "Afficher un paywall ciblé AA au premier lancement dans le SDK Capacitor" description: "Affichez un paywall immédiatement et mettez-le à jour pour les utilisateurs Apple Ads une fois l'attribution appliquée dans Capacitor, en utilisant AdaptyProfile.appliedAttributionSources." --- L'attribution Apple Ads (AA) arrive de façon asynchrone après `adapty.activate()`. Au premier lancement, elle n'est généralement pas encore disponible, donc `getFlow` se résout par rapport à l'audience par défaut et les utilisateurs Apple Ads ratent votre paywall segmenté AA. Plutôt que de retarder le paywall jusqu'à la réception de l'attribution, affichez-en un immédiatement et actualisez-le dès que l'attribution AA est appliquée — ainsi, les utilisateurs Apple Ads voient la variante ciblée et les autres voient un paywall sans attente. `AdaptyProfile.appliedAttributionSources` vous indique quand l'attribution AA a été appliquée. ## Avant de commencer \{#before-you-start\} Vous avez besoin de : - SDK Adapty Capacitor **3.17.1** ou version ultérieure. - Apple Ads configuré pour l'application dans Adapty. Voir [Apple Ads](apple-search-ads). ## Fonctionnement \{#how-it-works\} Après `adapty.activate()`, le SDK demande l'attribution Apple Ads à Apple en arrière-plan et transmet le résultat au backend d'Adapty. Quand AA devient la source d'attribution active pour le profil, le SDK envoie un `AdaptyProfile` mis à jour à votre listener `onLatestProfileLoad`, avec `'apple_search_ads'` dans son tableau `appliedAttributionSources`. Cela vous permet de charger le paywall en deux étapes : 1. Appelez `getFlow` immédiatement. Sans attribution appliquée, Adapty résout la requête par rapport à l'audience par défaut, et l'utilisateur voit un paywall tout de suite. 2. Quand `'apple_search_ads'` apparaît, appelez à nouveau `getFlow`. Adapty résout alors la requête par rapport à l'audience Apple Ads et retourne le paywall ciblé, qui remplace le premier. `appliedAttributionSources` peut être vide ou absent. Cela signifie soit : - L'attribution Apple Ads n'a pas encore été traitée pour ce profil, soit - aucune attribution n'est arrivée du tout. Dans tous les cas, l'étape 1 est sans risque — Adapty résout la requête par rapport à l'audience qui correspond à l'état actuel du profil, généralement l'audience par défaut. L'étape 2 ne s'exécute que lorsque `'apple_search_ads'` apparaît. :::important À chaque lancement suivant, le profil en cache contient déjà `'apple_search_ads'` dans `appliedAttributionSources`, donc le premier `getFlow` renvoie déjà le paywall segmenté Apple Ads — il n'y a pas de second appel ni de changement visible. Le flow en deux étapes n'a d'importance qu'au premier lancement, tant que l'attribution est encore en cours de traitement. ::: ## Implémentation \{#implementation\} Affichez un paywall immédiatement, puis écoutez `'apple_search_ads'` et actualisez le paywall dès qu'il arrive. 1. **Activez le SDK.** Voir [Installer et configurer le SDK Capacitor](sdk-installation-capacitor). 2. **Chargez et affichez un paywall** avec `getFlow` comme d'habitude — ne bloquez pas sur l'attribution. 3. **Abonnez-vous aux mises à jour du profil** avec `adapty.addListener('onLatestProfileLoad', …)` et surveillez `'apple_search_ads'`. Quand il apparaît, récupérez à nouveau le paywall et affichez le mis à jour. Si vous n'avez pas encore configuré le listener, voir [Écouter les mises à jour d'abonnement](capacitor-check-subscription-status#listen-to-subscription-updates) : ```typescript const listener = await adapty.addListener('onLatestProfileLoad', async ({ profile }) => { if (!profile.appliedAttributionSources?.includes('apple_search_ads')) return; const targeted = await adapty.getFlow({ placementId }); // present the targeted flow in place of the first one }); // Call listener.remove() after the upgrade, or after a timeout (see below). ``` 4. **Arrêtez d'écouter après un délai d'expiration.** La plupart des utilisateurs ne reçoivent jamais d'attribution Apple Ads, donc supprimez le listener au bout d'un moment plutôt que de le garder ouvert pour toute la session. Configurez un [paywall de secours](capacitor-use-fallback-paywalls) pour le placement afin que l'utilisateur voie toujours quelque chose en cas d'échec d'une requête. ## Exemple complet \{#complete-example\} `onAppleAdsAttribution` se résout dès que l'attribution Apple Ads est appliquée, ou rejette après `timeoutMs`. L'utilisation ci-dessous charge un paywall immédiatement, puis le récupère à nouveau quand l'attribution arrive — les utilisateurs Apple Ads obtiennent le paywall ciblé, et si l'attribution n'arrive jamais, le premier paywall reste en place : ```typescript const APPLE_ADS_SOURCE = 'apple_search_ads'; const placementId = 'YOUR_PLACEMENT_ID'; function hasAppleAdsAttribution(profile: AdaptyProfile): boolean { return profile.appliedAttributionSources?.includes(APPLE_ADS_SOURCE) ?? false; } /** * Resolves once Apple Ads attribution is applied to the profile. * Rejects with a timeout error if attribution never arrives within `timeoutMs`. * Call after `adapty.activate()`. */ export function onAppleAdsAttribution(timeoutMs: number): Promise<void> { return new Promise((resolve, reject) => { let timer: ReturnType<typeof setTimeout> | undefined; let handle: { remove: () => void } | undefined; const stop = () => { clearTimeout(timer); handle?.remove(); }; adapty .addListener('onLatestProfileLoad', ({ profile }) => { if (!hasAppleAdsAttribution(profile)) return; stop(); resolve(); }) .then(listener => { handle = listener; }); timer = setTimeout(() => { stop(); reject(new Error(`Apple Ads attribution timed out after ${timeoutMs}ms`)); }, timeoutMs); }); } let flow = await adapty.getFlow({ placementId }); onAppleAdsAttribution(30_000) .then(() => adapty.getFlow({ placementId })) .then(updated => { flow = updated; }) .catch(() => { console.log('Apple Ads attribution or loading failed'); }); ``` Au premier lancement, un utilisateur Apple Ads voit brièvement le paywall par défaut avant qu'il soit remplacé. Si vous affichez des paywalls avec le Paywall Builder, décidez si la re-présentation est acceptable, ou appliquez la mise à jour uniquement avant que le paywall soit affiché. Ajustez `timeoutMs` en fonction du temps pendant lequel vous souhaitez garder l'écoute active — l'attribution qui arrive le fait généralement en quelques secondes après le lancement. Si votre application écoute déjà `onLatestProfileLoad` à d'autres fins (par exemple, [vérifier le statut de l'abonnement](capacitor-check-subscription-status#listen-to-subscription-updates)), vous n'avez pas besoin de le modifier. `adapty.addListener` prend en charge plusieurs listeners indépendants, donc celui-ci s'ajoute sans affecter les autres. --- # File: capacitor-test --- --- title: "Test & release in Capacitor SDK" description: "Apprenez à tester et publier votre application Capacitor avec le SDK Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application Capacitor, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu sur iOS et Android. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox d'Apple et l'environnement de test de Google Play. ## Tester votre application \{#test-your-app\} Pour des tests complets de vos achats intégrés, consultez nos guides de test par plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android). ## Préparer la publication \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [Liste de vérification avant publication](release-checklist) pour confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats s'effectuent et sont bien remontés à Adapty - L'accès se déverrouille et se restaure correctement - Les exigences en matière de confidentialité et de validation sont respectées --- # File: kids-mode-capacitor --- --- title: "Mode Enfants dans le SDK Capacitor" description: "Activez facilement le Mode Enfants pour respecter les politiques d'Apple et Google. Aucune donnée IDFA, GAID ou publicitaire collectée dans le SDK Capacitor." --- Si votre application Capacitor est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/) et de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour répondre à ces politiques et passer les révisions des stores. ## Ce qui est requis \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte 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) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous vous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `<Prénom.Nom>` sera clairement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des IDs hachés ou des UUIDs générés par l'appareil) pour assurer la conformité. ## Activer le Mode Enfants \{#enabling-kids-mode\} ### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, désactivez la collecte de l'IDFA, du GAID et de l'adresse IP de l'utilisateur : ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // Disable IP address collection ipAddressCollectionDisabled: true, // Disable IDFA collection on iOS ios: { idfaCollectionDisabled: true }, // Disable Google Advertising ID collection on Android android: { adIdCollectionDisabled: true } } }); console.log('Adapty activated with Kids Mode enabled'); } catch (error) { console.error('Failed to activate Adapty with Kids Mode:', error); } ``` ### Configurations spécifiques à chaque plateforme \{#platform-specific-configurations\} #### iOS \{#ios\} <SDKv4> Même avec la collecte IDFA désactivée dans le code (ci-dessus), votre build inclut toujours les frameworks `AdSupport` et `AppTrackingTransparency`. La catégorie Enfants de l'App Store ne les autorise pas. Et comme le SDK v4 installe le SDK iOS natif via Swift Package Manager, il n'y a pas d'étape Podfile pour les supprimer. Pour respecter les exigences d'Apple, ajoutez la commande `adapty-kids-mode` fournie avec le SDK dans le `postinstall` de votre application. Elle active le trait `KidsMode` du SDK, qui exclut ce code à la compilation. La commande se réapplique à chaque installation : ```json showLineNumbers title="package.json" { "scripts": { "postinstall": "adapty-kids-mode" } } ``` Réinstallez ensuite et résolvez à nouveau les packages iOS, puis compilez avec **Xcode 26** ou une version ultérieure : ```sh showLineNumbers title="Shell" npm install npx cap sync ios ``` Pour désactiver le Mode Enfants, exécutez `adapty-kids-mode disable` et synchronisez à nouveau. </SDKv4> <SDKv3> Si vous utilisez CocoaPods pour iOS, vous pouvez également activer le Mode Enfants au niveau natif : 1. Mettez à jour votre Podfile : - Si vous **n'avez pas** de section `post_install`, ajoutez l'intégralité du bloc de code ci-dessous. - Si vous **avez déjà** une section `post_install`, intégrez les lignes mises en évidence dedans. ```ruby showLineNumbers title="Podfile" def adapty_enable_kids_mode(installer) installer.pods_project.targets.each do |target| next unless target.name == 'Adapty' target.build_configurations.each do |config| flags = config.build_settings['OTHER_SWIFT_FLAGS'] || '$(inherited)' flags = flags.join(' ') if flags.is_a?(Array) config.build_settings['OTHER_SWIFT_FLAGS'] = "#{flags} -DADAPTY_KIDS_MODE" end target.frameworks_build_phase.files.dup.each do |bf| target.frameworks_build_phase.remove_build_file(bf) if bf.display_name.to_s.include?('AdSupport') end end installer.pods_project.save Dir.glob(File.join(installer.sandbox.root, 'Target Support Files', '**', '*.xcconfig')).each do |xc| File.write(xc, File.read(xc).gsub(/\s*-framework\s+"?AdSupport"?/, '')) end end post_install do |installer| # ... keep your existing post_install body (Flutter adds one automatically) ... adapty_enable_kids_mode(installer) # <-- enable Adapty Kids Mode end ``` 2. Exécutez la commande suivante pour appliquer les modifications : ```sh showLineNumbers title="Shell" pod install ``` </SDKv3> #### Android : supprimer la permission d'identifiant publicitaire \{#android-remove-the-advertising-id-permission\} Définir `adIdCollectionDisabled: true` (ci-dessus) empêche Adapty de collecter l'identifiant publicitaire, mais le SDK déclare toujours la permission `AD_ID`. Si votre application cible **uniquement** les enfants et est compilée pour Android 13 (API 33) ou supérieur, Google Play vous interdit même de la demander. Effectuez deux ajouts dans votre élément `<manifest>` : 1. Déclarez le namespace `tools` (le manifeste par défaut de Capacitor l'omet). 2. Ajoutez une entrée `<uses-permission>` pour `AD_ID` avec `tools:node="remove"` afin de la supprimer. ```xml showLineNumbers title="android/app/src/main/AndroidManifest.xml" <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" /> </manifest> ``` ## Étapes suivantes \{#next-steps\} Une fois le Mode Enfants activé, assurez-vous de : 1. Tester votre application en profondeur pour vérifier que toutes les fonctionnalités fonctionnent correctement 2. Mettre à jour la politique de confidentialité de votre application pour refléter la désactivation de la collecte de données 3. Soumettre votre application pour révision avec une documentation claire sur la conformité au Mode Enfants Pour plus d'informations sur les exigences spécifiques à chaque plateforme : - [Mode Enfants dans le SDK iOS](kids-mode) pour les détails de configuration iOS supplémentaires - [Mode Enfants dans le SDK Android](kids-mode-android) pour les détails de configuration Android supplémentaires --- # File: capacitor-reference --- --- title: "Référence" description: "Documentation de référence pour l'Adapty Capacitor SDK." --- Cette page contient la documentation de référence pour l'Adapty Capacitor SDK. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://capacitor.adapty.io/)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](capacitor-handle-errors)** - Gestion des erreurs et résolution des problèmes --- # File: capacitor-handle-errors --- --- title: "Gérer les erreurs dans le SDK Capacitor" description: "Gérer les erreurs dans le SDK Capacitor." --- Chaque erreur retournée par le SDK est une instance d'`AdaptyError`. Voici un exemple : :::tip **Activez les logs verbeux avant de déboguer.** La plupart des `AdaptyError` encapsulent une erreur sous-jacente de StoreKit, Play Billing, réseau ou backend. Avec les logs verbeux activés (`adapty.setLogLevel({ logLevel: 'verbose' })` — voir [Logging](sdk-installation-capacitor#logging)), cette erreur encapsulée s'affiche dans la console, ce qui vous indique généralement la cause réelle. La propriété `detail` d'`AdaptyError` est renseignée quel que soit le niveau de log — les logs verbeux la font simplement apparaître dans la console. ::: ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product }); // Handle purchase result if (result.type === 'success') { console.log('Purchase successful:', result.profile); } else if (result.type === 'user_cancelled') { console.log('User cancelled the purchase'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { if (error instanceof AdaptyError) { console.error('Adapty error:', error.adaptyCode, error.localizedDescription); // Handle specific error codes switch (error.adaptyCode) { case ErrorCodeName.cantMakePayments: console.log('In-app purchases are not allowed on this device'); break; case ErrorCodeName.notActivated: console.log('Adapty SDK is not activated'); break; case ErrorCodeName.productPurchaseFailed: console.log('Purchase failed:', error.detail); break; default: console.log('Other error occurred:', error.detail); } } else { console.error('Non-Adapty error:', error); } } ``` ## Propriétés des erreurs \{#error-properties\} La classe `AdaptyError` expose les propriétés suivantes : | Propriété | Type | Description | |----------|------|-------------| | `adaptyCode` | `number` | Code d'erreur numérique (ex. : `1003` pour cantMakePayments) | | `localizedDescription` | `string` | Message d'erreur compréhensible par l'utilisateur | | `detail` | `string \| undefined` | Détails supplémentaires sur l'erreur (optionnel) | | `message` | `string` | Message d'erreur complet incluant le code et la description | ## Codes d'erreur \{#error-codes\} Le SDK exporte des constantes et des utilitaires pour travailler avec les codes d'erreur : ### Constante ErrorCodeName \{#errorcodename-constant\} Associe des identifiants textuels à des codes numériques : ```typescript ErrorCodeName.cantMakePayments // 1003 ErrorCodeName.notActivated // 2002 ErrorCodeName.networkFailed // 2005 ``` ### Constante ErrorCode \{#errorcode-constant\} Associe des codes numériques à des identifiants textuels : ```typescript ErrorCode[1003] // 'cantMakePayments' ErrorCode[2002] // 'notActivated' ErrorCode[2005] // 'networkFailed' ``` ### Fonctions utilitaires \{#helper-functions\} ```typescript // Get numeric code from string name: getErrorCode('cantMakePayments') // 1003 // Get string name from numeric code: getErrorPrompt(1003) // 'cantMakePayments' ``` ### Comparer les codes d'erreur \{#comparing-error-codes\} **Important :** `error.adaptyCode` est un **nombre**, il faut donc le comparer directement avec des codes numériques : ```typescript // Option 1: Use ErrorCodeName constant (recommended) ✅ if (error.adaptyCode === ErrorCodeName.cantMakePayments) { console.log('Cannot make payments'); } // Option 2: Compare with numeric literal ✅ if (error.adaptyCode === 1003) { console.log('Cannot make payments'); } // NOT like this ❌ - compares number to string and will never match if (error.adaptyCode === ErrorCode[1003]) { } ``` ## Gestionnaire d'erreurs global \{#global-error-handler\} Vous pouvez configurer un gestionnaire d'erreurs global pour intercepter toutes les erreurs Adapty : ```typescript showLineNumbers // Set up global error handler AdaptyError.onError = (error: AdaptyError) => { console.error('Global Adapty error:', { code: error.adaptyCode, message: error.localizedDescription, detail: error.detail }); // Handle specific error types globally if (error.adaptyCode === ErrorCodeName.notActivated) { // SDK not activated - maybe retry activation console.log('SDK not activated, attempting to reactivate...'); } }; ``` ## Patterns courants de gestion des erreurs \{#common-error-handling-patterns\} ### Gérer les erreurs d'achat \{#handle-purchase-errors\} ```typescript showLineNumbers async function handlePurchase(product: AdaptyPaywallProduct) { try { const result = await adapty.makePurchase({ product }); if (result.type === 'success') { console.log('Purchase successful:', result.profile); } else if (result.type === 'user_cancelled') { console.log('User cancelled the purchase'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { if (error instanceof AdaptyError) { switch (error.adaptyCode) { case ErrorCodeName.cantMakePayments: console.log('In-app purchases not allowed'); break; case ErrorCodeName.productPurchaseFailed: console.log('Purchase failed:', error.detail); break; default: console.error('Purchase error:', error.localizedDescription); } } } } ``` ### Gérer les erreurs réseau \{#handle-network-errors\} ```typescript showLineNumbers async function fetchFlow(placementId: string) { try { const flow = await adapty.getFlow({ placementId }); return flow; } catch (error) { if (error instanceof AdaptyError) { switch (error.adaptyCode) { case ErrorCodeName.networkFailed: console.log('Network error, retrying...'); // Implement retry logic break; case ErrorCodeName.serverError: console.log('Server error:', error.detail); break; case ErrorCodeName.notActivated: console.log('SDK not activated'); break; default: console.error('Paywall fetch error:', error.localizedDescription); } } throw error; } } ``` ## Codes StoreKit système \{#system-storekit-codes\} | Erreur | Code | Description | |-----|----|-----------| | unknown | 0 | Cette erreur indique qu'une erreur inconnue ou inattendue s'est produite. | | clientInvalid | 1 | Ce code d'erreur indique que le client n'est pas autorisé à effectuer l'action tentée. | | paymentCancelled | 2 | <p>Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.</p><p>Aucune action n'est requise, mais en termes de logique métier, vous pouvez proposer une remise à votre utilisateur ou lui rappeler plus tard.</p> | | paymentInvalid | 3 | Cette erreur indique que l'un des paramètres de paiement n'a pas été reconnu par le store. | | paymentNotAllowed | 4 | <p>Ce code d'erreur indique que l'utilisateur n'est pas autorisé à valider des paiements. Raisons possibles :</p><p></p><p>- Les paiements ne sont pas pris en charge dans le pays de l'utilisateur.</p><p>- L'utilisateur est mineur.</p> | | storeProductNotAvailable | 5 | Ce code d'erreur indique que le produit demandé est absent de l'App Store. Assurez-vous que le produit est disponible pour le pays utilisé. | | cloudServicePermissionDenied | 6 | Ce code d'erreur indique que l'utilisateur n'a pas autorisé l'accès aux informations du service Cloud. | | cloudServiceNetworkConnectionFailed | 7 | Ce code d'erreur indique que l'appareil n'a pas pu se connecter au réseau. | | cloudServiceRevoked | 8 | Ce code d'erreur indique que l'utilisateur a révoqué l'autorisation d'utiliser ce service cloud. | | privacyAcknowledgementRequired | 9 | Ce code d'erreur indique que l'utilisateur n'a pas encore accepté la politique de confidentialité du store. | | unauthorizedRequestData | 10 | Ce code d'erreur indique que la requête est mal construite. | | invalidOfferIdentifier | 11 | <p>L'identifiant de l'offre n'est pas valide. Raisons possibles :</p><p></p><p>- Vous n'avez pas configuré d'offre avec cet identifiant dans l'App Store.</p><p>- Vous avez révoqué l'offre.</p><p>- Vous avez mal saisi l'identifiant de l'offre.</p> | | invalidSignature | 12 | Ce code d'erreur indique que la signature dans une remise de paiement n'est pas valide. Assurez-vous d'avoir renseigné le champ **In-app purchase Key ID** et téléchargé le fichier **In-App Purchase Private Key**. Consultez la rubrique [Configure App Store integration](app-store-connection-configuration) pour plus de détails. | | missingOfferParams | 13 | <p>Cette erreur indique des problèmes avec l'intégration Adapty ou avec les offres.</p><p>Consultez [Configure App Store integration](app-store-connection-configuration) et [Offers](offers) pour savoir comment les configurer.</p> | | invalidOfferPrice | 14 | Ce code d'erreur indique que le prix que vous avez spécifié dans le store n'est plus valide. Les offres doivent toujours représenter un prix réduit. | ## Codes Android personnalisés \{#custom-android-codes\} | Erreur | Code | Description | |-----|----|-----------| | adaptyNotInitialized | 20 | Vous devez configurer correctement le SDK Adapty via la méthode `Adapty.activate`. Découvrez comment procéder [pour React Native](sdk-installation-reactnative). | | productNotFound | 22 | Cette erreur indique que le produit demandé à l'achat n'est pas disponible dans le store. | | invalidJson | 23 | Le JSON du paywall n'est pas valide. Corrigez-le dans l'Adapty Dashboard. Consultez la rubrique [Customize paywall with remote config](customize-paywall-with-remote-config) pour plus de détails. | | currentSubscriptionToUpdateNotFoundInHistory | 24 | L'abonnement d'origine à renouveler est introuvable. | | pendingPurchase | 25 | Cette erreur indique que l'état de l'achat est en attente plutôt qu'acheté. Consultez la page [Handling pending transactions](https://developer.android.com/google/play/billing/integrate#pending) dans la documentation Android Developer pour plus de détails. | | billingServiceTimeout | 97 | Cette erreur indique que la requête a atteint le délai d'expiration maximal avant que Google Play puisse répondre. Cela peut être causé, par exemple, par un retard dans l'exécution de l'action demandée par l'appel de la Play Billing Library. | | featureNotSupported | 98 | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. | | billingServiceDisconnected | 99 | Cette erreur fatale indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. | | billingServiceUnavailable | 102 | Cette erreur temporaire indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau entre l'appareil client et les services Google Play Billing. | | billingUnavailable | 103 | <p>Cette erreur indique qu'une erreur de facturation utilisateur s'est produite pendant le processus d'achat. Exemples de situations où cela peut se produire :</p><p></p><p>1\. L'application Play Store sur l'appareil de l'utilisateur est obsolète.</p><p>2. L'utilisateur se trouve dans un pays non pris en charge.</p><p>3. L'utilisateur est un utilisateur entreprise, et son administrateur a désactivé les achats pour les utilisateurs.</p><p>4. Google Play ne peut pas débiter le moyen de paiement de l'utilisateur. Par exemple, la carte de crédit de l'utilisateur a peut-être expiré.</p><p>5. L'utilisateur n'est pas connecté à l'application Play Store.</p> | | developerError | 105 | Il s'agit d'une erreur fatale indiquant que vous utilisez incorrectement une API. | | billingError | 106 | Il s'agit d'une erreur fatale indiquant un problème interne avec Google Play lui-même. | | itemAlreadyOwned | 107 | Le produit consommable a déjà été acheté. | | itemNotOwned | 108 | Cette erreur indique que l'action demandée sur l'élément a échoué car | ## Codes StoreKit personnalisés \{#custom-storekit-codes\} | Erreur | Code | Description | |-----|----|-----------| | noProductIDsFound | 1000 | <p>Cette erreur indique qu'aucun des produits du paywall n'est disponible dans le store.</p><p>Si vous rencontrez cette erreur, suivez les étapes ci-dessous pour la résoudre :</p><p></p><p>1. Vérifiez que tous les produits ont été ajoutés à l'Adapty Dashboard.</p><p>2. Assurez-vous que le Bundle ID de votre application correspond à celui d'Apple Connect.</p><p>3. Vérifiez que les identifiants de produits des stores correspondent à ceux que vous avez ajoutés au tableau de bord. Notez que les identifiants ne doivent pas contenir le Bundle ID, sauf s'il est déjà inclus dans le store.</p><p>4. Confirmez que le statut de paiement de l'application est actif dans vos paramètres fiscaux Apple. Assurez-vous que vos informations fiscales sont à jour et que vos certificats sont valides.</p><p>5. Vérifiez qu'un compte bancaire est associé à l'application afin qu'elle soit éligible à la monétisation.</p><p>6. Vérifiez si les produits sont disponibles dans toutes les régions. Assurez-vous également que vos produits sont à l'état **"Ready to Submit"**.</p> | | productRequestFailed | 1002 | <p>Impossible de récupérer les produits disponibles pour le moment. Raison possible :</p><p></p><p>- Aucun cache n'a encore été créé et il n'y a pas de connexion Internet simultanément.</p> | | cantMakePayments | 1003 | Les achats intégrés ne sont pas autorisés sur cet appareil. | | noPurchasesToRestore | 1004 | Cette erreur indique que Google Play n'a pas trouvé d'achat à restaurer. | | cantReadReceipt | 1005 | <p>Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.</p><p>Aucune action n'est requise, mais en termes de logique métier, vous pouvez proposer une remise à votre utilisateur ou lui rappeler plus tard.</p> | | productPurchaseFailed | 1006 | L'achat du produit a échoué. Cette erreur encapsule une erreur StoreKit sous-jacente — lisez l'erreur encapsulée (ou activez les logs détaillés pour la voir dans la console) pour connaître la raison réelle. L'erreur encapsulée est généralement l'un des codes StoreKit 0–14 du tableau ci-dessus — le plus souvent `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` ou `invalidOfferPrice`. Si vous ne pouvez pas identifier une raison précise, essayez un nouveau [profil sandbox](test-purchases-in-sandbox) ; si le problème persiste, contactez le support Apple. | | refreshReceiptFailed | 1010 | Cette erreur indique que le reçu n'a pas été reçu. Applicable à StoreKit 1 uniquement. | | receiveRestoredTransactionsFailed | 1011 | La restauration des achats a échoué. | ## Codes réseau personnalisés \{#custom-network-codes\} | Erreur | Code | Description | | :------------------- | :--- | :----------------------------------------------------------- | | notActivated | 2002 | Vous devez configurer correctement le SDK Adapty via la méthode `Adapty.activate`. Découvrez comment procéder [pour React Native](sdk-installation-reactnative). | | badRequest | 2003 | Requête incorrecte. | | serverError | 2004 | Erreur serveur. | | networkFailed | 2005 | La requête réseau a échoué. | | decodingFailed | 2006 | Cette erreur indique que le décodage de la réponse a échoué. | | encodingFailed | 2009 | Cette erreur indique que l'encodage de la requête a échoué. | | analyticsDisabled | 3000 | Nous ne pouvons pas traiter les événements analytics, car vous les avez désactivés. Consultez la rubrique [Analytics integration](analytics-integration) pour plus de détails. | | wrongParam | 3001 | Cette erreur indique que certains de vos paramètres sont incorrects : vide alors qu'il ne devrait pas l'être, mauvais type, etc. | | activateOnceError | 3005 | Il n'est pas possible d'appeler la méthode `.activate` plus d'une fois. | | profileWasChanged | 3006 | Le profil utilisateur a été modifié pendant l'opération. | | fetchTimeoutError | 3101 | Cette erreur signifie que le paywall n'a pas pu être récupéré dans le délai imparti. Pour éviter cette situation, [configurez des fallbacks locaux](fetch-paywalls-and-products). | | operationInterrupted | 9000 | Cette opération a été interrompue par le système. | --- # File: capacitor-sdk-migration-guides --- --- title: "Guides de migration pour le SDK Capacitor" description: "Guides de migration pour les versions du SDK Adapty Capacitor." --- Cette page regroupe tous les guides de migration pour le SDK Adapty Capacitor. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées : - **[Migrer vers v4.0 (beta)](migration-to-capacitor-sdk-v4)** - [**Migrer vers v3.16**](migration-to-capacitor-316) --- # File: migration-to-capacitor-sdk-v4 --- --- title: "Migrer le SDK Adapty Capacitor vers la v. 4.0" description: "Migrez vers le SDK Adapty Capacitor v4.0 (bêta) en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK Adapty Capacitor 4.0 (bêta) introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall({ placementId, locale?, params? })` | `adapty.getFlow({ placementId, params? })` | | `adapty.getPaywallForDefaultAudience({ placementId, locale?, params? })` | `adapty.getFlowForDefaultAudience({ placementId, params? })` | | `adapty.getPaywallProducts({ paywall })` | `adapty.getPaywallProducts({ flow })` | | `adapty.logShowPaywall({ paywall })` | `adapty.logShowFlow({ flow })` | | `AdaptyPaywall` (type) | `AdaptyFlow` + `AdaptyFlowPaywall` | | `createPaywallView(paywall, params?)` | `createFlowView(flow, params?)` | | `PaywallViewController` | `FlowViewController` | | `EventHandlers` (type) | `FlowEventHandlers` | | `CreatePaywallViewParamsInput` | `CreateFlowViewParamsInput` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` conserve son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` conserve également son nom, en prenant désormais un `AdaptyFlow`. Les méthodes `getFlow` et `getFlowForDefaultAudience` ne prennent plus de paramètre `locale` — passez-le plutôt à `createFlowView`. Les API d'achat et de profil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) et `setFallback` conservent les mêmes signatures, mais le fichier de secours lui-même doit être retéléchargé — voir [Fichiers de secours](#fallback-files). Les méthodes de vue `present`, `dismiss`, `setEventHandlers` et `showDialog`, ainsi que les gestionnaires d'événements `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` et `onAndroidSystemBack` conservent les mêmes noms qu'en v3. Les méthodes d'onboarding fonctionnent toujours mais sont dépréciées — voir [Dépréciation de l'API onboarding](#onboarding-api-deprecation). Certains comportements par défaut ont changé — voir [Changements de comportement par défaut](#default-behavior-changes). ## Versions minimales \{#minimum-versions\} Les prérequis d'exécution sont inchangés depuis v3.16+ : **iOS 15.0**, **Android minSdk 24** et **Capacitor 8**. Aucune modification de la cible de déploiement n'est nécessaire. Il y a un nouveau prérequis de build : **Xcode 26 ou supérieur** — le SDK iOS natif Adapty 4.0.2 inclus dans cette version utilise Swift tools 6.2. v4 intègre les SDK natifs Adapty iOS 4.0.2 et Android BOM 4.0.1. ## Installation \{#installation\} ### Mettre à jour le package La v4.0 est une version préliminaire, il faut donc épingler la version exacte — npm ne sélectionne pas les versions préliminaires avec les plages caret/tilde : ```bash showLineNumbers npm install @adapty/capacitor@4.0.1-beta.1 ``` Synchronisez ensuite les projets natifs : ```bash showLineNumbers npx cap sync ``` ### iOS : Swift Package Manager uniquement \{#ios-swift-package-manager-only\} [Le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), donc à partir de la v4, le fichier `AdaptyCapacitor.podspec` est supprimé et le SDK s'installe sur iOS **uniquement via Swift Package Manager (SPM)**. Le projet iOS de votre application doit utiliser l'intégration SPM de Capacitor : - Nouvelles applications : ajoutez la plateforme iOS avec le gestionnaire de paquets SPM : ```bash showLineNumbers npx cap add ios --packagemanager SPM ``` - Applications existantes basées sur CocoaPods : migrez le projet iOS en suivant le [guide Capacitor pour utiliser SPM dans un projet existant](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project). Consultez [Installer le SDK Adapty](sdk-installation-capacitor) pour la configuration complète. ## Récupération des flows \{#fetching-flows\} ### getPaywall → getFlow Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et l'option `locale` quitte l'appel de récupération pour rejoindre `createFlowView` ; pour les paywalls personnalisés, toutes les locales sont retournées dans `flow.remoteConfigs` : ```diff showLineNumbers - const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); + const view = await createFlowView(flow, { locale: 'en' }); ``` `locale` reste optionnel dans `createFlowView` : omettez-le et la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de `en`. Voir [Localisations et codes de langue](capacitor-localizations-and-locale-codes). `getPaywallForDefaultAudience` est renommé de la même façon : ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID' }); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` conserve son nom mais accepte désormais un `AdaptyFlow` : ```diff showLineNumbers - const products = await adapty.getPaywallProducts({ paywall }); + const products = await adapty.getPaywallProducts({ flow }); ``` ### Fichiers de secours \{#fallback-files\} Le format du fichier de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le dans votre application. ## Modèle de données \{#data-model\} `getFlow` retourne un `AdaptyFlow` au lieu d'un `AdaptyPaywall`, et la structure de l'objet a changé : | Champ v3 `AdaptyPaywall` | Champ v4 `AdaptyFlow` | Action | |---|---|---| | `remoteConfig?` (unique) | `remoteConfigs?: AdaptyRemoteConfig[]` (tableau) | Un flow porte un Remote Config par langue configurée. Lisez celui qui correspond à l'utilisateur : `flow.remoteConfigs?.find((c) => c.lang === 'en')`. | | `products` | `flow.paywalls[i].productIdentifiers` | Les identifiants de produits se trouvent désormais sur chaque variation du flow, et non sur le flow lui-même. | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Déplacé du flow vers chaque variation de paywall. | | `version?: number` | `flowVersionId?: string` | Renommé, et le type est passé de `number` à `string`. | | `hasViewConfiguration` | supprimé | Supprimez tout contrôle `hasViewConfiguration` de votre code — `createFlowView` lève désormais une exception à la place (voir [Affichage des flows](#displaying-flows)). | | `requestLocale` | supprimé | La langue ne fait plus partie du modèle. | | _(nouveau)_ | `paywalls: AdaptyFlowPaywall[]` | Chaque entrée correspond à une variation de paywall dans le flow. | | _(nouveau)_ | `responseCreatedAt: number` | Horodatage de la réponse du serveur, en millisecondes. | `hasViewConfiguration` et `requestLocale` restent sur `AdaptyOnboarding` — seul le modèle de flow les supprime. Les identifiants de produits ont été déplacés du flow vers chaque variante : ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Méthodes de paywall web \{#web-paywall-methods\} `openWebPaywall` et `createWebPaywallUrl` conservent leurs noms, mais l'option `paywallOrProduct` accepte désormais un `AdaptyFlowPaywall` (une variante de flow) plutôt qu'un `AdaptyPaywall`. Vous pouvez toujours passer un `AdaptyPaywallProduct`. Vérifiez que `flow.paywalls` n'est pas vide avant de lire la première entrée : ```diff showLineNumbers const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); - await adapty.openWebPaywall({ paywallOrProduct: paywall }); + await adapty.openWebPaywall({ paywallOrProduct: flow.paywalls[0] }); ``` ## Suivi des vues de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` est renommé en `logShowFlow` et prend désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord. ```diff showLineNumbers - await adapty.logShowPaywall({ paywall }); + await adapty.logShowFlow({ flow }); ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage de flows ou de paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement. ## Affichage des flows \{#displaying-flows\} ### createPaywallView → createFlowView Renommez la fonction factory et passez l'`AdaptyFlow`. Le contrôleur retourné est renommé de `PaywallViewController` en `FlowViewController`, mais ses méthodes (`present`, `dismiss`, `setEventHandlers`, `showDialog`) restent inchangées. Le type des paramètres est renommé de `CreatePaywallViewParamsInput` en `CreateFlowViewParamsInput` : ```diff showLineNumbers - import { createPaywallView } from '@adapty/capacitor'; + import { createFlowView } from '@adapty/capacitor'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` `createFlowView` lève une `AdaptyError` si le flow n'a pas de vue configurée — ce qui remplace la vérification `hasViewConfiguration` de la v3 : ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - const view = await createPaywallView(paywall); - await view.present(); - } + try { + const view = await createFlowView(flow); + await view.present(); + } catch (error) { + // the flow has no view configured, or view creation failed + } ``` :::note Une vue de flow est à usage unique : après avoir appelé `dismiss()`, la vue est détruite et ses gestionnaires d'événements sont effacés. Appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois. ::: ### Marges de zone sécurisée Android \{#android-safe-area-paddings\} `CreateFlowViewParamsInput` ajoute un nouveau paramètre : `enableSafeArea`, qui contrôle les marges de zone sécurisée Android à l'exécution. Il est imbriqué sous la clé `android` et vaut `true` par défaut : ```typescript showLineNumbers const view = await createFlowView(flow, { android: { enableSafeArea: true }, }); ``` ## Gestion des événements \{#handling-events\} L'interface du gestionnaire d'événements est renommée de `EventHandlers` en `FlowEventHandlers`, et un callback est renommé. Les corps des gestionnaires existants n'ont pas besoin d'être modifiés — il suffit de renommer : ```diff showLineNumbers - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` Tous les autres gestionnaires d'événements conservent leur nom. Deux d'entre eux reçoivent également un deuxième argument : `onPurchaseCompleted` devient `(purchaseResult, product)` et `onPurchaseFailed` devient `(error, product)`, où `product` est l'`AdaptyPaywallProduct` concerné. Consultez [Gérer les événements de flow et de paywall](capacitor-handling-events) pour la liste complète. v4 ajoute également quelques fonctionnalités que vous pouvez activer : - Les méthodes `adapty.openWebUrl({ url, openIn })` et `adapty.requestAppReview()` — elles alimentent les gestionnaires par défaut `onUrlPress` et `onRequestAppReview`, de sorte que les URLs et les demandes d'évaluation de l'application sont gérées nativement sans configuration particulière. Ne les appelez directement que si vous remplacez ces gestionnaires. - Gestion des achats en mode Observateur dans les flows via les nouveaux gestionnaires `onObserverPurchaseInitiated` / `onObserverRestoreInitiated`. Voir [Présenter des flows en mode Observateur](capacitor-present-flows-in-observer-mode). ## Changements de comportement par défaut \{#default-behavior-changes\} Ces changements ne provoquent pas d'erreurs de compilation, testez-les donc à l'exécution : - **`onAndroidSystemBack`**: Le comportement par défaut est passé de la fermeture de la vue à son maintien ouvert. Pour retrouver l'ancien comportement, renvoyez `true` depuis le handler. - **`onPurchaseCompleted`**: Le comportement par défaut est passé de la fermeture de la vue (sauf si l'utilisateur a annulé l'achat) à son maintien ouvert dans tous les cas. Pour retrouver l'ancien comportement, renvoyez `purchaseResult.type !== 'user_cancelled'` depuis le handler. - **`onRestoreCompleted`**: Le comportement par défaut est passé de la fermeture de la vue après une restauration réussie à son maintien ouvert. Pour retrouver l'ancien comportement, renvoyez `true` depuis le handler. - **`onUrlPress`**: Le comportement par défaut ouvre désormais l'URL via la couche native, en respectant le paramètre de navigateur intégré ou externe configuré dans le tableau de bord. Surchargez le handler pour ouvrir les URL vous-même. - **Les vues sont à usage unique** : après `dismiss()`, la vue est détruite. Appelez `createFlowView` à nouveau pour afficher le flow une nouvelle fois. ## API supprimées \{#removed-apis\} ### Exports supprimés Ces symboles ne sont plus exportés depuis `@adapty/capacitor`. Supprimez leurs imports : - **`AdaptyPaywall`** : Utilisez `AdaptyFlow` et `AdaptyFlowPaywall` à la place. - **`ProductReference`** : Utilisez `AdaptyProductIdentifier`, accessible via `flow.paywalls[i].productIdentifiers`. - **`AdaptyPaywallBuilder`** : Supprimé. Les flows et paywalls s'affichent nativement. - **`AdaptyAndroidSubscriptionUpdateParameters`** : Utilisez la structure imbriquée des paramètres d'achat `android` (voir ci-dessous). ### activate: lockMethodsUntilReady `lockMethodsUntilReady` (déjà obsolète et sans effet en v3) est supprimé. Retirez-le de votre appel `activate` — le conserver ne compile plus : ```diff showLineNumbers - await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY', params: { lockMethodsUntilReady: true } }); + await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY' }); ``` ### makePurchase : paramètres Android \{#makepurchase-android-parameters\} La forme Android plate (deprecated) de `MakePurchaseParamsInput` est supprimée — seule la forme imbriquée subsiste. Déplacez les paramètres d'achat Android dans `params: { android: { ... } }`. Consultez [Effectuer des achats](capacitor-making-purchases) pour un exemple complet. ## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\} L'ancienne API onboarding est dépréciée depuis la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, mais sera supprimée dans une future version — prévoyez donc la migration de vos onboardings vers le Flow Builder. Symboles dépréciés : `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView` et `OnboardingViewController`. --- # File: migration-to-capacitor-316 --- --- title: "Migrer le SDK Adapty Capacitor vers v3.16" description: "Migrez vers le SDK Adapty Capacitor v3.16 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- À partir de la version 3.16.0 du SDK Adapty, Capacitor 8 est requis. Si vous avez besoin de Capacitor 7, utilisez la version 3.15 du SDK Adapty. Pour passer au SDK Capacitor v3.16, assurez-vous que votre projet utilise Capacitor 8. Si vous utilisez encore Capacitor 7, deux options s'offrent à vous : 1. **Passer à Capacitor 8** : Suivez le [guide officiel de migration Capacitor](https://capacitorjs.com/docs/updating/8-0) pour mettre à jour votre projet, puis installez le SDK Adapty v3.16. 2. **Rester sur le SDK Adapty v3.15** : Si la mise à niveau vers Capacitor 8 n'est pas envisageable, continuez à utiliser le SDK Adapty v3.15, qui prend en charge Capacitor 7. --- # End of Documentation _Generated on: 2026-08-04T15:08:25.967Z_ _Successfully processed: 45/45 files_ # FLUTTER - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:25.970Z Total files: 53 --- # File: flutter-sdk-overview --- --- title: "Flutter SDK overview" description: "Découvrez le SDK Flutter d'Adapty et ses fonctionnalités clés." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Flutter.svg?style=flat&logo=flutter)](https://github.com/adaptyteam/AdaptySDK-Flutter/releases) Bienvenue ! Notre mission : rendre les achats intégrés aussi simples que possible 🚀 Le SDK Flutter d'Adapty vous libère des contraintes liées aux achats intégrés pour que vous puissiez vous concentrer sur l'essentiel : créer des applications formidables. Voici ce que nous gérons pour vous : - Gestion des achats, validation des reçus et gestion des abonnements prêts à l'emploi - Création et test de flows et de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans configuration – cohortes, LTV, churn et analyse d'entonnoir inclus - Statut d'abonnement utilisateur toujours à jour entre les sessions et les appareils - Intégration de votre application avec des services d'attribution marketing et d'analyse en une seule ligne de code :::note Avant de plonger dans le code, vous devrez intégrer Adapty avec App Store Connect et Google Play Console, puis configurer les produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Commencer \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons couvrir dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-flutter) : Ajoutez le SDK comme dépendance à votre projet et activez-le dans le code. 2. [Activer les achats via les flows](flutter-quickstart-paywalls) : Configurez le flux d'achat pour que les utilisateurs puissent acheter des produits. Pour construire votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](flutter-quickstart-manual). 3. [Vérifier le statut de l'abonnement](flutter-check-subscription-status) : Vérifiez automatiquement l'état de l'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (optionnel)](flutter-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir que leurs données sont stockées de manière cohérente sur tous les appareils. ### Le voir en action \{#see-it-in-action\} Vous voulez voir comment tout s'assemble ? On a ce qu'il vous faut : - **Application exemple** : Consultez notre [exemple complet](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) qui illustre la configuration complète ## Concepts principaux \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts clés qui font fonctionner Adapty. Ce qui fait la force de l'approche d'Adapty, c'est que seuls les placements sont codés en dur dans votre application. Tout le reste – produits, designs de paywalls, tarification et offres – peut être géré de façon flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre application – abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Des produits regroupés avec une configuration, attachés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, construite dans le Flow Builder. Adapty affiche l'interface et gère l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous construisez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](flutter-quickstart-manual). Dans le code SDK, les deux sont récupérés via la même méthode `getFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Pensez aux placements comme au « où » et au « quand » de votre stratégie de monétisation. Les placements courants incluent : - `main` - L'emplacement principal de votre paywall - `onboarding` - Affiché pendant le flow d'onboarding de l'utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits dans votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque les utilisateurs achètent un produit, leur profil se voit attribuer un **niveau d'accès** que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-flutter --- --- title: "Installer et configurer le SDK Flutter" description: "Guide étape par étape pour installer le SDK Adapty sur Flutter pour les applications basées sur des abonnements." --- Le SDK Adapty comprend deux modules clés pour une intégration fluide dans votre application Flutter : - **Core Adapty** : Ce SDK essentiel est nécessaire au bon fonctionnement d'Adapty dans votre application. - **AdaptyUI** : Ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez notre [exemple d'application](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example), qui illustre la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Prérequis \{#requirements\} Le SDK Adapty prend en charge iOS 13.0+, mais nécessite iOS 15.0+ pour fonctionner correctement avec les paywalls créés dans le Paywall Builder. Adapty Flutter SDK 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — relève les exigences minimales à **iOS 15.0+**, **Xcode 26+** et **Flutter 3.32.0+** (Dart 3.8.0+). Consultez [Adapty SDK 4.0](#adapty-sdk-40-swift-package-manager) ci-dessous pour les détails d'installation. :::info Adapty est compatible avec Google Play Billing Library jusqu'à la version 8.x. Par défaut, Adapty fonctionne avec Google Play Billing Library v7.0.0, mais si vous souhaitez forcer une version ultérieure, vous pouvez [ajouter la dépendance](https://developer.android.com/google/play/billing/integrate#dependency) manuellement. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Flutter.svg?style=flat&logo=flutter)](https://github.com/adaptyteam/AdaptySDK-Flutter/releases) :::important Les étapes ci-dessous installent le dernier SDK stable (3.x). Si vous avez besoin de la v4 — requise pour le [Flow Builder](adapty-flow-builder) et utilisée par le [démarrage rapide](flutter-quickstart-paywalls) — suivez plutôt [Adapty SDK 4.0 : Swift Package Manager](#adapty-sdk-40-swift-package-manager) ci-dessous. ::: 1. Ajoutez Adapty à votre fichier `pubspec.yaml` : ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: ^<the latest SDK version> ``` 2. Exécutez la commande suivante pour installer les dépendances : ```bash showLineNumbers title="Terminal" flutter pub get ``` 3. Importez les SDK Adapty dans votre application : ```dart showLineNumbers title="main.dart" import 'package:adapty_flutter/adapty_flutter.dart'; ``` ### SDK Adapty 4.0 : Swift Package Manager \{#adapty-sdk-40-swift-package-manager\} Ajoutez Adapty Flutter SDK 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — à votre `pubspec.yaml` : ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: 4.0.3 ``` À partir de la v4, le SDK iOS natif n'est plus distribué via CocoaPods — le plugin le récupère uniquement via **Swift Package Manager** ([le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). Si vous utilisez Flutter 3.32–3.43, activez la prise en charge de Swift Package Manager une seule fois : ```bash showLineNumbers title="Terminal" flutter config --enable-swift-package-manager ``` Flutter 3.44 et versions ultérieures activent Swift Package Manager par défaut, aucune action n'est donc nécessaire. Pour les changements d'API dans la v4, consultez le [guide de migration](migration-to-flutter-sdk-v4). ## Activer le module Adapty du SDK \{#activate-adapty-module-of-adapty-sdk\} Activez le SDK dans le code de votre application. :::note Le SDK n'a besoin d'être activé qu'une seule fois dans votre application. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. ```dart showLineNumbers title="main.dart" void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override void initState() { _initializeAdapty(); super.initState(); } Future<void> _initializeAdapty() async { try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY'), ); } catch (e) { // handle the error } } Widget build(BuildContext context) { return Text("Hello"); } } ``` :::important Attendez que `activate` soit résolu avant d'appeler toute autre méthode du SDK Adapty. Consultez [l'ordre des appels dans le SDK Flutter](flutter-sdk-call-order) pour la séquence complète. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), commencez par [activer le module AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) ci-dessous, puis suivez le [guide de démarrage rapide du Paywall Builder](flutter-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [guide de démarrage rapide pour les paywalls personnalisés](flutter-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder) et avez [installé le module AdaptyUI](sdk-installation-flutter#install-adapty-sdk), vous devez également activer AdaptyUI : :::note Les dépendances liées à AdaptyUI sont liées à votre application, que AdaptyUI soit activé ou non. ::: :::important Dans votre code, vous devez activer le module Adapty principal avant d'activer AdaptyUI. ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withActivateUI(true), // This automatically activates AdaptyUI ); ``` ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Level | Description | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------ | | `AdaptyLogLevel.error` | Seules les erreurs seront journalisées | | `AdaptyLogLevel.warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais méritent attention, seront journalisés. | | `AdaptyLogLevel.info` | Les erreurs, avertissements et divers messages d'information seront journalisés. Valeur par défaut | | `AdaptyLogLevel.verbose` | Toute information supplémentaire utile au débogage, comme les appels de fonctions, les requêtes API, etc., sera journalisée. | | `AdaptyLogLevel.debug` | Les informations de débogage seront journalisées. | Vous pouvez définir le niveau de log dans votre application avant de configurer Adapty : ```dart showLineNumbers title="main.dart" // Set log level before activation. // 'verbose' is recommended for development and the first production release await Adapty().setLogLevel(AdaptyLogLevel.verbose); // Or set it during configuration await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withLogLevel(AdaptyLogLevel.verbose), ); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs, sauf si vous les envoyez explicitement. Vous pouvez toutefois mettre en place des politiques de sécurité supplémentaires pour respecter les règles du store ou les réglementations de votre pays. #### Désactiver la collecte et le partage des adresses IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` sur `true` pour désactiver la collecte et le partage des adresses IP des utilisateurs. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'IP ne sont pas nécessaires pour votre application. ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withIpAddressCollectionDisabled(true), ); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `appleIdfaCollectionDisabled` (iOS) ou `googleAdvertisingIdCollectionDisabled` (Android) sur `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour respecter les politiques de l'App Store/Play Store, éviter de déclencher la demande d'autorisation App Tracking Transparency, ou si votre application n'a pas besoin d'une attribution publicitaire ou d'analyses basées sur les identifiants publicitaires. ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withAppleIdfaCollectionDisabled(true) // iOS ..withGoogleAdvertisingIdCollectionDisabled(true), // Android ); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Le module est activé automatiquement avec le SDK Adapty. Si vous n'utilisez pas le Paywall Builder et souhaitez désactiver le module AdaptyUI, passez `withActivateUI(false)` lors de l'activation. Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire la consommation réseau. Vous pouvez personnaliser les paramètres du cache en fournissant une configuration personnalisée. Utilisez `withMediaCacheConfiguration` pour remplacer les limites du cache par défaut. C'est facultatif — si vous n'appelez pas cette méthode, les valeurs par défaut seront utilisées (100 Mo sur disque, nombre illimité en mémoire). En revanche, si vous créez l'objet de configuration, tous ses paramètres sont obligatoires. ```dart showLineNumbers title="main.dart" final mediaCacheConfig = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 200 * 1024 * 1024, // 200 MB memoryStorageCountLimit: 2147483647, // max int value diskStorageSizeLimit: 200 * 1024 * 1024, // 200 MB ); await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withMediaCacheConfiguration(mediaCacheConfig), ); ``` **Paramètres :** | Paramètre | Présence | Description | |-------------------------|----------|-----------------------------------------------------------------------------| | memoryStorageTotalCostLimit | requis | Taille totale du cache en mémoire en octets. La valeur par défaut est 100 Mo. | | memoryStorageCountLimit | requis | Limite du nombre d'éléments dans le stockage en mémoire. La valeur par défaut est la valeur int maximale. | | diskStorageSizeLimit | requis | Limite de taille des fichiers sur disque en octets. La valeur par défaut est 100 Mo. | ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont activés sur iOS et désactivés sur Android. Pour les activer également sur Android, définissez `withGoogleLocalAccessLevelAllowed` sur `true` : ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withGoogleLocalAccessLevelAllowed(true), ); ``` ### Effacer les données lors d'une restauration depuis une sauvegarde \{#clear-data-on-backup-restore\} Lorsque `appleClearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, notamment les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état propre. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withAppleClearDataOnBackup(true) // default – false ); ``` ## Dépannage \{#troubleshooting\} #### Règles de sauvegarde Android (configuration de l'Auto Backup) \{#android-backup-rules-auto-backup-configuration\} Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules` ou `android:allowBackup`. Symptômes typiques : `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 Ces modifications doivent être effectuées dans votre répertoire de la plateforme Android (généralement situé dans le dossier `android/` de votre projet). ::: Pour résoudre ce problème, vous devez : - Indiquer au gestionnaire de fusion de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Créer des fichiers de règles de sauvegarde qui fusionnent les règles d'Adapty avec celles des autres SDKs. #### 1. Ajoutez l'espace de noms `tools` à votre manifeste \{#1-add-the-tools-namespace-to-your-manifest\} Dans votre fichier `AndroidManifest.xml`, assurez-vous que la balise racine `<manifest>` inclut tools : ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. Remplacez les attributs de sauvegarde dans `<application>` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `<application>` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion de remplacer les valeurs des bibliothèques : ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez les fichiers de règles de sauvegarde fusionnés \{#3-create-merged-backup-rules-files\} Créez des fichiers XML dans le répertoire `res/xml/` de votre projet Android, en combinant les règles d'Adapty avec celles des autres SDKs. Android utilise des formats de règles de sauvegarde différents selon la version de l'OS, donc créer les deux fichiers garantit la compatibilité avec toutes les versions d'Android prises en charge par votre application. :::note Les exemples ci-dessous utilisent AppsFlyer comme exemple de SDK tiers. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> #### Les achats échouent après être revenu d'une autre application sur Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si l'Activity qui démarre le flow d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser de façon incorrecte lorsque l'utilisateur revient de Google Play, d'une application bancaire ou d'un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son traitement comme une annulation. Pour garantir le bon fonctionnement des achats, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flow d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui démarre le flow d'achat est définie sur `standard` ou `singleTop` : ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Erreurs de build Swift 6 causées par le remplacement de SWIFT_VERSION dans le Podfile \{#swift-6-build-errors-caused-by-podfile-swift_version-override\} Lors de la compilation de votre application Flutter pour iOS, vous pouvez rencontrer des erreurs de compilation Swift 6 sur les cibles de pods Adapty. Les symptômes typiques incluent des incompatibilités `@Sendable` dans `AdaptyUIBuilderLogic`, l'absence de conformité `Sendable` sur les types Adapty, ou des erreurs d'isolation d'acteur. Les pods Adapty déclarent `s.swift_version = '6.0'` et nécessitent Swift 6 pour être compilés. Le code de votre propre application peut rester en Swift 5 — seules les cibles de pods Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`, `AdaptyLogger`, `AdaptyPlugin`) ont besoin d'être compilées avec Swift 6. La cause la plus fréquente est un hook `post_install` dans `ios/Podfile` qui réécrit `SWIFT_VERSION` pour toutes les cibles de pods : ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` **Fix** : Excluez les cibles de pods Adapty de la substitution : ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name) target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` Ensuite, exécutez `pod install` depuis le répertoire `ios/` et reconstruisez le projet. Pour vérifier, ouvrez `ios/Pods/Pods.xcodeproj`, sélectionnez la cible pod `Adapty` → **Build Settings** → **Swift Language Version**. La valeur doit être **Swift 6**. --- # File: flutter-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK Flutter" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – des séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez un paywall à la place — voir [Implémenter les paywalls manuellement](flutter-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez les flows dans votre application (par exemple `main`, `onboarding`, `settings`). Vous associez les flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite les tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond aux besoins de votre app : | Implémentation | Complexité | Quand l'utiliser | |------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère tout le flux d'achat complexe, la validation des reçus et la gestion des abonnements en coulisses. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre application, mais vous récupérez quand même l'objet flow depuis Adapty pour garder de la flexibilité dans les offres de produits. Voir le [guide](flutter-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous avez déjà votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limites dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.** Si vous préférez construire l'interface du paywall vous-même, voir [Implémenter les paywalls manuellement](flutter-quickstart-manual). ::: Pour afficher un flow créé dans Adapty Flow Builder, vous n'avez besoin que de quelques lignes dans le code de votre application : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre application. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow quand les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez-y votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-flutter) dans le code de votre application. Ce guide utilise les APIs du SDK Adapty Flutter v4. :::tip La façon la plus rapide de réaliser ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des paywalls et des placements via la [CLI développeur](developer-cli-quickstart). ::: ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter des flows différents pour différentes audiences ou de lancer des [tests A/B](ab-tests). Pour récupérer un flow créé dans Adapty Flow Builder, vous devez : 1. Obtenir l'objet `flow` par l'ID de [placement](placements) en utilisant la méthode `getFlow` et vérifier s'il a été créé dans le builder grâce à la propriété `hasViewConfiguration`. 2. Créer la vue du flow en utilisant la méthode `createFlowView`. La vue contient les éléments d'interface et le style nécessaires pour afficher le flow. :::important Pour obtenir la configuration de la vue, vous devez activer le bouton **Show on device** dans le builder. Sinon, vous obtiendrez une configuration de vue vide et le flow ne sera pas affiché. ::: ```dart showLineNumbers try { // the requested flow final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final view = await AdaptyUI().createFlowView( flow: flow, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez la vue du flow, quelques lignes suffisent pour l'afficher. Pour afficher le flow, utilisez la méthode `view.present()` sur la `view` créée par la méthode `createFlowView`. Chaque `view` ne peut être présentée qu'une seule fois : une fois fermée, elle est libérée de la mémoire. Si vous avez besoin d'afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](flutter-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Quand les utilisateurs cliquent sur des boutons dans le flow, le SDK Flutter gère automatiquement les achats, la restauration, la fermeture de la vue et l'ouverture des URLs. Cependant, les autres boutons ont des IDs personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Pour contrôler ou surveiller les processus sur l'écran du flow, implémentez les méthodes `AdaptyUIFlowsEventsObserver` et définissez l'observateur avant d'afficher n'importe quel écran. Si un utilisateur a effectué une action, `flowViewDidPerformAction` sera appelé et votre application devra répondre en fonction de l'ID de l'action. Trois méthodes d'observateur sont **obligatoires** : `flowViewDidFinishPurchase`, `flowViewDidFinishRestore` et `flowViewDidReceiveError` — votre classe ne compilera pas sans elles. :::tip Consultez nos guides sur la gestion des [actions](flutter-handle-paywall-actions) et des [événements](flutter-handling-events) des boutons. ::: Implémentez l'observateur comme un objet dédié à longue durée de vie plutôt que comme un widget. Comme un seul slot d'observateur global est partagé dans toute l'application, le lier à un `State` entraînerait une fuite de l'écran (le SDK conserve une référence forte vers lui) et serait silencieusement remplacé lorsque le prochain écran s'enregistre. Utiliser `extends` hérite également du comportement par défaut du SDK, donc en dehors des trois méthodes obligatoires, vous ne surchargez que les callbacks qui vous intéressent. ```dart showLineNumbers title="Flutter" // A dedicated, long-lived handler for flow events. // It does NOT live inside a Widget/State, so it never leaks and is never // silently replaced when screens are pushed or popped. class FlowEventsHandler extends AdaptyUIFlowsEventsObserver { // A single, app-wide instance — same idiom as Adapty() and AdaptyUI(). static final FlowEventsHandler _instance = FlowEventsHandler._(); factory FlowEventsHandler() => _instance; FlowEventsHandler._(); // This method is called when user performs an action on the flow UI. // Overriding it replaces the default behavior (dismiss on close, open URLs), // so keep those cases if you want to preserve it. @override void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): // close the flow on the Android back button view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } // Required: decide what happens after a purchase finishes @override void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { if (purchaseResult is! AdaptyPurchaseResultUserCancelled) { view.dismiss(); } } // Required: dismiss the flow once a restore succeeds @override void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { view.dismiss(); } // Required: handle rendering and other view errors @override void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { print('Flow error: $error'); view.dismiss(); } } ``` Enregistrez le handler **une seule fois** au démarrage de l'application, avant qu'un flow ne soit affiché : ```dart showLineNumbers title="Flutter" AdaptyUI().setFlowsEventsObserver(FlowEventsHandler()); ``` ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow. Vous devez maintenant [vérifier le niveau d'accès des utilisateurs](flutter-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment toutes ces étapes peuvent être intégrées ensemble dans votre application. ```dart void main() { // Register a single, long-lived observer once, before any flow is shown. // It is intentionally a plain object (NOT a Widget/State): its lifetime is the // whole app, so it never leaks and is never silently replaced when screens are // pushed or popped. AdaptyUI().setFlowsEventsObserver(FlowEventsHandler()); runApp(MaterialApp(home: FlowScreen())); } /// A dedicated handler for AdaptyUI flow events. /// /// It `extends` [AdaptyUIFlowsEventsObserver] (rather than being implemented /// by a `State`), which gives you two things for free: /// * the SDK's sensible defaults for optional callbacks, so besides the three /// required methods you only override what you actually care about; /// * a lifecycle that is independent of the widget tree — there is no strong /// reference back into a `Widget`, so nothing leaks and there is nothing to /// unregister. /// /// Every callback receives the [AdaptyUIFlowView] it relates to, so handling /// flow actions never requires a `BuildContext` or widget state. class FlowEventsHandler extends AdaptyUIFlowsEventsObserver { // A single, app-wide instance — same idiom as Adapty() and AdaptyUI(). static final FlowEventsHandler _instance = FlowEventsHandler._(); factory FlowEventsHandler() => _instance; FlowEventsHandler._(); // Called when the user performs an action on the flow UI. @override void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): // close the flow on the Android back button view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): // Open the URL natively, honoring the dashboard browser setting. AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } // Required: decide what happens after a purchase finishes. @override void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { if (purchaseResult is! AdaptyPurchaseResultUserCancelled) { view.dismiss(); } } // Required: dismiss the flow once a restore succeeds. @override void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { view.dismiss(); } // Required: handle rendering and other view errors. @override void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { print('Flow error: $error'); view.dismiss(); } } class FlowScreen extends StatefulWidget { const FlowScreen({super.key}); @override State<FlowScreen> createState() => _FlowScreenState(); } class _FlowScreenState extends State<FlowScreen> { @override void initState() { super.initState(); _showFlowIfNeeded(); } Future<void> _showFlowIfNeeded() async { try { final flow = await Adapty().getFlow( placementId: 'YOUR_PLACEMENT_ID', ); if (!flow.hasViewConfiguration) return; final view = await AdaptyUI().createFlowView(flow: flow); await view.present(); } catch (_) { // Handle any errors (network, SDK issues, etc.) } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Adapty Flow Example')), body: Center( // Add a button to re-trigger the flow for testing purposes. child: ElevatedButton( onPressed: _showFlowIfNeeded, child: const Text('Show Flow'), ), ), ); } } ``` --- # File: flutter-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK Flutter" description: "Apprenez à vérifier le statut d'abonnement dans votre application Flutter avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — afficher un paywall ou donner accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appelez `getProfile` si vous avez besoin des données de profil les plus récentes immédiatement (par exemple au lancement de l'application) ou si vous souhaitez forcer une mise à jour. - Configurez les **mises à jour automatiques du profil** pour conserver une copie locale automatiquement actualisée à chaque changement de statut d'abonnement. ### Obtenir le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour du profil dans votre application : 1. Utilisez `Adapty().didUpdateProfileStream.listen()` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode chaque fois que le statut d'abonnement de l'utilisateur change. 2. Enregistrez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser dans toute votre application sans effectuer de requêtes réseau supplémentaires. ```dart class SubscriptionManager { AdaptyProfile? _currentProfile; SubscriptionManager() { // Listen for profile updates Adapty().didUpdateProfileStream.listen((profile) { _currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() bool hasAccess() { return _currentProfile?.accessLevels['premium']?.isActive ?? false; } } ``` :::note Adapty appelle automatiquement le listener du flux de mise à jour du profil au démarrage de votre application, fournissant des données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Connecter le profil à la logique de paywall \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates concernant l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios tels que le lancement de l'application, l'accès aux sections premium ou l'affichage de contenu spécifique. ```dart Future<bool> _checkAccessLevel() async { try { final profile = await Adapty().getProfile(); return profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive ?? false; } catch (e) { print('Error checking access level: $e'); return false; // Show paywall if access check fails } } Future<void> _initializePaywall() async { await _loadPaywall(); final hasAccess = await _checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } ``` ## Prochaines étapes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](flutter-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce pour quoi ils ont payé. --- # File: flutter-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK Flutter" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans Flutter." --- :::important Ce guide vous concerne si vous disposez de votre propre système d'authentification. Vous y apprendrez comment gérer les profils utilisateurs dans Adapty pour les aligner avec votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez un **customer user ID** pour faire le lien entre les profils Adapty et votre système d'auth interne. Voici les différences entre utilisateurs anonymes et identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveaux profils à chaque réinstallation | Le même profil sur toutes les sessions et tous les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'app | Les données des utilisateurs identifiés persistent d'une installation à l'autre | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lors de l'activation du SDK au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, celui-ci est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme lors de l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, ceux-ci sont automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. Ainsi, avec les utilisateurs anonymes, de nouveaux profils sont créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). Pour les utilisateurs anonymes, vous devez compter les installations par **identifiants d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. ## Utilisateurs identifiés \{#identified-users\} Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID au moment de leur authentification. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils disposent d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après leur connexion ou leur inscription), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez jamais utilisé ce customer user ID auparavant**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez en dur la valeur du paramètre, tous les utilisateurs seront considérés comme un seul. ::: Utilisez toujours `await` avec `identify` avant d'appeler d'autres méthodes du SDK. Les appels simultanés produisent l'erreur `#3006 profileWasChanged` ou aboutissent sur le profil anonyme. Voir [Ordre des appels dans le SDK Flutter](flutter-sdk-call-order). ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID au moment d'activer le SDK, vous pouvez l'envoyer dans la méthode `activate` au lieu d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'au moment de l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`. Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé) ou un nouveau. Si vous en passez un nouveau, le nouveau profil créé lors de l'activation sera automatiquement lié au customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord analytiques, car les installations sont comptées sur la base des identifiants d'appareil. Un identifiant d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une énième installation, ni de l'utilisation d'un customer user ID existant. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génère pas d'événements d'installation supplémentaires. Si vous souhaitez compter les installations sur la base d'utilisateurs uniques plutôt que d'appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```dart showLineNumbers" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID) // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. ); } catch (e) { // handle the error } ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si votre application dispose d'un bouton de déconnexion, utilisez la méthode `logout`. :::important La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur. ::: ```dart showLineNumbers try { await Adapty().logout(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty le lie à son identifiant de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (déjà lié à un profil), vous devez obtenir le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](flutter-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](flutter-check-subscription-status) pour que les données se synchronisent automatiquement. ## Prochaines étapes \{#next-steps\} Félicitations ! Vous avez mis en place la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre app ! Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu - [**Onboardings**](flutter-onboardings) : Engagez les utilisateurs avec des onboardings et fidélisez-les - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code - [**Définir des attributs de profil personnalisés**](flutter-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher différents paywalls à différents utilisateurs --- # File: adapty-sdk-integration-skill-flutter --- --- title: "Intégrer Adapty dans votre application Flutter avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Flutter de bout en bout avec votre outil de codage IA." --- :::important La compétence est en bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-flutter) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-flutter --- --- title: "Intégrer Adapty dans votre application Flutter avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre application Flutter avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Flutter à l'aide d'un outil IA — vous lui fournissez les bonnes docs Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite une configuration du tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire via un skill LLM interactif ou manuellement depuis le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre app, vos produits, vos niveaux d'accès, vos paywalls et vos placements directement — sans ouvrir le Dashboard à chaque étape. Vous avez seulement besoin de [connecter vos stores](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à travers chaque étape — y compris quand ouvrir le Dashboard pour connecter vos stores. ### Approche manuelle \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir. 1. **Connectez vos stores** : Dans l'Adapty Dashboard, allez dans **App settings → General**. Connectez l'App Store et Google Play si votre application Flutter cible les deux plateformes. C'est indispensable pour que les achats fonctionnent. [Connecter les stores](integrate-payments) 2. **Copiez votre clé SDK publique** : Dans l'Adapty Dashboard, allez dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez à la configuration d'Adapty. 3. **Créez au moins un produit** : Dans l'Adapty Dashboard, allez sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les fournit via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : Dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID de placement est la chaîne que vous passez à `Adapty().getPaywall()`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : Dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels['premium']?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des apps. Si les utilisateurs payants accèdent à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` vs. un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois ces cinq éléments en place, vous êtes prêt à coder. Dites à votre LLM : « Ma clé SDK publique est X, mon ID de placement est Y » pour qu'il génère le code d'initialisation et de récupération des paywalls correct. ::: ### À configurer quand vous serez prêt \{#set-up-when-ready\} Ces éléments ne sont pas nécessaires pour commencer à coder, mais ils deviendront utiles à mesure que votre intégration avance : - **Tests A/B** : À configurer sur la page **Placements**. Aucune modification de code requise. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : Ajoutez des appels `getPaywall` avec différents IDs de placement. - **Intégrations analytiques** : À configurer sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytiques](analytics-integration) et [intégrations d'attribution](attribution-integration). ## Fournir la documentation Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs en fonction de vos questions — sans avoir à coller des URLs manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez : ``` npx ctx7 setup ``` Cette commande détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub de Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the Flutter SDK ``` :::warning Même si Context7 élimine le besoin de coller des liens de documentation manuellement, l'ordre d'implémentation est important. Suivez le [guide d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne. ::: ### Utiliser les docs en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle doc Adapty en Markdown brut. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-flutter.md](https://adapty.io/docs/fr/adapty-cursor-flutter.md). Chaque étape du [guide d'implémentation](#implementation-walkthrough) ci-dessous contient un bloc « À envoyer à votre LLM » avec des liens `.md` à coller. Pour accéder à davantage de documentation d'un coup, consultez les [fichiers d'index et sous-ensembles spécifiques à chaque plateforme](#plain-text-doc-index-files) ci-dessous. ## Guide d'implémentation \{#implementation-walkthrough\} La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devriez observer une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA prend en charge un mode de planification (comme le mode plan de Cursor ou Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et les docs Adapty avant d'écrire du code. Dites à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides à suivre : - [**Adapty Paywall Builder**](adapty-paywall-builder) : Vous créez des paywalls dans l'éditeur no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](flutter-making-purchases) : Vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats. - [**Mode Observer**](observer-vs-full-mode) : Vous conservez votre infrastructure d'achats existante et utilisez Adapty uniquement pour les analyses et les intégrations. Vous ne savez pas quoi choisir ? Lisez le [tableau comparatif dans le guide de démarrage rapide](flutter-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez la dépendance au SDK Adapty avec `flutter pub add` et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionnera sans ça. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-flutter) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-flutter.md ``` :::tip[Point de contrôle] - **Attendu :** L'application se compile et s'exécute sur iOS et Android. La console de débogage affiche le log d'activation d'Adapty. - **Point d'attention :** « Public API key is missing » → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis les paramètres de l'app. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de votre approche pour les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **Guides :** - [Activer les achats via les paywalls (guide de démarrage rapide)](flutter-quickstart-paywalls) - [Récupérer les paywalls du Paywall Builder et leur configuration](flutter-get-pb-paywalls) - [Afficher les paywalls](flutter-present-paywalls) - [Gérer les événements de paywall](flutter-handling-events) - [Répondre aux actions des boutons](flutter-handle-paywall-actions) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/flutter-quickstart-paywalls.md - https://adapty.io/docs/fr/flutter-get-pb-paywalls.md - https://adapty.io/docs/fr/flutter-present-paywalls.md - https://adapty.io/docs/fr/flutter-handling-events.md - https://adapty.io/docs/fr/flutter-handle-paywall-actions.md ``` :::tip[Point de contrôle] - **Attendu :** Le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat en sandbox. - **Point d'attention :** Paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement au tableau de bord et que le placement a une audience assignée. ::: </TabItem> <TabItem value="manual" label="Paywalls manuels"> **Guides :** - [Activer les achats dans votre paywall personnalisé (guide de démarrage rapide)](flutter-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-flutter) - [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-flutter) - [Effectuer des achats](flutter-making-purchases) - [Restaurer les achats](flutter-restore-purchase) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/flutter-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-flutter.md - https://adapty.io/docs/fr/present-remote-config-paywalls-flutter.md - https://adapty.io/docs/fr/flutter-making-purchases.md - https://adapty.io/docs/fr/flutter-restore-purchase.md ``` :::tip[Point de contrôle] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat en sandbox. - **Point d'attention :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Mode Observer"> **Guides :** - [Présentation du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode-flutter) - [Signaler les transactions en mode Observer](report-transactions-observer-mode-flutter) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-flutter.md - https://adapty.io/docs/fr/report-transactions-observer-mode-flutter.md ``` :::tip[Point de contrôle] - **Attendu :** Après un achat en sandbox via votre flux d'achat existant, la transaction apparaît dans le tableau de bord Adapty sous **Event Feed**. - **Point d'attention :** Aucun événement → vérifiez que vous signalez les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez le profil utilisateur pour un niveau d'accès actif afin de bloquer l'accès au contenu premium. **Guide :** [Vérifier le statut de l'abonnement](flutter-check-subscription-status) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/flutter-check-subscription-status.md ``` :::tip[Point de contrôle] - **Attendu :** Après un achat en sandbox, `profile.accessLevels['premium']?.isActive` retourne `true`. - **Point d'attention :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Liez les comptes utilisateurs de votre app aux profils Adapty pour que les achats persistent sur tous les appareils. :::important Ignorez cette étape si votre application ne gère pas l'authentification. ::: **Guide :** [Identifier les utilisateurs](flutter-quickstart-identify) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/flutter-quickstart-identify.md ``` :::tip[Point de contrôle] - **Attendu :** Après avoir appelé `Adapty().identify()`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Point d'attention :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution de profil anonyme. ::: ### Préparer le lancement \{#prepare-for-release\} Une fois votre intégration fonctionnelle en sandbox, parcourez la checklist de lancement pour vous assurer que tout est prêt pour la production. **Guide :** [Checklist de lancement](release-checklist) À envoyer à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Point de contrôle] - **Attendu :** Tous les éléments de la checklist confirmés : connexions aux stores, notifications serveur, flux d'achat, vérifications du niveau d'accès et exigences de confidentialité. - **Point d'attention :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**. ::: ## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\} Si vous avez besoin de donner à votre LLM un contexte plus large que des pages individuelles, nous hébergeons des fichiers d'index qui listent ou regroupent l'ensemble de la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : Liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par exemple ChatGPT), vous devrez télécharger `llms.txt` et le joindre à la conversation en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : L'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement quand vous avez besoin d'une vue d'ensemble complète. - Sous-ensembles Flutter [`flutter-llms.txt`](https://adapty.io/docs/fr/flutter-llms.txt) et [`flutter-llms-full.txt`](https://adapty.io/docs/fr/flutter-llms-full.txt) : Sous-ensembles spécifiques à la plateforme qui économisent des tokens par rapport au site complet. --- # File: flutter-paywalls --- --- title: "Flows et paywalls - Flutter" description: "Affichez et gérez les flows et paywalls créés avec Adapty Flow Builder ou Paywall Builder dans votre application Flutter." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['flutter-get-pb-paywalls', 'flutter-present-paywalls', 'flutter-handling-events', 'flutter-handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les flows et paywalls Adapty, consultez notre [guide de démarrage rapide](flutter-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['flutter-quickstart-manual', 'fetch-paywalls-and-products-flutter', 'present-remote-config-paywalls-flutter', 'flutter-making-purchases']} /> Pour d'autres guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](flutter-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['flutter-use-fallback-paywalls', 'flutter-web-paywall']} /> --- # File: flutter-get-pb-paywalls --- --- title: "Obtenir les flows et paywalls - Flutter" description: "Récupérez les flows et paywalls depuis Adapty dans votre application Flutter." --- <SDKv4> <MethodPromo method="getFlow" /> Après avoir [conçu votre flow ou votre paywall dans le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. Notez que cette rubrique concerne les flows et les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez la rubrique [Récupérer les paywalls et les produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-flutter). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des flows et des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-flutter) dans votre application mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Récupérez le flow ou le paywall et créez sa [vue](flutter-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible — idéalement bien avant de l'afficher. La méthode `createFlowView` charge la configuration de la vue et lance en arrière-plan le téléchargement et la mise en cache des images. Plus vous l'appelez tôt, plus ces téléchargements ont de temps pour s'achever. Au moment d'afficher le flow ou le paywall, sa configuration et ses images peuvent déjà être en cache, prêtes à l'affichage. Pour récupérer un flow ou un paywall, utilisez la méthode `getFlow` : ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // le flow/paywall demandé } on AdaptyError catch (adaptyError) { // gérer l'erreur } catch (e) { // gérer l'erreur } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser durant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement ainsi qu'un serveur de secours indépendant au cas où le CDN serait inaccessible. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos paywalls tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | défaut : 5 sec | <p>Une `Duration` qui limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en arrière-plan.</p> | ## Paramètres de réponse \{#response-parameters\} | Paramètre | Description | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objet `AdaptyFlow` contenant les identifiants du flow (`instanceIdentity`, `variationId`), son nom, son placement, ses variations de paywall (`paywalls`), ainsi que les éventuelles configurations distantes (`remoteConfigs`). | ## Récupérer la configuration de la vue \{#fetch-the-view-configuration\} :::important Veillez à activer le bouton **Show on device** dans le builder. Si cette option n'est pas activée, la configuration de la vue ne sera pas disponible pour être récupérée. ::: Si le placement a été conçu dans le **Flow Builder** ou le **Paywall Builder**, Adapty génère l'interface pour vous — la propriété `hasViewConfiguration` du flow récupéré est `true`. Créez la vue avec `createFlowView`, puis [présentez le flow ou le paywall](flutter-present-paywalls). Si le placement est un paywall personnalisé sans interface Builder (`hasViewConfiguration` vaut `false`), [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-flutter) à la place. :::warning Le résultat de la méthode `createFlowView` ne peut être présenté qu'une seule fois. Si vous devez le présenter à nouveau, appelez la méthode `createFlowView` une nouvelle fois. ::: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView(flow: flow); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | obligatoire | Un objet `AdaptyFlow` permettant d'obtenir une vue pour le flow/paywall souhaité. | | **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) utilisée pour afficher la vue — par exemple, `en` ou `pt-br`. Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci n'a pas de version `en`. Voir [Localisations et codes de langue](flutter-localizations-and-locale-codes). | | **customTags** | optionnel | Définit une map de tags personnalisés et de leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu, remplacés dynamiquement par des chaînes spécifiques pour personnaliser le contenu du flow/paywall. Consultez la rubrique [Tags personnalisés dans le Paywall Builder](custom-tags-in-paywall-builder) pour plus de détails. | | **preloadProducts** | optionnel | Activez cette option pour optimiser le moment d'affichage des produits à l'écran. Lorsque la valeur est `true`, AdaptyUI récupère automatiquement les produits nécessaires. Par défaut : `false`. | | **loadTimeout** | optionnel | Une `Duration` qui limite le temps de chargement de la configuration de la vue. Si le délai est dépassé, les données en cache ou le fallback local sont utilisés. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation de flow](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](flutter-localizations-and-locale-codes). ::: Une fois que vous avez la vue, [présentez le flow/paywall](flutter-present-paywalls). ## Récupérer un flow ou un paywall pour l'audience par défaut afin d'accélérer le chargement \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et les paywalls sont récupérés presque instantanément, et vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs ont une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est important de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `getFlow`, comme décrit dans la section [Récupérer le flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de rétrocompatibilité** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'un chargement plus rapide des flows ou des paywalls, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow/paywall } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont confrontés à une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre flow/paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via un simple dictionnaire : ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createFlowView( flow: flow, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Si une ressource est introuvable, le flow/paywall reviendra à son apparence par défaut. ::: ## Configurer les minuteries définies par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des minuteries personnalisées dans votre application mobile, transmettez une map `customTimers` à la méthode `createFlowView`. Chaque clé de la map correspond à un identifiant de minuterie, et sa valeur est un objet `DateTime` qui définit quand la minuterie se termine. Voici un exemple : ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView( flow: flow, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2027, 1, 1), // New Year 2027 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID**s des minuteries définies par le développeur dans l'Adapty Dashboard. La map `customTimers` permet à votre application de mettre à jour dynamiquement chaque minuterie avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin du minuteur, comme le jour du Nouvel An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures qui a démarré lorsque l'utilisateur a ouvert le flow. </SDKv4> <SDKv3> Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. :::warning Le nouveau Paywall Builder nécessite la version 3.3.0 ou supérieure du SDK Flutter. ::: Veuillez noter que ce sujet concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez le sujet [Récupérer les paywalls et les produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-flutter). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-flutter) dans votre application mobile. </details> ## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration d'affichage](flutter-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour récupérer un paywall, utilisez la méthode `getPaywall` : ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en"); // the requested paywall } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](flutter-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre recommandation d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir d'obtenir toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en interne.</p><p>Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.</p> | ## Paramètres de réponse \{#response-parameters\} | Paramètre | Description | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) contenant une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer la configuration d'affichage d'un paywall conçu avec le Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration d'affichage ne pourra pas être récupérée. ::: Après avoir récupéré le paywall, vérifiez s'il contient un `ViewConfiguration`, ce qui indique qu'il a été créé avec le Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si le `ViewConfiguration` est présent, traitez-le comme un paywall Paywall Builder ; sinon, [traitez-le comme un paywall Remote Config](present-remote-config-paywalls-flutter). ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Une fois que vous avez la vue, [affichez le paywall](flutter-present-paywalls). ## Obtenir un paywall pour une audience par défaut afin d'accélérer la récupération \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls sont récupérés presque instantanément, il n'est donc pas nécessaire de chercher à optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme détaillé dans la section [Récupérer les informations du paywall](flutter-get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité descendante** : si vous devez afficher des paywalls différentes pour différentes versions de l'application (actuelle et futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichées. - **Perte de ciblage** : tous les utilisateurs verront la même paywall conçue pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide du paywall, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, utilisez `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 3.2.0 du SDK Flutter. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre recommandation d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposent peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache n'est pas effacé au redémarrage de l'application ; il n'est supprimé que lors d'une réinstallation ou d'un nettoyage manuel.</p> | ## Personnaliser les assets \{#customize-assets\} Pour personnaliser les images et vidéos de votre paywall, implémentez des assets personnalisés. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle d'assets personnalisés, vous ciblez ces éléments par leurs identifiants pour personnaliser leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK Flutter d'Adapty vers la version 3.8.0 ou supérieure. ::: Voici un exemple montrant comment fournir des ressources personnalisées via un simple dictionnaire : ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Si un asset est introuvable, le paywall reviendra à son apparence par défaut. ::: ## Configurer les minuteries définies par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des minuteries personnalisées dans votre application mobile, passez une map `customTimers` à la méthode `createPaywallView`. Chaque clé de la map est un identifiant de minuterie, et sa valeur est un objet `DateTime` qui définit quand la minuterie se termine. Voici un exemple : ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2025, 1, 1), // New Year 2025 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID**s des minuteurs définis par le développeur dans l'Adapty Dashboard. La map `customTimers` permet à votre application de mettre à jour dynamiquement chaque minuteur avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin du minuteur, par exemple le Jour de l'An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures démarrée lorsque l'utilisateur a ouvert le paywall. </SDKv3> --- # File: flutter-present-paywalls --- --- title: "Afficher les flows & paywalls - Flutter" description: "Présentez les flows et paywalls dans les applications Flutter grâce aux fonctionnalités de monétisation d'Adapty." --- <SDKv4> Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. :::warning Ce guide concerne les flows et les paywalls créés avec le Paywall Builder. Pour afficher des **paywalls Remote Config**, consultez [Afficher un paywall conçu avec la Remote Config](present-remote-config-paywalls-flutter). ::: Le SDK Flutter d'Adapty propose deux façons d'afficher les flows et les paywalls : - **Écran autonome** - **Widget intégré** ## Afficher en tant qu'écran autonome \{#present-as-standalone-screen\} Pour afficher un flow ou un paywall en tant qu'écran autonome, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createFlowView`](flutter-get-pb-paywalls#fetch-the-view-configuration). Chaque `view` ne peut être présentée qu'une seule fois : une fois fermée, la vue est libérée de la mémoire. Si vous devez afficher à nouveau le flow ou le paywall, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Fermer le flow ou le paywall \{#dismiss-the-flow-or-paywall\} Quand vous devez fermer un flow ou un paywall par programmation, utilisez la méthode `dismiss()` : ```dart showLineNumbers title="Flutter" try { await view.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Fermer une vue la libère de la mémoire — une vue fermée ne peut plus être réaffichée. Créez-en une nouvelle avec `createFlowView` à la place. ::: ### Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'un flow ou une vue paywall est affiché sur Android. Sur Android, les alertes classiques apparaissent derrière la vue, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du flow ou du paywall sur toutes les plateformes. ```dart showLineNumbers title="Flutter" try { final action = await view.showDialog( title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', ); if (action == AdaptyUIDialogActionType.secondary) { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (e) { // handle error } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le flow ou le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.fullScreen` (par défaut) ou `AdaptyUIIOSPresentationStyle.pageSheet`. ```dart showLineNumbers try { await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## Intégrer dans la hiérarchie de widgets \{#embed-in-widget-hierarchy\} Pour intégrer un flow ou un paywall dans votre arbre de widgets existant, utilisez directement le widget `AdaptyUIFlowPlatformView` dans votre hiérarchie de widgets Flutter. ```dart showLineNumbers title="Flutter" AdaptyUIFlowPlatformView( flow: flow, // The flow object you fetched locale: 'en', // The localization to render the flow with onDidAppear: (view) { }, onDidDisappear: (view) { }, onDidPerformAction: (view, action) { }, onDidSelectProduct: (view, productId) { }, onDidStartPurchase: (view, product) { }, onDidFinishPurchase: (view, product, purchaseResult) { }, onDidFailPurchase: (view, product, error) { }, onDidStartRestore: (view) { }, onDidFinishRestore: (view, profile) { }, onDidFailRestore: (view, error) { }, onDidReceiveError: (view, error) { }, onDidFailLoadingProducts: (view, error) { }, onDidFinishWebPaymentNavigation: (view, product, error) { }, ) ``` :::note Pour que la vue de la plateforme Android fonctionne, assurez-vous que votre `MainActivity` étend `FlutterFragmentActivity` : ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: </SDKv4> <SDKv3> Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. :::warning Ce guide concerne uniquement les **paywalls créés avec le nouveau Paywall Builder**, qui nécessitent SDK v3.2.0 ou une version ultérieure. Le processus de présentation des paywalls diffère selon la version du Paywall Builder utilisée et selon les paywalls de Remote Config. - Pour présenter des **paywalls de Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-flutter). ::: Le SDK Flutter d'Adapty propose deux façons de présenter les paywalls : - **Écran autonome** - **Widget intégré** ## Afficher comme écran autonome \{#present-as-standalone-screen\} Pour afficher un paywall comme écran autonome, utilisez la méthode `view.present()` sur le `view` créé par la méthode [`createPaywallView`](flutter-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisé qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `createPaywallView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser le même `view` sans le recréer peut entraîner une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Fermer le paywall \{#dismiss-the-paywall\} Pour fermer le paywall par programmation, utilisez la méthode `dismiss()` : ```dart showLineNumbers title="Flutter" try { await view.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'une vue de paywall est affichée sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes. ```dart showLineNumbers title="Flutter" try { final action = await view.showDialog( title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', ); if (action == AdaptyUIDialogActionType.secondary) { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (e) { // handle error } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.fullScreen` (par défaut) ou `AdaptyUIIOSPresentationStyle.pageSheet`. ```dart showLineNumbers try { await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## Intégrer dans la hiérarchie de widgets \{#embed-in-widget-hierarchy\} Pour intégrer un paywall dans votre arborescence de widgets existante, utilisez le widget `AdaptyUIPaywallPlatformView` directement dans votre hiérarchie de widgets Flutter. ```dart showLineNumbers title="Flutter" AdaptyUIPaywallPlatformView( paywall: paywall, // The paywall object you fetched onDidAppear: (view) { }, onDidDisappear: (view) { }, onDidPerformAction: (view, action) { }, onDidSelectProduct: (view, productId) { }, onDidStartPurchase: (view, product) { }, onDidFinishPurchase: (view, product, purchaseResult) { }, onDidFailPurchase: (view, product, error) { }, onDidStartRestore: (view) { }, onDidFinishRestore: (view, profile) { }, onDidFailRestore: (view, error) { }, onDidFailRendering: (view, error) { }, onDidFailLoadingProducts: (view, error) { }, onDidFinishWebPaymentNavigation: (view, product, error) { }, ) ``` :::note Pour que la vue de plateforme Android fonctionne, assurez-vous que votre `MainActivity` étend `FlutterFragmentActivity` : ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: </SDKv3> --- # File: flutter-handle-paywall-actions --- --- title: "Répondre aux actions des boutons dans le SDK Flutter" description: "Gérez les actions des boutons de paywall dans Flutter avec Adapty pour une meilleure monétisation de l'application." --- <SDKv4> Si vous créez des flows ou des paywalls avec le builder Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action que vous avez assignée. Ce guide explique comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **La fermeture de la vue et l'ouverture des URL sont gérées automatiquement** par l'implémentation par défaut de `flowViewDidPerformAction`, et le SDK lui-même traite les achats et les restaurations. Toutes les autres actions des boutons, comme la connexion ou l'ouverture d'un autre flow, nécessitent l'implémentation de réponses appropriées dans le code de l'application. Notez que la réponse aux achats et restaurations *terminés* se fait dans les callbacks d'observateur requis — voir [Gérer les événements de flow et de paywall](flutter-handling-events). ::: ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui fermera votre flow ou paywall, dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. Aucun code n'est requis : l'implémentation par défaut de `flowViewDidPerformAction` ferme la vue lorsqu'elle reçoit `CloseAction`. :::info Le bouton **Back** du système Android ne ferme plus la vue par défaut. Il est transmis à `flowViewDidPerformAction` en tant que `AndroidSystemBackAction` — gérez-le vous-même si vous souhaitez que le bouton Retour ferme le flow ou le paywall. ::: Surchargez `flowViewDidPerformAction` si vous avez besoin d'un comportement personnalisé — par exemple, pour fermer également la vue avec le bouton Retour Android, comme dans la v3 : ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } ``` :::warning Surcharger `flowViewDidPerformAction` remplace entièrement l'implémentation par défaut — conservez les cas `CloseAction` et `OpenUrlAction` si vous souhaitez maintenir le comportement par défaut de fermeture et d'ouverture d'URL. ::: ## Ouvrir des URL depuis les flows et les paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien (par exemple, **Terms of use** ou **Privacy policy**), dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. Aucun code n'est requis : l'implémentation par défaut de `flowViewDidPerformAction` ouvre l'URL nativement via `AdaptyUI().openUrl`, en respectant le paramètre de navigateur intégré ou externe défini dans le tableau de bord. Le comportement par défaut suffit dans la plupart des cas. Si vous souhaitez tout de même ouvrir les URL vous-même, surchargez le gestionnaire : ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): view.dismiss(); break; case OpenUrlAction(url: final url): // Open the URL in whatever way fits your app break; default: break; } } ``` ## Se connecter à l'application \{#log-into-the-app\} Pour ajouter un bouton permettant aux utilisateurs de se connecter à votre application : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `login` qui identifie votre utilisateur. ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'login'): // Navigate to your login screen in whatever way fits your app break; default: break; } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre application, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall : ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'openNewPaywall'): // Display another flow or paywall break; default: break; } } ``` </SDKv4> <SDKv3> Si vous créez des paywalls avec le Paywall Builder Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action que vous avez assignée. Ce guide explique comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **Seuls les achats et les restaurations sont gérés automatiquement.** Toutes les autres actions des boutons, comme la fermeture des paywalls ou l'ouverture de liens, nécessitent l'implémentation de réponses appropriées dans le code de l'application. ::: ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui fermera votre paywall : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre application, implémentez un gestionnaire pour les actions `CloseAction` et `AndroidSystemBackAction`. :::info Dans le SDK Flutter, les actions `CloseAction` et `AndroidSystemBackAction` déclenchent la fermeture du paywall par défaut. Vous pouvez toutefois surcharger ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un paywall peut déclencher l'ouverture d'un autre. ::: ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): view.dismiss(); break; default: break; } } ``` ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le Paywall Builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. ```dart // You have to install url_launcher plugin in order to handle urls: // https://pub.dev/packages/url_launcher void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case OpenUrlAction(url: final url): final Uri uri = Uri.parse(url); launchUrl(uri, mode: LaunchMode.inAppBrowserView); break; default: break; } } ``` ## Se connecter à l'application \{#log-into-the-app-1\} Pour ajouter un bouton permettant aux utilisateurs de se connecter à votre application : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `login` qui identifie votre utilisateur. ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'login'): // Navigate to your login screen in whatever way fits your app break; default: break; } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions-1\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre application, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre paywall : ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'openNewPaywall'): // Display another paywall break; default: break; } } ``` </SDKv3> --- # File: flutter-handling-events --- --- title: "Flutter - Gérer les événements de flow et de paywall" description: "Découvrez comment gérer les événements liés aux abonnements dans Flutter avec Adapty pour suivre efficacement les interactions des utilisateurs." --- <SDKv4> :::important Ce guide couvre la gestion des événements pour les achats, les restaurations, la sélection de produits et le rendu. La fermeture de la vue et l'ouverture de liens sont gérées par l'implémentation par défaut de `flowViewDidPerformAction` — consultez notre [guide sur la gestion des actions de bouton](flutter-handle-paywall-actions) pour les remplacer ou gérer des actions de bouton personnalisées. ::: Les flows et paywalls configurés avec le 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 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 sur le flow ou le paywall. Découvrez comment répondre à ces événements ci-dessous. Pour contrôler ou surveiller les processus qui se déroulent sur l'écran du flow ou du paywall dans votre application mobile, implémentez les méthodes `AdaptyUIFlowsEventsObserver` et définissez l'observateur avant d'afficher un écran : ```dart showLineNumbers title="Flutter" AdaptyUI().setFlowsEventsObserver(this); ``` Trois méthodes d'observateur sont **obligatoires** — votre classe ne compilera pas sans elles : `flowViewDidFinishPurchase`, `flowViewDidFinishRestore` et `flowViewDidReceiveError`. Toutes les autres méthodes sont optionnelles. Pour détacher un observateur précédemment défini, passez `null` à `setFlowsEventsObserver`. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Les exemples d'événements ci-dessous montrent les propriétés disponibles sur chaque objet, avec des valeurs illustratives dans les commentaires. ### Événements générés par l'utilisateur \{#user-generated-events\} #### Vue apparue \{#view-appeared\} Cette méthode est invoquée lorsque la vue du flow ou du paywall est affichée à l'écran. :::note Sur iOS, également invoquée lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré. ::: ```dart showLineNumbers title="Flutter" void flowViewDidAppear(AdaptyUIFlowView view) { } ``` #### Vue disparue \{#view-disappeared\} Cette méthode est invoquée lorsque la vue du flow ou du paywall est fermée depuis l'écran. :::note Sur iOS, également invoquée lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. ::: ```dart showLineNumbers title="Flutter" void flowViewDidDisappear(AdaptyUIFlowView view) { } ``` #### Sélection de produit \{#product-selection\} Si un produit est sélectionné pour l'achat (par un utilisateur ou par le système), cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ``` </Details> #### Achat démarré \{#started-purchase\} Si un utilisateur lance le processus d'achat, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' product.localizedTitle; // 'Premium Monthly' product.localizedDescription; // 'Premium subscription for 1 month' product.price.amount; // 9.99 (double) product.price.currencyCode; // 'USD' product.price.localizedString; // '$9.99' } ``` </Details> #### Achat terminé \{#finished-purchase\} Cette méthode est **obligatoire**. Elle est invoquée lorsqu'un achat réussit, que l'utilisateur annule son achat, ou que l'achat semble en attente : ```dart showLineNumbers title="Flutter" void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // successful purchase break; case AdaptyPurchaseResultPending(): // purchase is pending break; case AdaptyPurchaseResultUserCancelled(): // user cancelled the purchase break; default: break; } } ``` <Details> <summary>Exemples d'événements (cliquer pour développer)</summary> ```dart void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) break; case AdaptyPurchaseResultPending(): // no additional data break; case AdaptyPurchaseResultUserCancelled(): // no additional data break; } } ``` </Details> :::info Contrairement à la v3, cette méthode n'a pas de comportement par défaut — la vue n'est plus fermée automatiquement après un achat réussi. Décidez vous-même de la suite : continuez le flow ou appelez `view.dismiss()`. Consultez [Répondre aux actions de bouton](flutter-handle-paywall-actions) pour plus de détails sur la fermeture d'un écran. ::: #### Navigation de paiement web terminée \{#finished-web-payment-navigation\} Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées : ```dart showLineNumbers title="Flutter" void flowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view, AdaptyPaywallProduct? product, AdaptyError? error) { } ``` **Paramètres :** | Paramètre | Description | |:------------|:------------------------------------------------------------------------------------------------------------------| | **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. | | **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. | #### Achat échoué \{#failed-purchase\} Cette méthode est invoquée lorsqu'un achat échoue (par exemple, en raison de problèmes de paiement ou d'erreurs réseau). Elle ne se déclenche **pas** pour les annulations initiées par l'utilisateur ou les transactions en attente — celles-ci sont gérées par `flowViewDidFinishPurchase` : ```dart showLineNumbers title="Flutter" void flowViewDidFailPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { } ``` #### Restauration démarrée \{#started-restore\} Si un utilisateur lance le processus de restauration, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void flowViewDidStartRestore(AdaptyUIFlowView view) { } ``` #### Restauration réussie \{#successful-restore\} Cette méthode est **obligatoire**. Si la restauration d'un achat réussit, elle sera invoquée : ```dart showLineNumbers title="Flutter" void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) profile.subscriptions['premium_monthly']?.isActive; // true profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez le sujet [Statut d'abonnement](flutter-listen-subscription-changes) pour savoir comment le vérifier et le sujet [Répondre aux actions de bouton](flutter-handle-paywall-actions) pour savoir comment fermer un écran. #### Restauration échouée \{#failed-restore\} Si la restauration d'un achat échoue, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void flowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) { } ``` ### Récupération des données et rendu \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne passez pas le tableau de produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode : ```dart showLineNumbers title="Flutter" void flowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) { } ``` #### Erreurs de vue \{#view-errors\} Cette méthode est **obligatoire**. Elle remplace la méthode `paywallViewDidFailRendering` de la v3 : les erreurs qui surviennent pendant le rendu de l'interface, ainsi que les autres erreurs de vue, sont signalées en l'appelant. Une fois que vous l'implémentez, la fermeture est de votre responsabilité — nous recommandons de fermer la vue en cas de telles erreurs, ce qui correspond également au comportement par défaut intégré du SDK lorsqu'aucun observateur n'est défini : ```dart showLineNumbers title="Flutter" void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { // log the error and dismiss the broken view view.dismiss(); } ``` Dans une situation normale, les erreurs de rendu ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le signaler. ### Événements analytiques \{#analytics-events\} La méthode optionnelle `flowViewDidReceiveAnalyticEvent` est réservée aux événements analytiques personnalisés 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. ### Gérer les achats en mode observateur \{#handle-purchases-in-observer-mode\} Si vous avez activé le SDK en [mode observateur](implement-observer-mode-flutter) et présentez un flow ou un paywall 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 votre `AdaptyUIObserverModeResolver` à la place. Consultez [Présenter des flows en mode observateur](flutter-present-flows-in-observer-mode) pour la configuration complète. ### Gérer les requêtes système \{#handle-system-requests\} Le `AdaptyUISystemRequestsHandler` (enregistré via `AdaptyUI().setSystemRequestsHandler(...)`) est réservé aux requêtes système d'un flow : les invites de permission du système d'exploitation (comme les notifications push ou l'accès à la caméra) et les demandes d'avis App Store. Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler. Si vous en enregistrez un, notez que `handlePermission` est la méthode obligatoire de la classe — demandez la permission avec votre propre code, puis retournez `AdaptyUIPermissionResult.granted()` ou `AdaptyUIPermissionResult.denied()` ; `handleAppReviewRequest` est optionnel. </SDKv4> <SDKv3> :::important 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 bouton](flutter-handle-paywall-actions) pour plus de détails. ::: Les paywalls configurés avec le [Paywall Builder](adapty-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 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 sur le paywall. Découvrez comment répondre à ces événements ci-dessous. :::warning Ce guide est uniquement pour les **paywalls du nouveau Paywall Builder** qui nécessitent Adapty SDK v3.0 ou une version ultérieure. ::: Pour contrôler ou surveiller les processus qui se déroulent sur l'écran du paywall dans votre application mobile, implémentez les méthodes `AdaptyUIPaywallsEventsObserver` et définissez l'observateur avant d'afficher un écran : ```dart showLineNumbers title="Flutter" AdaptyUI().setPaywallsEventsObserver(this); ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Les exemples d'événements ci-dessous montrent les propriétés disponibles sur chaque objet, avec des valeurs illustratives dans les commentaires. ### Événements générés par l'utilisateur \{#user-generated-events\} #### Paywall apparu \{#paywall-appeared\} Cette méthode est invoquée lorsque la vue du paywall est affichée à l'écran. :::note Sur iOS, également invoquée lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré. ::: ```dart showLineNumbers title="Flutter" void paywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### Paywall disparu \{#paywall-disappeared\} Cette méthode est invoquée lorsque la vue du paywall est fermée depuis l'écran. :::note Sur iOS, également invoquée lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. ::: ```dart showLineNumbers title="Flutter" void paywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### Sélection de produit \{#product-selection\} Si un produit est sélectionné pour l'achat (par un utilisateur ou par le système), cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ``` </Details> #### Achat démarré \{#started-purchase\} Si un utilisateur lance le processus d'achat, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' product.localizedTitle; // 'Premium Monthly' product.localizedDescription; // 'Premium subscription for 1 month' product.price.amount; // 9.99 (double) product.price.currencyCode; // 'USD' product.price.localizedString; // '$9.99' } ``` </Details> #### Achat terminé \{#finished-purchase\} Cette méthode est invoquée lorsqu'un achat réussit, que l'utilisateur annule son achat, ou que l'achat semble en attente : ```dart showLineNumbers title="Flutter" void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // successful purchase break; case AdaptyPurchaseResultPending(): // purchase is pending break; case AdaptyPurchaseResultUserCancelled(): // user cancelled the purchase break; default: break; } } ``` <Details> <summary>Exemples d'événements (cliquer pour développer)</summary> ```dart void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) break; case AdaptyPurchaseResultPending(): // no additional data break; case AdaptyPurchaseResultUserCancelled(): // no additional data break; } } ``` </Details> Nous recommandons de fermer l'écran dans ce cas. Consultez [Répondre aux actions de bouton](flutter-handle-paywall-actions) pour plus de détails sur la fermeture d'un écran de paywall. #### Navigation de paiement web terminée \{#finished-web-payment-navigation\} Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées : ```dart showLineNumbers title="Flutter" void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct? product, AdaptyError? error) { } ``` **Paramètres :** | Paramètre | Description | |:------------|:------------------------------------------------------------------------------------------------------------------| | **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. | | **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. | <Details> <summary>Exemples d'événements (cliquer pour développer)</summary> ```dart void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct? product, AdaptyError? error) { // product — AdaptyPaywallProduct?: product?.vendorProductId; // 'premium_monthly' if (error == null) { // navigation succeeded } else { // error — AdaptyError: error.code; // AdaptyErrorCode.networkFailed (2005) error.message; // 'Network request failed' error.detail; // platform-specific underlying error, or null } } ``` </Details> #### Achat échoué \{#failed-purchase\} Cette méthode est invoquée lorsqu'un achat échoue (par exemple, en raison de problèmes de paiement ou d'erreurs réseau). Elle ne se déclenche **pas** pour les annulations initiées par l'utilisateur ou les transactions en attente — celles-ci sont gérées par `paywallViewDidFinishPurchase` : ```dart showLineNumbers title="Flutter" void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' // error — AdaptyError: error.code; // AdaptyErrorCode.productPurchaseFailed (1006) error.message; // 'Product purchase failed.' error.detail; // platform-specific underlying error, or null } ``` </Details> #### Restauration démarrée \{#started-restore\} Si un utilisateur lance le processus de restauration, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void paywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) profile.subscriptions['premium_monthly']?.isActive; // true profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez le sujet [Statut d'abonnement](flutter-listen-subscription-changes) pour savoir comment le vérifier et le sujet [Répondre aux actions de bouton](flutter-handle-paywall-actions) pour savoir comment fermer un écran de paywall. #### Restauration échouée \{#failed-restore\} Si la restauration d'un achat échoue, cette méthode sera invoquée : ```dart showLineNumbers title="Flutter" void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.receiveRestoredTransactionsFailed (1011) error.message; // 'Error occurred in the process of restoring purchases.' error.detail; // platform-specific underlying error, or null } ``` </Details> ### Récupération des données et rendu \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne passez pas le tableau de produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode : ```dart showLineNumbers title="Flutter" void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.productRequestFailed (1002) error.message; // 'Unable to fetch available In-App Purchase products at the moment.' error.detail; // platform-specific underlying error, or null } ``` </Details> #### Erreurs de rendu \{#rendering-errors\} Si une erreur survient pendant le rendu de l'interface, elle sera signalée en appelant cette méthode. Par défaut (depuis la v3.15.2), le paywall est automatiquement fermé lorsqu'une erreur de rendu se produit, mais vous pouvez modifier ce comportement si nécessaire. ```dart showLineNumbers title="Flutter" void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { // Default behavior: view.dismiss() // Override with custom logic if needed, for example: // - Log the error // - Show an error message to the user } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```dart void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.jsException (4105) error.message; // 'An exception was thrown from JS during AdaptyUI flow execution.' error.detail; // platform-specific underlying error, or null // Default behavior: view.dismiss() } ``` </Details> Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le signaler. </SDKv3> --- # File: flutter-use-fallback-paywalls --- --- title: "Flutter - Utiliser les paywalls de secours" description: "Gérer les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles" --- :::warning Les paywalls de secours sont pris en charge par le SDK Flutter v2.11 et versions ultérieures. ::: To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} 1. Ajoutez les fichiers de configuration de secours dans le répertoire `assets` de l'application, à la racine du projet. 2. Appelez la méthode `.setFallback` **avant** de récupérer le paywall ou l'onboarding cible. ```dart showLineNumbers title="Flutter" final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; try { await Adapty().setFallback(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres : | Paramètre | Description | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **assetId** | Chemin vers le fichier de configuration de secours. | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: flutter-localizations-and-locale-codes --- --- title: "Utiliser les localisations et les codes de langue dans le SDK Flutter" description: "Gérez les localisations et les codes de langue de votre application pour atteindre un public mondial." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu lorsqu'Adapty choisit la localisation pour un flow, et lorsque vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. C'est pourquoi Adapty s'appuie sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prévoir quelle localisation un utilisateur reçoit. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-étiquettes en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty cherche la localisation correspondant à la langue d'un utilisateur, voici ce qui se passe : 1. La chaîne de langue est convertie en minuscules et tous les traits de soulignement (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de langue correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est trouvée non plus, Adapty retourne le contenu dans la langue par défaut du flow Cette approche permet à `'pt_BR'`, `pt-BR` et `pt-br` de tous pointer vers la même localisation. ## Implémenter les localisations \{#implementing-localizations\} Avec le SDK v4, vous n'avez pas besoin de passer un code de langue lors de la récupération d'un flow — `getFlow` retourne le flow avec toutes ses localisations, et Adapty en applique une au moment de la construction de la vue du flow. L'argument `locale` de `getFlow` et `getFlowForDefaultAudience` n'a aucun effet sur les flows ; il est déprécié et génère un avertissement dans les logs. - **Flows construits dans le builder** : le SDK ne lit pas la locale de l'appareil, donc résolvez-la dans votre app et passez-la comme argument `locale` de `createFlowView` ou `AdaptyUIFlowPlatformView`. L'argument est optionnel — omettez-le et le flow s'affichera en `en`, ou dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow n'a pas de localisation `en`. Si vous demandez une localisation que le flow ne possède pas, la vue se rabat sur la locale par défaut du flow sans erreur, et les chaînes manquantes dans la localisation choisie proviennent de la locale par défaut. `AdaptyUIFlowView.locale` indique la localisation avec laquelle la vue a été construite. Cette fonctionnalité nécessite Flutter SDK 4.0.3 avec les versions natives iOS 4.0.2 et Android 4.0.1, et renvoie `null` avec des SDK natifs plus anciens. - **Paywalls personnalisés (Remote Config)** : `getFlow` retourne toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée contient un code `locale` et le contenu de la configuration (chaîne `data` ou le `dictionary` parsé). Sélectionnez l'entrée qui correspond à l'utilisateur, avec votre propre fallback : ```dart showLineNumbers final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final config = flow.remoteConfigs.firstWhereOrNull((c) => c.locale == 'en') ?? flow.remoteConfig; // the first remote config, if present // read your values from config?.dictionary ``` Les règles de correspondance des codes de locale décrites ci-dessus expliquent comment Adapty normalise les codes `locale` stockés sur chaque Remote Config. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de locale entrent en jeu dans plusieurs scénarios — par exemple, lorsque vous essayez de récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de locale étant complexes et pouvant varier d'une plateforme à l'autre, nous nous appuyons sur un standard interne pour toutes les plateformes que nous supportons. Cependant, justement parce que ces codes sont complexes, il est vraiment important que vous compreniez ce que vous envoyez exactement à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin de toujours recevoir ce que vous attendez. ## Norme des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Quand Adapty reçoit un appel du SDK côté client avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de locale reçue est convertie en minuscules et tous les tirets de soulignement (`_`) sont remplacés par des tirets (`-`) 2. On cherche ensuite la localisation dont le code correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si toujours aucune correspondance n'est trouvée, on retourne le contenu dans la locale par défaut du paywall De cette façon, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Implémentation des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous interrogez sur les localisations, vous utilisez probablement déjà des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de localisation. Extrayez ensuite la valeur de cette clé lors de l'appel à notre SDK, comme ceci : ```dart showLineNumbers // 1. Modify your app_en.arb, app_es.arb, app_pt_br.arb files /* app_en.arb */ "adapty_paywalls_locale": "en", /* app_es.arb */ "adapty_paywalls_locale": "es", /* app_pt_br.arb */ "adapty_paywalls_locale": "pt-br", // 2. Extract and use the locale code final locale = AppLocalizations.of(context)!.adapty_paywalls_locale; // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` De cette façon, vous gardez un contrôle total sur la localisation récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : une autre approche \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement de codes de langue pour chaque localisation. Cela revient à extraire un code de langue depuis d'autres objets fournis par votre plateforme, comme ceci : ```dart showLineNumbers final locale = Localizations.localeOf(context).languageCode; // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` Notez que nous déconseillons cette approche pour plusieurs raisons : 1. Sur iOS, les langues préférées et la locale actuelle ne sont pas identiques. Si vous souhaitez que la localisation soit correctement sélectionnée, vous devrez soit vous reposer sur la logique d'Apple, qui fonctionne nativement si vous utilisez l'approche recommandée avec des fichiers de chaînes localisées, soit la recréer vous-même. 2. Il est difficile de prédire ce que le serveur d'Adapty recevra exactement. Par exemple, sur iOS, il est possible d'obtenir une locale comme `ar_OM@numbers='latn'` sur un appareil et de l'envoyer à notre serveur. Pour cet appel, vous obtiendrez non pas la localisation `ar-om` que vous recherchiez, mais plutôt `ar`, ce qui est probablement inattendu. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: flutter-web-paywall --- --- title: "Implémenter des paywalls web dans le SDK Flutter" description: "Configurez un paywall web pour accepter des paiements sans les frais et audits de l'App Store." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé la version 3.6.1 ou ultérieure du SDK Adapty. ::: Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `.openWebPaywall` : 1. Génère une URL unique permettant à Adapty d'associer un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `.getProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. ```dart showLineNumbers title="Flutter" try { await Adapty().openWebPaywall(product: <YOUR_PRODUCT>); // The web paywall will be opened } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle other errors } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall(product)` qui génère des URLs à partir du paywall et y ajoute également les données du produit. 2. `openWebPaywall(paywall)` qui génère des URLs à partir du paywall sans y ajouter les données du produit. Utilisez-la lorsque vos produits dans le paywall Adapty diffèrent de ceux du paywall web. Dans le SDK v4, le paramètre `paywall` prend un `AdaptyFlowPaywall` — une variante de paywall du flow récupéré. Vérifiez que `flow.paywalls` n'est pas vide avant d'y accéder par index, par exemple `flow.paywalls[0]`. ::: #### Gérer les erreurs \{#handle-errors\} | Erreur | Description | Action recommandée | |-----------------------------------------|---------------------------------------------------------------|---------------------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | Le paywall n'a pas d'URL d'achat web configurée | Vérifiez que le paywall a bien été configuré dans l'Adapty Dashboard | | AdaptyError.productWithoutPurchaseUrl | Le produit n'a pas d'URL d'achat web | Vérifiez la configuration du produit dans l'Adapty Dashboard | | AdaptyError.failedOpeningWebPaywallUrl | Impossible d'ouvrir l'URL dans le navigateur | Vérifiez les paramètres de l'appareil ou proposez une autre méthode d'achat | | AdaptyError.failedDecodingWebPaywallUrl | Impossible d'encoder correctement les paramètres dans l'URL | Vérifiez que les paramètres d'URL sont valides et correctement formatés | ## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} :::important L'ouverture des paywalls web dans un navigateur intégré est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les paywalls web s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. Cela affiche la page d'achat web directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application. Pour activer cette option, définissez le paramètre `in` sur `.inAppBrowser` : ```dart showLineNumbers try { await Adapty().openWebPaywall( product: <YOUR_PRODUCT>, openIn: AdaptyWebPresentation.inAppBrowser, ); // The web paywall will be opened in the in-app browser } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle other errors } ``` --- # File: flutter-troubleshoot-paywall-builder --- --- title: "Résoudre les problèmes du Paywall Builder dans le SDK Flutter" description: "Résoudre les problèmes du Paywall Builder dans le SDK Flutter" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus avec le Paywall Builder d'Adapty dans le SDK Flutter. ## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La méthode `createPaywallView` ne parvient pas à récupérer la configuration du paywall. **Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le nombre de vues du paywall affiche le double de la valeur attendue. **Cause** : Vous appelez peut-être `logShowFlow` (SDK Flutter v4+) / `logShowPaywall` dans votre code, ce qui duplique le compteur de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls créés avec ces outils, les statistiques sont suivies automatiquement — il n'est donc pas nécessaire d'appeler cette méthode. **Solution** : Vérifiez que vous n'appelez pas `logShowFlow` (SDK Flutter v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder qui ne sont pas couverts ci-dessus. **Solution** : Mettez à jour le SDK vers la dernière version à l'aide des [guides de migration](flutter-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: flutter-present-flows-in-observer-mode --- --- title: "Présenter des flows en mode Observer dans le SDK Flutter" description: "Présentez des flows et des paywalls Paywall Builder en mode Observer dans votre application Flutter tout en gérant les achats avec votre propre code." --- Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas besoin de vous soucier du rendu dans votre code d'application mobile pour l'afficher à l'utilisateur. Ce type de flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez la rubrique [Afficher des flows & paywalls](flutter-present-paywalls). ::: :::info Cette fonctionnalité nécessite Adapty Flutter SDK 4.0 ou version ultérieure — elle n'était auparavant disponible que dans les SDK natifs iOS et Android. Consultez le [guide de migration](migration-to-flutter-sdk-v4) pour effectuer la mise à niveau. ::: <details> <summary>Avant de commencer à présenter des flows (cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios) et [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez le [guide d'installation du SDK Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](flutter-get-pb-paywalls) dans votre code d'application mobile. </details> En mode Observer, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou paywall rendu par Adapty, le SDK appelle votre `AdaptyUIObserverModeResolver` à la place — effectuez l'achat ou la restauration avec votre propre code à cet endroit. 1. Implémentez l'`AdaptyUIObserverModeResolver` : ```dart showLineNumbers title="Flutter" class MyObserverModeResolver extends AdaptyUIObserverModeResolver { @override void observerModeDidInitiatePurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, void Function() onStartPurchase, void Function() onFinishPurchase, ) { onStartPurchase(); // the view shows its loading indicator // make the purchase with your own code, then: onFinishPurchase(); // the view hides the loading indicator } @override void observerModeDidInitiateRestore( AdaptyUIFlowView view, void Function() onStartRestore, void Function() onFinishRestore, ) { onStartRestore(); // restore purchases with your own code, then: onFinishRestore(); } } ``` La méthode `observerModeDidInitiatePurchase` vous informe que l'utilisateur a initié un achat, et `observerModeDidInitiateRestore` — que l'utilisateur a initié une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse. N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. Cela est nécessaire pour le bon fonctionnement du flow, notamment pour afficher le chargement, entre autres : | Callback | Description | | :----------------- | :------------------------------------------------------------------------------------------- | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a commencé. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a commencé. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | 2. Enregistrez le resolver avant de présenter tout écran : ```dart showLineNumbers title="Flutter" AdaptyUI().setObserverModeResolver(MyObserverModeResolver()); ``` 3. Créez et présentez la vue du flow comme d'habitude : [récupérez le flow et créez sa vue](flutter-get-pb-paywalls), puis [présentez-la](flutter-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — une fois le resolver enregistré, chaque flow ou paywall rendu par Adapty achemine les achats et les restaurations par son intermédiaire. :::warning N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-flutter). Sinon, Adapty ne reconnaîtra pas la transaction et ne pourra pas déterminer le paywall source de l'achat. ::: --- # File: flutter-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement dans le SDK Flutter" description: "Apprenez à implémenter les paywalls manuellement dans votre application Flutter avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty via la méthode `makePurchase`. De cette façon, nous gérons tous les scénarios utilisateur et vous n'avez qu'à traiter les résultats des achats. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['flutter-quickstart-manual', 'fetch-paywalls-and-products-flutter', 'present-remote-config-paywalls-flutter', 'flutter-making-purchases', 'flutter-restore-purchase', 'flutter-troubleshoot-purchases']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, mais souhaitez tout de même bénéficier des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode-flutter', 'report-transactions-observer-mode-flutter', 'flutter-troubleshoot-purchases']} /> --- # File: flutter-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec Flutter SDK" description: "Intégrez le SDK Adapty dans vos paywalls Flutter personnalisés pour activer les achats intégrés." --- Ce guide décrit comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les précédents. Ce guide utilise les APIs du SDK Adapty Flutter v4 — si vous utilisez la v3, consultez le [guide de migration](migration-to-flutter-sdk-v4) pour les noms de méthodes correspondants. :::important **Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la méthode la plus simple pour activer les achats, utilisez le [Adapty Paywall Builder](flutter-quickstart-paywalls). Avec le Paywall Builder, vous créez des paywalls dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différents designs sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. Dans le SDK v4, les variantes de paywall pour un placement sont portées par un objet **flow** — vous récupérez un flow et interrogez ses produits. - [**Placements**](placements) – où et quand vous affichez des paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez des paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de différents paywalls à différents utilisateurs. Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En résumé, ce sont juste votre façon de gérer les produits que vous vendez dans votre application. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère les utilisateurs anonymes et identifiés différemment. Lisez le [guide de démarrage rapide sur l'identification](flutter-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs. ## Étape 1. Récupérer les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau de produits pour ce flow en utilisant la méthode `getPaywallProducts`. ```dart showLineNumbers Future<void> loadPaywall() async { try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final products = await Adapty().getPaywallProducts(flow: flow); // Use products to build your custom paywall UI } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le processus d'achat et retournera le profil mis à jour. ```dart showLineNumbers Future<void> purchaseProduct(AdaptyPaywallProduct product) async { try { final purchaseResult = await Adapty().makePurchase(product: product); switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // Purchase successful, profile updated break; case AdaptyPurchaseResultUserCancelled(): // User canceled the purchase break; case AdaptyPurchaseResultPending(): // Purchase is pending (e.g., user will pay offline with cash) break; } } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Les stores d'applications exigent que toutes les applications avec des abonnements fournissent un moyen permettant aux utilisateurs de restaurer leurs achats. Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera leur historique d'achats avec Adapty et retournera le profil mis à jour. ```dart showLineNumbers Future<void> restorePurchases() async { try { final profile = await Adapty().restorePurchases(); // Restore successful, profile updated } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## Étape 4. Vérifier le statut de l'abonnement \{#step-4-check-the-subscription-status\} Après un achat ou une restauration, vérifiez le [niveau d'accès](access-level) de l'utilisateur pour décider d'afficher ou non le paywall ou de débloquer les fonctionnalités payantes. Les méthodes `makePurchase` et `restorePurchases` retournent déjà le profil mis à jour ; chaque fois que vous avez besoin du statut actuel ailleurs dans l'application, utilisez la méthode `getProfile` : ```dart showLineNumbers Future<bool> hasPremiumAccess() async { try { final profile = await Adapty().getProfile(); return profile.accessLevels['premium']?.isActive ?? false; } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } return false; } ``` Pour plus de façons de vérifier et surveiller le statut de l'abonnement, notamment en écoutant les mises à jour en temps réel, consultez [Vérifier le statut de l'abonnement](flutter-check-subscription-status). ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans le [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez le [PurchasesObserver](https://github.com/adaptyteam/AdaptySDK-Flutter/blob/master/example/lib/purchase_observer.dart) dans notre exemple d'application, qui illustre la gestion des achats avec une gestion appropriée des erreurs, des observateurs d'interface utilisateur et une intégration complète du SDK. --- # File: fetch-paywalls-and-products-flutter --- --- title: "Récupérer les paywalls et produits pour les paywalls Remote Config dans le SDK Flutter" description: "Récupérez les paywalls et produits dans le SDK Adapty Flutter pour améliorer la monétisation des utilisateurs." --- <SDKv4> Avant de présenter les Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique porte sur les Remote Config et les paywalls personnalisés. Pour savoir comment récupérer les flows et les paywalls personnalisés avec le Paywall Builder, consultez [Obtenir les flows et paywalls](flutter-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-flutter) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits multiplateforme sont intégrés dans des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez récupérer un `AdaptyFlow` depuis l'un de vos [placements](placements) via la méthode `getFlow`. :::important **Ne codez pas les ID de produits en dur.** Le seul ID à coder en dur est l'ID du placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](flutter-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en interne.</p> | :::note Dans la v4, `getFlow` ne prend pas de paramètre `locale`. Pour les paywalls personnalisés, toutes les localisations disponibles sont retournées dans les Remote Configs du flow (`flow.remoteConfigs`) — choisissez celle qui correspond à la langue de l'appareil ou au paramètre de l'application. Voir [Localisations et codes de langue](flutter-localizations-and-locale-codes). ::: Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant les identifiants du flow (`instanceIdentity`, `variationId`), son nom, son placement, ses variantes de paywall (`paywalls`) et les Remote Configs éventuels (`remoteConfigs`). | ## Récupérer les produits \{#fetch-products\} Une fois que vous disposez du flow, vous pouvez interroger le tableau de produits qui lui correspond : ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(flow: flow); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) avec : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue de l'appareil. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. La localisation est basée sur les paramètres régionaux de l'appareil. Vous pouvez aussi accéder au prix sous forme numérique via `product.price.amount`. La valeur est fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. semaine, mois, année, etc.), utilisez `product.subscription?.localizedPeriod`. La localisation est basée sur les paramètres régionaux de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscription?.period`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (i.e. day, week, month, year ou unknown). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `AdaptyPeriodUnit.month` dans la propriété unit, et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : un enum avec les valeurs `AdaptyPaymentMode.freeTrial`, `AdaptyPaymentMode.payAsYouGo`, `AdaptyPaymentMode.payUpFront` et `AdaptyPaymentMode.unknown`. Les essais gratuits correspondent au type `AdaptyPaymentMode.freeTrial`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, cette valeur est `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon les paramètres régionaux de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Son fonctionnement est identique à ce qui est décrit dans la section précédente pour les offres.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon les paramètres régionaux de l'utilisateur. | ## Accélérer la récupération d'un flow avec le flow de l'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En règle générale, les flows sont récupérés quasi instantanément, donc vous n'avez pas à vous soucier de ce processus. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs ont une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience fluide, plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-flutter#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non rendus. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui vous prive de tout ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des flows, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](fetch-paywalls-and-products-flutter#fetch-flow-information). ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne le Remote Config et les paywalls personnalisés. Pour savoir comment récupérer des paywalls créés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](flutter-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer des paywalls et des produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-flutter) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **Ne codez pas les ID de produits en dur.** Le seul ID à coder en dur est l'ID du placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en"); // the requested paywall } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](flutter-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](flutter-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont retournés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en interne.</p> | N'utilisez pas d'identifiants de produits codés en dur ! Étant donné que les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent évoluer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, elle doit afficher les 3 sans nécessiter de modification du code. La seule chose à coder en dur est l'identifiant de placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le paywall, vous pouvez récupérer le tableau de produits qui lui correspond : ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(paywall: paywall); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) avec : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. Cette localisation est basée sur la locale de l'appareil. Vous pouvez également accéder au prix sous forme de nombre avec `product.price.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (par exemple semaine, mois, année, etc.), utilisez `product.subscription?.localizedPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscription?.period`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire day, week, month, year ou unknown). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `AdaptyPeriodUnit.month` dans la propriété unit, et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou un autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de réduction : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : un enum avec les valeurs `AdaptyPaymentMode.freeTrial`, `AdaptyPaymentMode.payAsYouGo`, `AdaptyPaymentMode.payUpFront` et `AdaptyPaymentMode.unknown`. Les essais gratuits seront de type `AdaptyPaymentMode.freeTrial`.<br/>• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, cette valeur sera `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Elle fonctionne de la même manière pour les offres que ce qui est décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la locale de l'utilisateur. | ## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls se chargent presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs ont une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme indiqué dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-flutter#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous pourrez rencontrer des difficultés. Il vous faudra soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez avec la méthode `getPaywall` décrite [ci-dessus](fetch-paywalls-and-products-flutter#fetch-paywall-information). ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 3.2.0 du SDK Flutter. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](flutter-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc fiable à utiliser durant la session pour éviter des requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p> | </SDKv3> --- # File: present-remote-config-paywalls-flutter --- --- title: "Afficher un paywall conçu via Remote Config dans le SDK Flutter" description: "Découvrez comment présenter des paywalls Remote Config dans le SDK Flutter d'Adapty pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et la façon dont votre paywall s'affiche. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant libre de présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer le Remote Config du paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} En v4, le flow contient une liste `remoteConfigs` — un Remote Config par localisation configurée. Choisissez l'entrée qui correspond à la langue de l'utilisateur et extrayez les valeurs dont vous avez besoin. Consultez [Localisations et codes de langue](flutter-localizations-and-locale-codes) pour sélectionner la bonne localisation. ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // one entry per configured localization; fall back to the first one final config = flow.remoteConfigs.firstWhereOrNull((c) => c.locale == 'en') ?? flow.remoteConfig; final String? headerText = config?.dictionary?['header_text'] as String?; } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler pour composer une page attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils. :::warning N'oubliez pas d'enregistrer l'événement d'affichage du paywall comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](flutter-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](flutter-use-fallback-paywalls). Ce paywall s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Si les données d'achat sont collectées automatiquement, l'enregistrement des affichages de paywalls nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowFlow(flow: flow)` — cela sera reflété dans vos métriques de paywall dans les funnels et les tests A/B. :::important L'appel de `.logShowFlow(flow: flow)` n'est pas nécessaire si vous affichez des flows ou des paywalls créés dans le [builder](adapty-paywall-builder). ::: ```dart showLineNumbers try { await Adapty().logShowFlow(flow: flow); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:----------------------------------------------------------------------| | **flow** | requis | Un objet `AdaptyFlow`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et la façon dont votre paywall s'affiche. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant libre de présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer le Remote Config du paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir le Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs dont vous avez besoin. ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID"); final String? headerText = paywall.remoteConfig?.dictionary?['header_text'] as String?; } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler pour composer une page attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils. :::warning N'oubliez pas d'enregistrer l'événement d'affichage du paywall comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](flutter-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](flutter-use-fallback-paywalls). Ce paywall s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Si les données d'achat sont collectées automatiquement, l'enregistrement des affichages de paywalls nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowPaywall(paywall)` — cela sera reflété dans vos métriques de paywall dans les funnels et les tests A/B. :::important L'appel de `.logShowPaywall(paywall)` n'est pas nécessaire si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```dart showLineNumbers try { final result = await Adapty().logShowPaywall(paywall: paywall); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:----------------------------------------------------------------------| | **paywall** | requis | Un objet [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html). | </SDKv3> --- # File: flutter-making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK Flutter" description: "Guide pour gérer les achats intégrés et les abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour offrir aux utilisateurs l'accès à des contenus ou services premium. Cela dit, afficher ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour les personnaliser. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode distincte appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode sert de point d'entrée pour que les utilisateurs interagissent avec les paywalls et réalisent leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de sa publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs pourtant éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans cela, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](flutter-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: ```dart showLineNumbers try { final purchaseResult = await Adapty().makePurchase(product: product); switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): if (profile.accessLevels['premium']?.isActive ?? false) { // Grant access to the paid features } break; case AdaptyPurchaseResultPending(): break; case AdaptyPurchaseResultUserCancelled(): break; default: break; } } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Si la requête a abouti, la réponse contient cet objet. Un objet [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur dans l'application.</p><p>Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.</p> | :::warning **Remarque :** si vous utilisez encore la version StoreKit d'Apple inférieure à v2.0 et une version du SDK Adapty inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est désormais dépréciée par Apple. ::: ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur opte pour un nouvel abonnement plutôt que de renouveler l'abonnement en cours, le comportement dépend du store : - Pour l'App Store, l'abonnement est automatiquement mis à jour au sein du groupe d'abonnements. Si un utilisateur souscrit un abonnement d'un groupe alors qu'il possède déjà un abonnement d'un autre groupe, les deux abonnements seront actifs simultanément. - Pour Google Play, l'abonnement n'est pas automatiquement mis à jour. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer un abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire : ```dart showLineNumbers try { final subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( 'OLD_PRODUCT_ID', AdaptyAndroidSubscriptionUpdateReplacementMode.immediateWithTimeProration, ); final result = await Adapty().makePurchase( product: product, parameters: AdaptyPurchaseParameters( subscriptionUpdateParams: subscriptionUpdateParams, ), ); // successful cross-grade } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------------------------- | :------- |:--------------------------------------------------------------------------------------------------------| | **parameters** | requis | un objet `AdaptyPurchaseParameters` dont le champ `subscriptionUpdateParams` est défini sur un objet [`AdaptyAndroidSubscriptionUpdateParameters`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyAndroidSubscriptionUpdateParameters-class.html). | Vous pouvez en savoir plus sur les abonnements et les modes de remplacement dans la documentation Google Developer : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les montées de version d'abonnement. Les passages à une version inférieure ne sont pas pris en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation en cours. ## Utiliser des codes promo sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie de code de rachat dans votre application : ```dart showLineNumbers try { await Adapty().presentCodeRedemptionSheet(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` :::danger D'après nos observations, la feuille de rachat de codes promo peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, vous devez ouvrir une URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ### Gérer les forfaits prépayés (Android) \{#manage-prepaid-plans-android\} Si les utilisateurs de votre application peuvent acheter des [forfaits prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, souscrire un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour ces forfaits. ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withGoogleEnablePendingPrepaidPlans(true), ); ``` --- # File: flutter-restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec Flutter SDK" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats sur iOS et Android permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés, comme des abonnements ou des achats intégrés, sans être débités à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leurs achats sans repayer. :::note Dans les paywalls créés avec [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans aucun code supplémentaire de votre part. Si c'est votre cas, vous pouvez passer cette étape. ::: Pour restaurer un achat si vous n'utilisez pas le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.restorePurchases()` : ```dart showLineNumbers try { final profile = await Adapty().restorePurchases(); if (profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive ?? false) { // successful access restore } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres de la réponse : | Paramètre | Description | |---------|-----------| | **Profile** | <p>Un objet [`AdaptyProfile`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). Ce modèle contient les informations sur les niveaux d'accès, les abonnements et les achats uniques.</p><p>Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.</p> | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: implement-observer-mode-flutter --- --- title: "Implémenter le mode Observer dans le SDK Flutter" description: "Implémentez le mode Observer dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Flutter." --- Si vous disposez déjà de votre propre infrastructure d'achat et n'êtes pas prêt à basculer complètement vers Adapty, vous pouvez explorer le [mode Observer](observer-vs-full-mode). Dans sa forme de base, le mode Observer offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analytics. Si cela correspond à vos besoins, vous devez uniquement : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions d'installation pour [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk). 2. [Signaler les transactions](report-transactions-observer-mode-flutter) depuis votre infrastructure d'achat existante vers Adapty. ## Configuration du mode Observer \{#observer-mode-setup\} Activez le mode Observer si vous gérez vous-même les achats et le statut des abonnements, et que vous utilisez Adapty uniquement pour envoyer les événements d'abonnement et les données analytics. :::important En mode Observer, le SDK Adapty ne clôture aucune transaction — assurez-vous donc de les gérer vous-même. ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withObserverMode(true) // Enable observer mode ..withLogLevel(AdaptyLogLevel.verbose), ); ``` Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | observerMode | Valeur booléenne qui contrôle le [mode Observer](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observer \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observer. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls Remote Config](present-remote-config-paywalls-flutter). 3. [Associez les paywalls](report-transactions-observer-mode-flutter) aux transactions d'achat. :::tip Dans le SDK v4, vous pouvez également présenter des flows et des paywalls générés par Adapty en mode Observer : enregistrez un `AdaptyUIObserverModeResolver` pour effectuer l'achat ou la restauration avec votre propre code lorsqu'un utilisateur appuie sur le bouton correspondant. Voir [Présenter des flows en mode Observer](flutter-present-flows-in-observer-mode). ::: --- # File: report-transactions-observer-mode-flutter --- --- title: "Signaler les transactions en Observer Mode dans le SDK Flutter" description: "Signalez les transactions d'achat en Adapty Observer Mode pour les informations utilisateur et le suivi des revenus dans le SDK Flutter." --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+ (current)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant des analyses de paywall précises. ```dart showLineNumbers try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | requis | <ul><li> Pour iOS : identifiant de la transaction.</li><li> Pour Android : identifiant de type chaîne `purchase.getOrderId` de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html). | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store ou les restaurer. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` sur les deux plateformes pour signaler explicitement chaque transaction, et utilisez `restorePurchases` sur Android comme étape supplémentaire pour s'assurer qu'Adapty la reconnaît. :::warning **Ne sautez pas le signalement des transactions et la restauration des achats !** Si vous n'appelez pas ces méthodes, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant des analyses de paywall précises. ```dart showLineNumbers // every time when calling transaction.finish() if (Platform.isAndroid) { try { await Adapty().restorePurchases(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } } try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | requis | <ul><li> Pour iOS, StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</li><li> Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</li><li> Pour Android : identifiant de type chaîne (purchase.getOrderId de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html). | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **Signalement des transactions** - Les versions jusqu'à 3.1.x écoutent automatiquement les transactions dans l'App Store, le signalement manuel n'est donc pas nécessaire. - La version 3.2 ne prend pas en charge l'Observer Mode. </TabItem> <TabItem value="kotlin" label="Android and Android-based cross-platforms" default> **Signalement des transactions** Utilisez `restorePurchases` pour signaler une transaction à Adapty en Observer Mode, comme expliqué sur la page [Restaurer les achats dans le code mobile](flutter-restore-purchase). :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: </TabItem> </Tabs> **Association des paywalls aux transactions** Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous souhaitez utiliser des paywalls et/ou des tests A/B en Observer Mode, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de bien configurer cela avant de publier votre application, sinon cela entraînera des erreurs dans les analyses. ```dart final transactionId = transaction.transactionIdentifier final variationId = paywall.variationId try { await Adapty().setVariationId('transactionId', variationId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> </Tabs> --- # File: flutter-troubleshoot-purchases --- --- title: "Troubleshoot purchases in Flutter SDK" description: "Troubleshoot purchases in Flutter SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Flutter. ## makePurchase est appelé avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et le statut de l'abonnement ne sont pas mis à jour dans Adapty. **Cause** : Cela indique généralement une configuration incomplète du Google Play Store. **Solution** : Assurez-vous d'avoir suivi toutes les [étapes de configuration Google Play](initial-android). ## makePurchase est invoqué deux fois \{#makepurchase-is-invoked-twice\} **Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat. **Cause** : Cela se produit généralement lorsque le flux d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur. **Solution** : Assurez-vous d'avoir suivi toutes les [étapes de configuration Google Play](initial-android). ## AdaptyError.cantMakePayments en mode observateur \{#adaptyerrorcantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` lors de l'utilisation de `makePurchase` en mode observateur. **Cause** : En mode observateur, vous devez gérer les achats de votre côté et non utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observateur. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observateur. Consultez [Implémenter le mode observateur](implement-observer-mode-flutter) pour plus de détails. ## Erreur 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\} **Problème** : Vous recevez une erreur de facturation indisponible de la part du Google Play Store. **Cause** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil. **Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus à ce sujet dans la documentation Play Store : [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui n'est pas trouvé. **Cause** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de complétion d'achat liés au sandbox. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés aux achats qui ne sont pas couverts ci-dessus. **Solution** : Mettez à jour le SDK vers la dernière version en utilisant les [guides de migration](flutter-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: flutter-user --- --- title: "Utilisateurs & accès dans le SDK Flutter" description: "Découvrez comment gérer les utilisateurs et les niveaux d'accès dans votre application Flutter avec le SDK Adapty." --- <CustomDocCardList /> --- # File: flutter-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK Flutter" description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Si vous disposez de votre propre système d'authentification, vous devriez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyé à toutes les intégrations. ### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur au moment de la configuration, passez-le simplement en tant que paramètre `customerUserId` à la méthode `.activate()` : ```dart showLineNumbers title="Dart" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID) ); } catch (e) { // handle the error } ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous ne disposez pas d'un identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas les plus courants d'utilisation de cette méthode sont après l'inscription ou l'authentification, lorsque l'utilisateur passe d'un utilisateur anonyme à un utilisateur authentifié. ```dart showLineNumbers try { await Adapty().identify(customerUserId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres de la requête : - **Customer User ID** (obligatoire) : un identifiant utilisateur sous forme de chaîne de caractères. :::warning Resoumission de données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces situations, le SDK Adapty bascule automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, comme des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez les soumettre à nouveau pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```dart showLineNumbers try { await Adapty().logout(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` Vous pouvez ensuite reconnecter l'utilisateur en utilisant la méthode `.identify()`. ## Assigner un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de lier les transactions App Store à l'identité interne de vos utilisateurs. StoreKit associe ce token à chaque transaction, afin que votre backend puisse relier les données App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications App Store restent correctement associés. Vous pouvez définir le token de deux façons : lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `appAccountToken` en même temps que `customerUserId`. Si vous ne passez que le token, il ne sera pas inclus dans la transaction. ::: ```dart showLineNumbers // During configuration: try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID, iosAppAccountToken: "YOUR_APP_ACCOUNT_TOKEN") ); } catch (e) { // handle the error } // Or when identifying users try { await Adapty().identify(customerUserId, iosAppAccountToken: "YOUR_APP_ACCOUNT_TOKEN"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Définir des identifiants de compte masqués (Android) \{#set-obfuscated-account-ids-android\} Google Play exige des identifiants de compte masqués pour certains cas d'utilisation afin de renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants permettent à Google Play d'identifier les achats tout en gardant les informations des utilisateurs anonymes, ce qui est particulièrement important pour la prévention des fraudes et l'analyse. Vous devrez peut-être définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations spécifiques en matière de confidentialité. Les identifiants masqués permettent à Google Play de suivre les achats sans exposer les identifiants réels des utilisateurs. ```dart showLineNumbers // During configuration: try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID, androidObfuscatedAccountId: "OBFUSCATED_ACCOUNT_ID") ); } catch (e) { // handle the error } // Or when identifying users try { await Adapty().identify(customerUserId, androidObfuscatedAccountId: "OBFUSCATED_ACCOUNT_ID"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: flutter-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK Flutter" description: "Découvrez comment définir des attributs utilisateur dans Adapty pour une meilleure segmentation des audiences." --- Vous pouvez définir des attributs optionnels tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir des attributs utilisateur, appelez la méthode `.updateProfile()` : ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setEmail("email@email.com") ..setPhoneNumber("+18888888888") ..setFirstName('John') ..setLastName('Appleseed') ..setGender(AdaptyProfileGender.other) ..setBirthday(DateTime(1970, 1, 3)); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Notez que les attributs que vous avez précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés autorisées `<Key>` de `AdaptyProfileParameters.Builder` et les valeurs `<Value>` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum, valeurs autorisées : `female`, `male`, `other` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, et dans vos analyses pour identifier quelles métriques produit influencent le plus les revenus. ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..setCustomStringAttribute('value1', 'key1') ..setCustomDoubleAttribute(1.0, 'key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` : ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..removeCustomAttribute('key1') ..removeCustomAttribute('key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Il peut arriver que vous ayez besoin de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut ne pas être à jour, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment. Les attributs sur le serveur peuvent donc avoir été modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Maximum 30 attributs personnalisés par utilisateur - Les noms de clés peuvent comporter jusqu'à 30 caractères. Le nom de clé peut contenir des caractères alphanumériques ainsi que : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre flottant de 50 caractères maximum. --- # File: flutter-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK Flutter" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre app Flutter." --- Avec Adapty, suivre le statut d'abonnement est simple. Pas besoin d'insérer manuellement des identifiants de produits dans votre code. Il vous suffit de vérifier la présence d'un [niveau d'accès](access-level) actif pour confirmer l'abonnement d'un utilisateur. <details> <summary>Avant de vérifier le statut d'abonnement (cliquez pour développer)</summary> - Pour iOS, configurez les [notifications serveur App Store](enable-app-store-server-notifications) - Pour Android, configurez les [notifications en temps réel pour les développeurs (RTDN)](enable-real-time-developer-notifications-rtdn) </details> ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). Nous recommandons de récupérer le profil au démarrage de l'application, par exemple lorsque vous [identifiez un utilisateur](flutter-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque modification. Vous pouvez ainsi utiliser l'objet profil sans le redemander à chaque fois. Pour être notifié des mises à jour du profil, écoutez les changements comme décrit dans la section [Écouter les mises à jour de profil, y compris les niveaux d'accès](flutter-listen-subscription-changes) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Paramètres de réponse : | Paramètre | Description | | --------- | ------------------------------------------------------------ | | Profile | <p>Un objet [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'app.</p><p></p><p>La méthode `.getProfile` fournit le résultat le plus à jour car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont renvoyées. Il est également important de noter que le SDK Adapty met à jour régulièrement le cache `AdaptyProfile` afin de maintenir ces informations aussi à jour que possible.</p> | La méthode `.getProfile()` vous fournit le profil utilisateur depuis lequel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par app. Par exemple, si vous avez une application d'actualités et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer les niveaux d'accès "sports" et "science". Mais la plupart du temps, un seul niveau d'accès suffit ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès "premium" par défaut. Voici un exemple de vérification du niveau d'accès "premium" par défaut : ```dart showLineNumbers try { final profile = await Adapty().getProfile(); if (profile?.accessLevels['premium']?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir les messages d'Adapty, une configuration supplémentaire est nécessaire : ```dart showLineNumbers Adapty().didUpdateProfileStream.listen((profile) { // handle any changes to subscription state }); ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache implémenté dans le SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir les informations relatives au statut d'abonnement du profil. Il est cependant important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour détecter les mises à jour ou modifications liées au profil. En cas de changements, comme de nouvelles transactions ou d'autres mises à jour, ceux-ci sont envoyés dans le cache afin de le maintenir synchronisé avec le serveur. --- # File: flutter-deal-with-att --- --- title: "Gérer l'ATT dans le SDK Flutter" description: "Commencez avec Adapty sur Flutter pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et affiche une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setAppTrackingTransparencyStatus(AdaptyIOSAppTrackingTransparencyStatus.authorized); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de transmettre les données en temps voulu aux intégrations que vous avez configurées. ::: --- # File: kids-mode-flutter --- --- title: "Mode Enfants dans le SDK Flutter" description: "Activez facilement le Mode Enfants pour respecter les politiques d'Apple et de Google. Aucune donnée IDFA, GAID ni publicitaire collectée dans le SDK Flutter." --- Si votre application Flutter est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/) et de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour satisfaire ces politiques et passer les revues des stores. ## Qu'est-ce qui est requis ? \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte 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) - [adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `<Prénom.Nom>` sera inévitablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activer le Mode Enfants \{#enabling-kids-mode\} ### Mises à jour dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, accédez à [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Mises à jour dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, désactivez la collecte de l'IDFA de l'utilisateur (pour iOS), du GAID/AAID (pour Android) et de l'adresse IP. **Android : Mettez à jour votre configuration SDK** ```dart showLineNumbers title="Dart" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') // highlight-start ..withGoogleAdvertisingIdCollectionDisabled(true) // set to `true` ..withIpAddressCollectionDisabled(true), // set to `true` // highlight-end ); } catch (e) { // handle the error } ``` **iOS : Activez le Mode Enfants dans le SDK v4** :::important Dans le SDK v4, le SDK iOS natif est installé via Swift Package Manager, et le Mode Enfants est activé grâce au trait Swift Package `KidsMode`, qui supprime à la compilation tout le code lié à l'IDFA, AdSupport et AppTrackingTransparency. Cela nécessite **Xcode 26** ou une version ultérieure. ::: Dans le SDK v4, utilisez le package `adapty_flutter_kids` à la place de `adapty_flutter` dans votre `pubspec.yaml`. Il s'agit d'une variante Mode Enfants du plugin avec la même API publique et la même version — la seule différence est que son SDK iOS natif est compilé avec le trait `KidsMode` : ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter_kids: 4.0.0 ``` Votre code Dart reste identique — mettez simplement à jour l'import avec le nouveau nom de package : ```dart showLineNumbers title="Dart" ``` **iOS : Activez le Mode Enfants avec CocoaPods (SDK v3)** 1. Mettez à jour votre Podfile : - Si vous **n'avez pas** de section `post_install`, ajoutez l'intégralité du bloc de code ci-dessous. - Si vous **avez** déjà une section `post_install`, intégrez les lignes mises en évidence dans celle-ci. ```ruby showLineNumbers title="Podfile" def adapty_enable_kids_mode(installer) installer.pods_project.targets.each do |target| next unless target.name == 'Adapty' target.build_configurations.each do |config| flags = config.build_settings['OTHER_SWIFT_FLAGS'] || '$(inherited)' flags = flags.join(' ') if flags.is_a?(Array) config.build_settings['OTHER_SWIFT_FLAGS'] = "#{flags} -DADAPTY_KIDS_MODE" end target.frameworks_build_phase.files.dup.each do |bf| target.frameworks_build_phase.remove_build_file(bf) if bf.display_name.to_s.include?('AdSupport') end end installer.pods_project.save Dir.glob(File.join(installer.sandbox.root, 'Target Support Files', '**', '*.xcconfig')).each do |xc| File.write(xc, File.read(xc).gsub(/\s*-framework\s+"?AdSupport"?/, '')) end end post_install do |installer| # ... keep your existing post_install body (Flutter adds one automatically) ... adapty_enable_kids_mode(installer) # <-- enable Adapty Kids Mode end ``` 2. Appliquez les modifications en exécutant ```sh showLineNumbers title="Shell" pod install ``` --- # File: flutter-onboardings --- --- title: "Onboardings dans le SDK Flutter" description: "Apprenez à utiliser les onboardings dans votre application Flutter avec le SDK Adapty." --- <CustomDocCardList /> --- # File: flutter-get-onboardings --- --- title: "Récupérer les onboardings avec le SDK Flutter" description: "Apprenez à récupérer les onboardings dans Adapty pour Flutter." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](flutter-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une apparence native cohérente, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir les flows et paywalls](flutter-get-pb-paywalls) et [Afficher les flows et paywalls](flutter-present-paywalls) pour démarrer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Flutter. La première étape consiste à récupérer l'onboarding associé au placement et sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Flutter Adapty](sdk-installation-flutter) version 3.8.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'ensemble de l'expérience — quel contenu apparaît, comment il est présenté et comment les interactions utilisateur (comme les réponses à des quiz ou les saisies de formulaires) sont traitées. Le conteneur suit également automatiquement les événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi des vues séparé. Pour de meilleures performances, récupérez la configuration de l'onboarding tôt afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher aux utilisateurs. Pour obtenir un onboarding, utilisez la méthode `getOnboarding` : ```dart showLineNumbers try { final onboarding = await Adapty().getOnboarding(placementId: "YOUR_PLACEMENT_ID"); } on AdaptyError catch (e) { //handle error } catch (e) { //handle error } ``` Ensuite, appelez la méthode `createOnboardingView` pour obtenir la vue que vous allez afficher. :::warning Le résultat de la méthode `createOnboardingView` ne peut être utilisé qu'une seule fois. Si vous avez besoin de l'utiliser à nouveau, appelez de nouveau la méthode `createOnboardingView`. L'appeler deux fois sans recréer peut entraîner l'erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```dart showLineNumbers try { final onboardingView = await Adapty().createOnboardingView(onboarding: onboarding); } on AdaptyError catch (e) { //handle error } catch (e) { //handle error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag est pour la langue, le second est pour la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant au cas où le CDN serait inaccessible. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | défaut : 5 sec | <p>Cette valeur limite le délai d'attente pour cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en coulisses.</p> | Paramètres de réponse : | Paramètre | Description | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyOnboarding-class.html) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. | ## Accélérer la récupération de l'onboarding avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ces situations, vous pourriez vouloir afficher un onboarding par défaut pour garantir une expérience utilisateur fluide plutôt que de n'afficher aucun onboarding. Pour y remédier, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Cependant, il est crucial de comprendre que l'approche recommandée reste de récupérer l'onboarding avec la méthode `getOnboarding`, comme décrit dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : Peut créer des problèmes lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions puissent s'afficher incorrectement. - **Pas de personnalisation** : Affiche uniquement le contenu pour l'audience « All Users », supprimant le ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si une récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'utilisation, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```dart showLineNumbers try { final onboarding = await Adapty().getOnboardingForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` Paramètres : | Paramètre | Présence | Description | |-----------------|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag est pour la langue, le second est pour la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant au cas où le CDN serait inaccessible. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | --- # File: flutter-present-onboardings --- --- title: "Afficher les onboardings dans Flutter SDK" description: "Découvrez comment présenter efficacement les onboardings pour générer plus de conversions." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](flutter-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — pour des animations plus fluides, un rendu natif cohérent, des temps de chargement réduits, et sans dépendance au runtime WebView. Consultez [Obtenir des flows et paywalls](flutter-get-pb-paywalls) et [Afficher des flows et paywalls](flutter-present-paywalls) pour démarrer. ::: Si vous avez personnalisé un onboarding à l'aide du builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application Flutter pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Avant de commencer, vérifiez que : 1. Vous avez installé le [SDK Flutter Adapty](sdk-installation-flutter) version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Le SDK Flutter Adapty propose deux façons d'afficher les onboardings : - **Écran autonome** - **Widget intégré** ## Afficher en écran autonome \{#present-as-standalone-screen\} Pour afficher un onboarding en écran autonome, utilisez la méthode `onboardingView.present()` sur l'`onboardingView` créé par la méthode `createOnboardingView`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher l'onboarding à nouveau, appelez `createOnboardingView` une nouvelle fois pour créer une nouvelle instance d'`onboardingView`. :::warning Réutiliser le même `onboardingView` sans le recréer peut provoquer une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```dart showLineNumbers title="Flutter" try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Fermer l'onboarding \{#dismiss-the-onboarding\} Pour fermer l'onboarding par programmation, utilisez la méthode `dismiss()` : ```dart showLineNumbers title="Flutter" try { await onboardingView.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.fullScreen` (par défaut) ou `AdaptyUIIOSPresentationStyle.pageSheet`. ```dart showLineNumbers try { await onboardingView.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## Intégrer dans la hiérarchie de widgets \{#embed-in-widget-hierarchy\} Pour intégrer un onboarding dans votre arbre de widgets existant, utilisez directement le widget `AdaptyUIOnboardingPlatformView` dans votre hiérarchie de widgets Flutter. ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, // The onboarding object you fetched onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` :::note Pour que la platform view Android fonctionne, assurez-vous que votre `MainActivity` étend `FlutterFragmentActivity` : ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: ## Chargement pendant l'onboarding \{#loader-during-onboarding\} Lors de l'affichage d'un onboarding, vous pouvez remarquer un bref écran de chargement entre votre splash screen et l'onboarding, le temps que la vue sous-jacente s'initialise. Vous pouvez gérer cela de différentes façons selon vos besoins. #### Contrôler le splash screen via onDidFinishLoading \{#control-splash-screen-using-ondidfinishloading\} :::note Cette approche est uniquement disponible lors de l'intégration de l'onboarding en tant que widget. Elle n'est pas disponible pour la présentation en écran autonome. ::: L'approche multiplateforme recommandée consiste à maintenir votre splash screen ou votre overlay personnalisé visible jusqu'à ce que l'onboarding soit entièrement chargé, puis à le masquer manuellement. Lorsque vous utilisez le widget intégré, superposez votre propre widget au-dessus de lui et masquez l'overlay lorsque `onDidFinishLoading` se déclenche : ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Hide your custom splash screen or overlay here }, // ... other callbacks ) ``` ### Personnaliser le loader natif \{#customize-native-loader\} :::important Cette approche est spécifique à chaque plateforme et nécessite la maintenance de code UI natif. Elle n'est pas recommandée sauf si vous maintenez déjà des couches natives distinctes dans votre application. ::: Si vous avez besoin de personnaliser le loader par défaut lui-même, vous pouvez le remplacer par des mises en page spécifiques à chaque plateforme. Cette approche nécessite des implémentations séparées pour Android et iOS : - **iOS** : Ajoutez `AdaptyOnboardingPlaceholderView.xib` à votre projet Xcode - **Android** : Créez `adapty_onboarding_placeholder_view.xml` dans `res/layout` et définissez-y un placeholder ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est disponible à partir du SDK Adapty v3.15.1. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web directement dans votre application, sans avoir à changer d'app. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `AdaptyWebPresentation.externalBrowser` : <Tabs> <TabItem value="standalone" label="Écran autonome" default> ```dart showLineNumbers title="Flutter" final onboardingView = await AdaptyUI().createOnboardingView( onboarding: onboarding, externalUrlsPresentation: AdaptyWebPresentation.externalBrowser, // default – AdaptyWebPresentation.inAppBrowser ); try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="embedded" label="Widget intégré"> ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, externalUrlsPresentation: AdaptyWebPresentation.externalBrowser, // default – AdaptyWebPresentation.inAppBrowser onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` </TabItem> </Tabs> ## Désactiver les marges de zone sécurisée (Android) \{#disable-safe-area-paddings-android\} Par défaut, sur les appareils Android, la vue d'onboarding applique automatiquement des marges de zone sécurisée pour éviter les éléments d'interface système tels que la barre d'état et la barre de navigation. Si vous souhaitez désactiver ce comportement et avoir un contrôle total sur la mise en page, vous pouvez le faire en ajoutant une ressource booléenne à votre application : 1. Rendez-vous dans `android/app/src/main/res/values`. Si le fichier `bools.xml` n'existe pas, créez-le. 2. Ajoutez la ressource suivante : ```xml <resources> <bool name="adapty_onboarding_enable_safe_area_paddings">false</bool> </resources> ``` Notez que ces modifications s'appliquent globalement à tous les onboardings de votre application. --- # File: flutter-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK Flutter" description: "Gérez les événements liés à l'onboarding dans Flutter avec Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de corrections ni d'améliorations. Utilisez les [flows](flutter-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance à l'exécution WebView. Consultez [Obtenir des flows et des paywalls](flutter-get-pb-paywalls) et [Afficher des flows et des paywalls](flutter-present-paywalls) pour démarrer. ::: Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. La façon de gérer ces événements dépend de l'approche de présentation utilisée : - **Présentation plein écran** : nécessite la mise en place d'un observateur d'événements global qui gère les événements pour toutes les vues d'onboarding - **Widget intégré** : gère les événements via des paramètres de rappel en ligne directement dans le widget Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Flutter Adapty](sdk-installation-flutter) 3.8.0 ou une version ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Événements de présentation plein écran \{#full-screen-presentation-events\} ### Configurer l'observateur d'événements \{#set-up-event-observer\} Pour gérer les événements des onboardings en plein écran, implémentez `AdaptyUIOnboardingsEventsObserver` et configurez-le avant la présentation : ```dart showLineNumbers title="Flutter" AdaptyUI().setOnboardingsEventsObserver(this); try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Gérer les événements \{#handle-events\} Implémentez ces méthodes dans votre observateur : ```dart showLineNumbers title="Flutter" void onboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, ) { // Onboarding finished loading } void onboardingViewDidFailWithError( AdaptyUIOnboardingView view, AdaptyError error, ) { // Handle loading errors } void onboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Handle close action view.dismiss(); } void onboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Dismiss onboarding before presenting paywall view.dismiss().then((_) { _openPaywall(actionId); }); } void onboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Handle custom actions } void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Handle user input updates } void onboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent event, ) { // Track analytics events } ``` ## Événements du widget intégré \{#embedded-widget-events\} Lorsque vous utilisez `AdaptyUIOnboardingPlatformView`, vous pouvez gérer les événements via des paramètres de rappel en ligne directement dans le widget. Notez que les événements seront envoyés à la fois aux rappels du widget et à l'observateur global (s'il est configuré), mais l'observateur global est optionnel : ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Onboarding finished loading }, onDidFailWithError: (error) { // Handle loading errors }, onCloseAction: (meta, actionId) { // Handle close action }, onPaywallAction: (meta, actionId) { _openPaywall(actionId); }, onCustomAction: (meta, actionId) { // Handle custom actions }, onStateUpdatedAction: (meta, elementId, params) { // Handle user input updates }, onAnalyticsEvent: (meta, event) { // Track analytics events }, ) ``` ## Types d'événements \{#event-types\} Les sections suivantes décrivent les différents types d'événements que vous pouvez gérer, quelle que soit l'approche de présentation utilisée. ### Gérer les actions personnalisées \{#handle-custom-actions\} Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un ID. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez ensuite utiliser cet ID dans votre code et le traiter comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé, comme **Login** ou **Allow notifications**, la méthode déléguée `onboardingController` sera déclenchée avec le cas `.custom(id:)` et le paramètre `actionId` correspond à l'**Action ID** du builder. Vous pouvez créer vos propres IDs, comme « allowNotifications ». ```dart // Full-screen presentation void onboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { switch (actionId) { case 'login': _login(); break; case 'allow_notifications': _allowNotifications(); break; } } // Embedded widget onCustomAction: (meta, actionId) { _handleCustomAction(actionId); } ``` <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Lorsqu'un onboarding finit de se charger, cet événement est déclenché : ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, ) { print('Onboarding loaded: ${meta.onboardingId}'); } // Embedded widget onDidFinishLoading: (meta) { print('Onboarding loaded: ${meta.onboardingId}'); } ``` <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton avec l'action **Close** assignée. <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Notez que vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { await view.dismiss(); } // Embedded widget onCloseAction: (meta, actionId) { Navigator.of(context).pop(); } ``` <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall si vous souhaitez l'afficher à l'intérieur de l'onboarding. Si vous voulez ouvrir un paywall après sa fermeture, il existe une méthode plus simple — gérez l'action de fermeture et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La façon la plus fluide de travailler avec les paywalls dans les onboardings est de définir l'ID d'action égal à l'ID du placement du paywall : Notez que, pour iOS, une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous présentez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding par programmation en arrière-plan. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue d'onboarding avant de présenter le paywall. ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Dismiss onboarding before presenting paywall view.dismiss().then((_) { _openPaywall(actionId); }); } Future<void> _openPaywall(String actionId) async { // Implement your paywall opening logic here } // Embedded widget onPaywallAction: (meta, actionId) { _openPaywall(actionId); } ``` <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### Suivi de la navigation \{#tracking-navigation\} Vous recevez un événement analytique lorsque différents événements liés à la navigation se produisent pendant le flow d'onboarding : ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent event, ) { trackEvent(event.type, meta.onboardingId); } // Embedded widget onAnalyticsEvent: (meta, event) { trackEvent(event.type, meta.onboardingId); } ``` L'objet `event` peut être de l'un des types suivants : |Type | Description | |------------|-------------| | `onboardingStarted` | Lorsque l'onboarding a été chargé | | `screenPresented` | Lorsqu'un écran est affiché | | `screenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque les utilisateurs effectuent une action pour quitter l'écran. | | `secondScreenPresented` | Lorsque le deuxième écran est affiché | | `userEmailCollected` | Déclenché lorsque l'e-mail de l'utilisateur est collecté via le champ de saisie | | `onboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, [attribuez l'ID `final` au dernier écran](design-onboarding). | | `unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `screensTotal` | Nombre total d'écrans dans le flow | <Details> <summary>Exemples d'événements (Cliquer pour développer)</summary> ```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 } } ``` </Details> --- # File: flutter-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK Flutter" description: "Enregistrez et utilisez les données des onboardings dans votre application Flutter avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne bénéficient plus de corrections ni d'améliorations. Utilisez plutôt les [flows](flutter-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui offre des animations plus fluides, un aspect natif cohérent, des temps de chargement réduits et aucune dépendance au moteur WebView. Consultez [Obtenir des flows et paywalls](flutter-get-pb-paywalls) et [Afficher des flows et paywalls](flutter-present-paywalls) pour commencer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```dart // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Process data } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Process data } ``` Consultez le format de l'action [ici](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyUIOnboardingPlatformView/onStateUpdatedAction.html). <Details> <summary>Formes des propriétés pour chaque type de params (cliquez pour développer)</summary> ```dart void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // elementId is a String: elementId; // 'preference_selector' // meta — AdaptyUIOnboardingMeta: meta.onboardingId; // 'onboarding_123' meta.screenClientId; // 'preferences_screen' meta.screenIndex; // 1 meta.screensTotal; // 3 // params is one of the AdaptyOnboardingsStateUpdatedParams subclasses: switch (params) { case AdaptyOnboardingsSelectParams(:final id, :final value, :final label): // a single selected option id; // 'option_1' value; // 'premium' label; // 'Premium Plan' break; case AdaptyOnboardingsMultiSelectParams(:final params): // a list of selected options, each an AdaptyOnboardingsSelectParams params; // [(id: 'interest_1', value: 'sports', label: 'Sports'), (id: 'interest_2', value: 'music', label: 'Music')] break; case AdaptyOnboardingsInputParams(:final input): switch (input) { case AdaptyOnboardingsTextInput(:final value): value; // 'John Doe' break; case AdaptyOnboardingsEmailInput(:final value): value; // 'user@example.com' break; case AdaptyOnboardingsNumberInput(:final value): value; // 25.0 (a double) break; } break; case AdaptyOnboardingsDatePickerParams(:final day, :final month, :final year): day; // 15 month; // 6 year; // 1990 break; } } ``` </Details> ## Cas d'usage \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](flutter-setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci : ```dart showLineNumbers // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Store user preferences or responses if (params is AdaptyOnboardingsInputParams) { final builder = AdaptyProfileParametersBuilder(); // Map elementId to appropriate profile field switch (elementId) { case 'name': if (params.input is AdaptyOnboardingsTextInput) { builder.setFirstName((params.input as AdaptyOnboardingsTextInput).value); } break; case 'email': if (params.input is AdaptyOnboardingsEmailInput) { builder.setEmail((params.input as AdaptyOnboardingsEmailInput).value); } break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Store user preferences or responses if (params is AdaptyOnboardingsInputParams) { final builder = AdaptyProfileParametersBuilder(); // Map elementId to appropriate profile field switch (elementId) { case 'name': if (params.input is AdaptyOnboardingsTextInput) { builder.setFirstName((params.input as AdaptyOnboardingsTextInput).value); } break; case 'email': if (params.input is AdaptyOnboardingsEmailInput) { builder.setEmail((params.input as AdaptyOnboardingsEmailInput).value); } break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } ``` ### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\} En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et attribuez des IDs significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](flutter-setting-user-attributes) pour les utilisateurs. ```dart showLineNumbers // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Handle quiz responses and set custom attributes if (params is AdaptyOnboardingsSelectParams) { final builder = AdaptyProfileParametersBuilder(); // Map quiz responses to custom attributes switch (elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.setCustomStringAttribute(params.value, 'experience'); break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Handle quiz responses and set custom attributes if (params is AdaptyOnboardingsSelectParams) { final builder = AdaptyProfileParametersBuilder(); // Map quiz responses to custom attributes switch (elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.setCustomStringAttribute(params.value, 'experience'); break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](flutter-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](flutter-handling-onboarding-events#opening-a-paywall). --- # File: flutter-best-practices --- --- title: "Bonnes pratiques avec le SDK Flutter" description: "Modèles de référence pour intégrer le SDK Adapty sur Flutter — ordre des appels, gestion des erreurs et autres règles prêtes pour la production." --- <CustomDocCardList /> --- # File: flutter-sdk-call-order --- --- title: "Ordre d'appel dans le SDK Flutter" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs #2002 intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre." --- `Adapty().activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant qu'il n'est pas résolu, le SDK n'a aucun état. Tout appel effectué avant ou en parallèle avec `activate()` échoue avec [`#2002 notActivated`](error-handling-on-flutter-react-native-unity#custom-network-codes). Si votre application authentifie des utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty().identify()` à ce moment-là. N'appelez pas de méthodes liées aux actions utilisateur tant que `identify` n'est pas résolu. Les appels qui entrent en concurrence avec lui échouent soit avec [`#3006 profileWasChanged`](error-handling-on-flutter-react-native-unity#custom-network-codes), soit s'appliquent au profil anonyme créé à l'activation. Dans ce cas, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks UID avant d'appeler `Adapty().activate`. Sinon, l'identifiant MMP est associé à un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre parcours dépend de deux éléments : à quel moment vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou analytics. - **Étapes 2 et 5** : Obligatoires pour toutes les applications. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou analytics (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie des utilisateurs et récupère l'identifiant utilisateur client après le lancement. Si vous disposez de l'identifiant utilisateur client au lancement de l'application, passez-le directement dans `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, donc l'étape 4 est inutile. | Étape | Appel | Quand | Notes | |-------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou analytics (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'application, en premier | Attendez le callback UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `Adapty().activate(configuration: ...)` avec `withCustomerUserId` défini sur la configuration | Lancement de l'application, après l'étape 1, si vous avez l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `Adapty().activate(configuration: ...)` sans `withCustomerUserId` | Lancement de l'application, après l'étape 1, si vous n'avez pas l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `Adapty().setIntegrationIdentifier(key: ..., value: ...)` pour chaque MMP | Après l'étape 2, avant tout appel lié aux actions utilisateur | Nécessaire pour que les identifiants MMP soient associés au bon profil. | | 4 | `await Adapty().identify(customerUserId)` | Après l'étape 3 (ou l'étape 2 si pas de MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Toujours utiliser `await`. Les appels simultanés pendant `identify` produisent `#3006 profileWasChanged`. | | 5 | `getPaywall` (`getFlow` dans le SDK v4), `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 si pas de MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne une perte d'accès premium pour les utilisateurs existants, un `appsflyer_id` manquant sur les profils, et des paywalls affichés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent via un paiement web (Stripe, Paddle) et installent ensuite l'application native, le premier `activate()` de l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flow d'authentification ou le référant d'installation), passez-le directement dans `activate()`. Sinon, l'achat web reste invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque paiement web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: flutter-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK Flutter" description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et stratégies de secours pour Flutter." --- Une récupération fiable de paywall sous Flutter fait trois choses : s'affiche rapidement, retourne le paywall ciblé par audience et bascule gracieusement lorsque le réseau est lent. Les règles ci-dessous couvrent le timing, la mise en cache et les stratégies de secours pour y parvenir. :::tip Ces règles supposent que `Adapty().activate()` et `Adapty().identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK Flutter](flutter-sdk-call-order). ::: Les conseils ci-dessous utilisent les noms de méthodes v3. Dans le SDK v4, `getPaywall` est renommé en `getFlow` et le type de politique de récupération en `AdaptyFlowFetchPolicy` — toutes les règles s'appliquent sans changement. ## Règles et pièges \{#rules-and-pitfalls\} | À faire | À éviter | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements en parallèle au démarrage. | Un pré-chargement en masse bloque le thread principal et provoque un écran noir pendant la rafale. | | Appelez `getPaywall` une fois que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `didUpdateProfileStream`. | Appeler `getPaywall` dans `main()` avant `runApp`. | L'attribution n'est pas encore arrivée. Le paywall se résout contre l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment `getPaywall`. | Sans délai d'expiration, les utilisateurs avec une mauvaise connectivité voient un écran vide jusqu'à ce que le réseau se rétablisse — ou ferment l'application. | Voir [Récupérer les paywalls et les produits](fetch-paywalls-and-products-flutter) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour une mauvaise connectivité \{#tune-for-poor-connectivity\} Pour les marchés avec une connectivité régulièrement médiocre (zones rurales, transports en commun, régions affectées par le routage) : - Définissez `fetchPolicy: AdaptyPaywallFetchPolicy.returnCacheDataElseLoad` sur chaque récupération sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le délai expire. - Ne conditionnez pas l'affichage du paywall à `getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: flutter-show-aa-targeted-paywall --- --- title: "Afficher un paywall ciblé AA au premier lancement dans Flutter SDK" description: "Attendez brièvement l'attribution Apple Ads avant d'afficher le paywall au premier lancement dans Flutter, avec repli sur l'audience par défaut en cas de délai dépassé. Utilise AdaptyProfile.appliedAttributionSources." --- L'attribution Apple Ads (AA) arrive de manière asynchrone après `Adapty().activate()`. Au premier lancement, elle n'est généralement pas encore disponible, donc si vous appelez `getPaywall` immédiatement, Adapty résout la requête par rapport à l'audience par défaut et les utilisateurs Apple Ads ratent votre paywall segmenté AA. Plutôt que d'afficher un paywall puis de le remplacer, attendez brièvement l'attribution AA avant d'afficher quoi que ce soit : affichez le paywall ciblé si l'attribution arrive dans un court délai, ou le paywall de l'audience par défaut si ce n'est pas le cas. `AdaptyProfile.appliedAttributionSources` vous indique quand l'attribution AA a été appliquée. ## Avant de commencer \{#before-you-start\} Vous avez besoin de : - Adapty Flutter SDK **3.17.0** ou version ultérieure. - Apple Ads configuré pour l'application dans Adapty. Voir [Apple Ads](apple-search-ads). ## Fonctionnement \{#how-it-works\} Après `Adapty().activate()`, le SDK demande l'attribution Apple Ads à Apple en arrière-plan et transmet le résultat au backend d'Adapty. Quand AA devient la source d'attribution active pour le profil, le SDK envoie un `AdaptyProfile` mis à jour à votre listener `didUpdateProfileStream`, avec `AdaptyAttributionSource.appleAds` dans sa liste `appliedAttributionSources`. Au premier lancement, deux cas sont à gérer : 1. **L'attribution arrive dans le délai imparti.** Appelez `getPaywall` — Adapty résout la requête par rapport à l'audience Apple Ads et retourne le paywall ciblé. 2. **Le délai expire en premier.** Affichez plutôt le paywall de l'audience par défaut, afin que les utilisateurs sans attribution Apple Ads n'attendent pas indéfiniment. `getPaywallForDefaultAudience` le retourne sans attendre la segmentation. `appliedAttributionSources` peut être vide. Cela signifie soit : - L'attribution Apple Ads n'a pas encore été traitée pour ce profil, ou - aucune attribution n'est arrivée du tout. Dans tous les cas, `getPaywallForDefaultAudience` peut être appelé en toute sécurité — il retourne le paywall de l'audience par défaut quel que soit l'état du profil. :::important L'attente ne s'applique qu'au premier lancement. Une fois l'attribution Apple Ads enregistrée, elle est stockée définitivement sur le profil. À chaque lancement suivant, le profil en cache contient déjà `AdaptyAttributionSource.appleAds` dans `appliedAttributionSources`, donc le chemin d'attribution se résout immédiatement et `getPaywall` retourne le paywall segmenté Apple Ads sans aucun délai. ::: ## Implémentation \{#implementation\} Au premier lancement, attendez `AdaptyAttributionSource.appleAds` et appliquez un délai strict — si l'attribution Apple Ads n'arrive jamais, ces utilisateurs doivent quand même voir un paywall. 1. **Activez le SDK.** Voir [Installer et configurer le Flutter SDK](sdk-installation-flutter). 2. **Abonnez-vous aux mises à jour du profil** avec `Adapty().didUpdateProfileStream.listen(…)`. Si vous n'avez pas encore configuré le listener, voir [Écouter les mises à jour d'abonnement](flutter-check-subscription-status#listen-to-subscription-updates). 3. **Surveillez `AdaptyAttributionSource.appleAds` dans `appliedAttributionSources`.** Quand il apparaît, chargez le paywall avec `getPaywall` — Adapty retourne la variante segmentée AA : ```dart final subscription = Adapty().didUpdateProfileStream.listen((profile) async { if (!profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) return; final paywall = await Adapty().getPaywall(placementId: placementId); // present the segmented paywall, then cancel the subscription and the timer }); ``` `didUpdateProfileStream` est un broadcast stream et ne rejoue pas les événements passés, donc vérifiez aussi le profil actuel une fois avec `getProfile()`. Lors des relances, l'attribution stockée est déjà appliquée et ne sera pas renvoyée. 4. **Démarrez un timer de 3 à 5 secondes en parallèle de l'abonnement.** Si le timer se déclenche avant que `AdaptyAttributionSource.appleAds` n'apparaisse, chargez plutôt le paywall de l'audience par défaut avec `getPaywallForDefaultAudience`. Affichez le premier paywall résolu et annulez l'autre chemin, afin que le paywall ne soit pas récupéré deux fois. Configurez un [paywall de secours](flutter-use-fallback-paywalls) pour le placement afin que l'utilisateur ne soit jamais bloqué en cas d'échec réseau. ## Exemple complet \{#complete-example\} L'implémentation ci-dessous met en compétition l'attribution et un délai, précharge le paywall de l'audience par défaut en parallèle, et retourne le paywall approprié. L'appelant attend une seule fonction — aucun listener ni indicateur d'état à gérer côté appelant : - Si l'attribution arrive dans le `timeout`, elle retourne le paywall segmenté via `getPaywall`. - Si le `timeout` expire en premier, elle retourne le paywall de l'audience par défaut préchargé via `getPaywallForDefaultAudience`. ```dart title="apple_ads_paywall.dart" /// Returns the Apple Ads-segmented paywall if attribution is applied within /// [timeout], otherwise the default-audience paywall. Call after Adapty().activate(). Future<AdaptyPaywall> getPaywallOrDefault({ required String placementId, required Duration timeout, }) { // Prefetch the default-audience paywall right away so the timeout path resolves // without an extra network round-trip. `getPaywallForDefaultAudience` skips the // wait for segmentation data. `..ignore()` keeps an unused prefetch from surfacing // as an unhandled error; the error still reaches the caller if this paywall wins. final defaultPaywall = Adapty().getPaywallForDefaultAudience(placementId: placementId)..ignore(); final completer = Completer<AdaptyPaywall>(); late final StreamSubscription<AdaptyProfile> subscription; late final Timer timer; void resolve(Future<AdaptyPaywall> paywall) { if (completer.isCompleted) return; timer.cancel(); subscription.cancel(); completer.complete(paywall); } void onProfile(AdaptyProfile profile) { if (profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) { resolve(Adapty().getPaywall(placementId: placementId)); } } // Attribution path: react to profile updates as attribution is applied. subscription = Adapty().didUpdateProfileStream.listen(onProfile); // The stream is a broadcast stream and doesn't replay, so check the current // profile too — on relaunches attribution is already stored and won't re-emit. Adapty().getProfile().then(onProfile).ignore(); // Timeout path: fall back to the prefetched default-audience paywall. timer = Timer(timeout, () => resolve(defaultPaywall)); return completer.future; } ``` Appelez depuis votre écran de démarrage, puis affichez le paywall une fois qu'il est résolu : ```dart try { final paywall = await getPaywallOrDefault( placementId: 'YOUR_PLACEMENT_ID', timeout: const Duration(seconds: 5), ); // present the paywall } on AdaptyError catch (adaptyError) { // handle the error or show a fallback paywall } catch (e) { // handle the error } ``` Ajustez `timeout` selon le temps que vous êtes prêt à faire attendre les utilisateurs avant qu'un paywall n'apparaisse. La plupart des utilisateurs n'ont pas d'attribution Apple Ads, donc ils attendent le délai complet — 3 à 5 secondes est un équilibre raisonnable. L'attribution qui arrive le fait généralement dans les quelques secondes suivant le lancement. Si votre application écoute déjà `didUpdateProfileStream` à d'autres fins (par exemple, [vérifier l'état de l'abonnement](flutter-check-subscription-status#listen-to-subscription-updates)), vous n'avez pas besoin de le modifier. `didUpdateProfileStream` est un broadcast stream, donc il prend en charge plusieurs listeners indépendants sans affecter les autres. --- # File: flutter-test --- --- title: "Tester et publier avec le SDK Flutter" description: "Apprenez à vérifier le statut des abonnements dans votre application Flutter avec Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application Flutter, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu sur iOS et Android. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox d'Apple et l'environnement de test de Google Play. ## Tester votre application \{#test-your-app\} Pour tester vos achats intégrés de manière complète, consultez nos guides de test par plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android). ## Préparer la publication \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [liste de contrôle pour la publication](release-checklist) pour vérifier que : - La connexion au store et les notifications serveur sont configurées - Les achats s'effectuent et sont bien remontés à Adapty - L'accès se déverrouille et se restaure correctement - Les exigences en matière de confidentialité et de révision sont respectées --- # File: flutter-reference --- --- title: "Référence pour le SDK Flutter" description: "Documentation de référence pour le SDK Flutter Adapty." --- Cette page contient la documentation de référence pour le SDK Flutter Adapty. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/#classes)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](error-handling-on-flutter-react-native-unity)** - Gestion des erreurs et résolution des problèmes --- # File: error-handling-on-flutter-react-native-unity --- --- title: "Gérer les erreurs dans le SDK Flutter" description: "Gérer les erreurs dans le SDK Flutter." --- Chaque erreur retournée par le SDK est un `AdaptyErrorCode`. Voici un exemple : :::tip **Activez les logs verbeux avant de déboguer.** La plupart des `AdaptyError` encapsulent une erreur sous-jacente de StoreKit, Play Billing, réseau ou backend. Avec les logs verbeux activés (`await Adapty().setLogLevel(AdaptyLogLevel.verbose)` — voir [Logging](sdk-installation-flutter#logging)), cette erreur encapsulée s'affiche dans la console, ce qui révèle généralement la cause réelle. ::: :::important Si ces solutions ne résolvent pas votre problème, consultez [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support, afin de nous aider à vous assister plus efficacement. ::: ```dart showLineNumbers try { final result = await adapty.makePurchase(product: product); } on AdaptyError catch (adaptyError) { if (adaptyError.code == AdaptyErrorCode.paymentCancelled) { // Cancelled } } catch (e) { } ``` ## Codes StoreKit système \{#system-storekit-codes\} | Erreur | Code | Solution | |-----|----|-----------| | [unknown](https://developer.apple.com/documentation/storekit/skerror/code/unknown) | 0 | Code d'erreur indiquant qu'une erreur inconnue ou inattendue s'est produite. <br/> Réessayez ou consultez la section [Autres problèmes](#other-issues). | | [clientInvalid](https://developer.apple.com/documentation/storekit/skerror/code/clientinvalid) | 1 | Ce code d'erreur indique que le client n'est pas autorisé à effectuer l'action demandée. | | [paymentCancelled](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 2 | <p>Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.</p><p>Aucune action n'est requise, mais d'un point de vue logique métier, vous pouvez proposer une remise à votre utilisateur ou lui rappeler l'offre ultérieurement.</p> | | [paymentInvalid](https://developer.apple.com/documentation/storekit/skerror/code/paymentinvalid) | 3 | Cette erreur indique que l'un des paramètres de paiement n'a pas été reconnu par l'App Store. | | [paymentNotAllowed](https://developer.apple.com/documentation/storekit/skerror/code/paymentnotallowed) | 4 | Ce code d'erreur indique que l'utilisateur n'est pas autorisé à valider des paiements. | | [storeProductNotAvailable](https://developer.apple.com/documentation/storekit/skerror/code/storeproductnotavailable) | 5 | Ce code d'erreur indique que le produit demandé n'est pas disponible dans le store. <br/> Essayez de réinstaller l'application. | | [cloudServicePermissionDenied](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicepermissiondenied) | 6 | Ce code d'erreur indique que l'utilisateur n'a pas autorisé l'accès aux informations du service Cloud. | | [cloudServiceNetworkConnectionFailed](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicenetworkconnectionfailed) | 7 | Ce code d'erreur indique que l'appareil n'a pas pu se connecter au réseau. | | [cloudServiceRevoked](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicerevoked/) | 8 | Ce code d'erreur indique que l'utilisateur a révoqué l'autorisation d'utiliser ce service Cloud. | | [privacyAcknowledgementRequired](https://developer.apple.com/documentation/storekit/skerror/code/privacyacknowledgementrequired) | 9 | Ce code d'erreur indique que l'utilisateur n'a pas encore accepté la politique de confidentialité d'Apple. | | [unauthorizedRequestData](https://developer.apple.com/documentation/storekit/skerror/code/unauthorizedrequestdata) | 10 | Ce code d'erreur indique que l'application tente d'utiliser une propriété pour laquelle elle ne dispose pas des droits requis. | | [invalidOfferIdentifier](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferidentifier) | 11 | <p>L'[`identifiant`](https://developer.apple.com/documentation/storekit/skpaymentdiscount/identifier) de l'offre n'est pas valide. Par exemple, vous n'avez pas configuré d'offre avec cet identifiant dans l'App Store, ou vous avez révoqué l'offre.</p><p>Assurez-vous de configurer les offres souhaitées dans AppStore Connect et de transmettre un identifiant d'offre valide.</p> | | [invalidSignature](https://developer.apple.com/documentation/storekit/skerror/code/invalidsignature) | 12 | Ce code d'erreur indique que la signature d'une remise sur paiement n'est pas valide. | | [missingOfferParams](https://developer.apple.com/documentation/storekit/skerror/code/missingofferparams) | 13 | Ce code d'erreur indique que des paramètres sont manquants dans une remise sur paiement. | | [invalidOfferPrice](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferprice/) | 14 | Ce code d'erreur indique que le prix que vous avez spécifié dans App Store Connect n'est plus valide. Les offres doivent toujours correspondre à un prix réduit. | ## Codes Android personnalisés \{#custom-android-codes\} | Erreur | Code | Solution | |-----|----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | adaptyNotInitialized | 20 | Vous devez configurer correctement le SDK Adapty via la méthode `Adapty.activate`. Découvrez comment procéder [pour Flutter]( sdk-installation-flutter#activate-adapty-module-of-adapty-sdk). | | productNotFound | 22 | Cette erreur indique que le produit demandé pour l'achat n'est pas disponible dans le store. | | invalidJson | 23 | Le JSON du paywall n'est pas valide. Corrigez-le dans l'Adapty Dashboard. Consultez la rubrique [Personnaliser un paywall avec le Remote Config](customize-paywall-with-remote-config) pour savoir comment y remédier. | | currentSubscriptionToUpdateNotFoundInHistory | 24 | L'abonnement d'origine qui doit être renouvelé est introuvable. | | pendingPurchase | 25 | Cette erreur indique que l'état de l'achat est en attente et non finalisé. Consultez la page [Handling pending transactions](https://developer.android.com/google/play/billing/integrate#pending) dans la documentation Android Developer pour plus de détails. | | billingServiceTimeout | 97 | Cette erreur indique que la requête a atteint le délai d'expiration maximal avant que Google Play puisse répondre. Cela peut être dû, par exemple, à un retard dans l'exécution de l'action demandée par l'appel à la bibliothèque Play Billing. | | featureNotSupported | 98 | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. | | billingServiceDisconnected | 99 | Cette erreur fatale indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. | | billingServiceUnavailable | 102 | Cette erreur temporaire indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau entre l'appareil client et les services Google Play Billing. | | billingUnavailable | 103 | <p>Cette erreur indique qu'une erreur de facturation utilisateur s'est produite lors du processus d'achat. Voici quelques exemples de cas où cela peut se produire :</p><p></p><p>1\. L'application Play Store sur l'appareil de l'utilisateur n'est pas à jour.</p><p>2. L'utilisateur se trouve dans un pays non pris en charge.</p><p>3. L'utilisateur est un utilisateur entreprise et son administrateur a désactivé les achats pour les utilisateurs.</p><p>4. Google Play n'est pas en mesure de débiter le mode de paiement de l'utilisateur. Par exemple, la carte de crédit de l'utilisateur a peut-être expiré.</p><p>5. L'utilisateur n'est pas connecté à l'application Play Store.</p> | | developerError | 105 | Il s'agit d'une erreur fatale indiquant que vous utilisez une API de manière incorrecte. | | billingError | 106 | Il s'agit d'une erreur fatale indiquant un problème interne à Google Play lui-même. | | itemAlreadyOwned | 107 | Le produit consommable a déjà été acheté. | | itemNotOwned | 108 | Cette erreur indique que l'action demandée sur l'article a échoué sin | ## Codes StoreKit personnalisés \{#custom-storekit-codes\} | Erreur | Code | Solution | |-----------------------------------------------------------------------------------------------------|------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | noProductIDsFound | 1000 | <p>Cette erreur indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le.</p><p>Si vous rencontrez cette erreur, suivez les étapes de la section [Correctif pour l'erreur Code-1000 `noProductIDsFound`](InvalidProductIdentifiers-flutter).</p> | | noProductsFound | 1001 | Cette erreur indique que le produit demandé à l'achat n'est pas disponible dans le store. | | productRequestFailed | 1002 | Impossible de récupérer les produits disponibles pour le moment. | | cantMakePayments | 1003 | Les achats intégrés ne sont pas autorisés sur cet appareil. Consultez le [guide](cantMakePayments-flutter) de dépannage. | | noPurchasesToRestore | 1004 | Cette erreur indique que l'App Store n'a trouvé aucun achat à restaurer. | | [cantReadReceipt](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 1005 | <p>Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.</p><p>En sandbox, vous n'aurez pas de fichier de reçu valide tant que vous n'avez pas effectué un achat — assurez-vous d'en faire un avant d'y accéder. Lors des tests en sandbox, vérifiez également que vous êtes connecté sur l'appareil avec un compte sandbox Apple valide.</p> | | productPurchaseFailed | 1006 | L'achat du produit a échoué. Cette erreur encapsule une erreur StoreKit sous-jacente — lisez l'erreur encapsulée (ou activez les logs verbeux pour la voir dans la console) pour en connaître la raison réelle. L'erreur encapsulée correspond généralement à l'un des codes StoreKit 0–14 du tableau ci-dessus — le plus souvent `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` ou `invalidOfferPrice`. Si vous ne parvenez pas à identifier une raison précise, essayez un nouveau [profil sandbox](test-purchases-in-sandbox) ; si l'échec persiste, contactez le support Apple. | | missingOfferSigningParams | 1007 | <p>Cette erreur indique un problème d'intégration Adapty ou avec les offres.</p><p>Consultez [Configurer l'intégration App Store](app-store-connection-configuration) et [Offres](offers) pour savoir comment les configurer.</p> | | refreshReceiptFailed | 1010 | Cette erreur indique que le reçu n'a pas été reçu. Applicable à StoreKit 1 uniquement. | | receiveRestoredTransactionsFailed | 1011 | La restauration des achats a échoué. | ## Codes réseau personnalisés \{#custom-network-codes\} | Erreur | Code | Solution | | :------------------- | :--- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | notActivated | 2002 | Le SDK Adapty n'est pas activé. <br/> Cela survient le plus souvent lorsqu'un écran de démarrage ou un hook d'interface précoce appelle des méthodes Adapty avant que `Adapty().activate` ne retourne. Le symptôme est intermittent et peut ne pas se reproduire dans l'émulateur car le timing sur un vrai appareil est différent. Attendez (`await`) le Future `activate` avant de planifier tout autre appel SDK. Voir [Ordre des appels dans le SDK Flutter](flutter-sdk-call-order) pour la séquence complète. | | badRequest | 2003 | Requête incorrecte. <br/> Vérifiez que vous avez bien suivi toutes les étapes requises pour [l'intégration avec l'App Store](app-store-connection-configuration). | | serverError | 2004 | Erreur serveur. <br/> Réessayez après quelques instants. Si le problème persiste, contactez l'équipe support Adapty. | | networkFailed | 2005 | Cette erreur indique des problèmes de connexion réseau sur l'appareil de l'utilisateur. <br/> Essayez de désactiver le VPN ou de passer du réseau cellulaire au Wi-Fi, ou inversement. | | decodingFailed | 2006 | Cette erreur indique que le décodage de la réponse a échoué. <br/> Vérifiez votre code et assurez-vous que les paramètres envoyés sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. | | encodingFailed | 2009 | Cette erreur indique que l'encodage de la requête a échoué. | | analyticsDisabled | 3000 | Impossible de traiter les événements d'analytics, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). | | wrongParam | 3001 | Cette erreur indique que certains de vos paramètres sont incorrects. <br/> Si vous utilisez le Paywall Builder d'Adapty et que vous ne pouvez pas afficher un paywall à cause de cette erreur, activez l'option **Show on device** dans le Paywall Builder.<br/> Une autre cause possible est que la version du fichier [paywall de secours](fallback-paywalls) local ne correspond pas à la version du SDK. Téléchargez un nouveau fichier depuis le tableau de bord. | | activateOnceError | 3005 | Il n'est pas possible d'appeler la méthode `.activate` plus d'une fois. | | profileWasChanged | 3006 | Le profil utilisateur a été modifié pendant l'opération. <br/> Cela se produit lorsqu'une méthode est appelée alors que `Adapty().identify` est encore en cours — l'appel en vol atterrit sur un profil sur le point d'être remplacé, et le SDK le rejette. Attendez toujours (`await`) `identify` avant tout appel lié à une action utilisateur. Voir [Ordre des appels dans le SDK Flutter](flutter-sdk-call-order). | | unsupportedData | 3007 | Cette erreur indique que le format des données n'est pas pris en charge par le SDK. | | persistingDataError | 3100 | Une erreur s'est produite lors de l'enregistrement des données. | | fetchTimeoutError | 3101 | Cette erreur indique que l'opération de récupération a expiré. | ## Autres problèmes \{#other-issues\} Si vous n'avez pas encore trouvé de solution, voici quelques pistes supplémentaires : - **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de passer à la dernière version du SDK, car elle est plus stable et inclut des correctifs pour les problèmes connus. - **Contacter l'équipe de support ou obtenir de l'aide auprès d'autres développeurs** sur le [forum de support](https://adapty.featurebase.app/). - **Contacter l'équipe de support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou que cela n'a pas résolu le problème, contactez notre équipe de support. Notez que votre problème sera résolu plus rapidement si vous [activez la journalisation verbose](sdk-installation-flutter#logging) et partagez les logs avec l'équipe. Vous pouvez également joindre des extraits de code pertinents. --- # File: InvalidProductIdentifiers-flutter --- --- title: "Correction de l'erreur Code-1000 noProductIDsFound dans le SDK Flutter" description: "Résolvez les erreurs d'identifiant de produit invalide lors de la gestion des abonnements dans Adapty." --- L'erreur code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont bien listés. Cette erreur peut parfois être accompagnée d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le sans vous en préoccuper. Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre : ## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\} 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Vérifier les produits \{#step-3-check-products\} 1. Rendez-vous dans **App Store Connect** et naviguez vers [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. Vos produits s'affichent dans la section **Subscriptions**. 3. Assurez-vous que le produit que vous testez est marqué **Ready to Submit**. <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Comparez l'ID du produit dans le tableau avec celui de l'onglet [**Products**](https://app.adapty.io/products) dans l'Adapty Dashboard. Si les ID ne correspondent pas, copiez l'ID du produit depuis le tableau et [créez un produit](create-product) avec cet ID dans l'Adapty Dashboard. <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3. Vérifier la disponibilité du produit \{#step-4-check-product-availability\} 1. Retournez dans **App Store Connect** et ouvrez la même section **Subscriptions**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis y sont listés. <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. Retournez dans la section **Monetization** → **Subscriptions** d'**App Store Connect**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à **Subscription Pricing** et développez la section **Current Pricing for New Subscribers**. <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Assurez-vous que tous les prix requis sont bien listés. <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Vérifier que le statut paid, le compte bancaire et les formulaires fiscaux sont actifs \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. Sur la page d'accueil d'[**App Store Connect**](https://appstoreconnect.apple.com/), cliquez sur **Business**. <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez le nom de votre entreprise. <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Faites défiler vers le bas et vérifiez que votre **Paid Apps Agreement**, votre **Bank Account** et vos **Tax forms** affichent tous le statut **Active**. <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En suivant ces étapes, vous devriez pouvoir résoudre l'avertissement `InvalidProductIdentifiers` et rendre vos produits disponibles dans le store. ## Étape 6. Recréer le produit s'il est bloqué \{#step-6-recreate-the-product-if-its-stuck\} Les étapes 1 à 5 peuvent toutes être validées — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK renvoie quand même `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre de produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit. Supprimez le produit dans App Store Connect et recréez-le avec le même ID de produit. Attendez jusqu'à 24 heures après la recréation pour que la propagation s'effectue. --- # File: cantMakePayments-flutter --- --- title: "Correction de l'erreur Code-1003 cantMakePayment dans le SDK Flutter" description: "Résolvez l'erreur de paiement lors de la gestion des abonnements dans Adapty." --- L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil. Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes : - Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous. - Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous. ## Problème : Restrictions de l'appareil \{#issue-device-restrictions\} | Problème | Solution | |--------------------------------|-------------------------------------------------------------------------------------------------------------| | Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) | | Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte | | Restrictions régionales | Utilisez un compte App Store d'une région prise en charge | ## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\} Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat. Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK. --- # File: flutter-sdk-migration-guides --- --- title: "Guides de migration Flutter SDK" description: "Guides de migration pour les versions du SDK Flutter Adapty." --- Cette page regroupe tous les guides de migration pour le SDK Flutter Adapty. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées : - **[Migrer vers la v4.0](migration-to-flutter-sdk-v4)** - **[Migrer vers la v3.8](flutter-migration-guide-38)** - **[Migrer vers la v3.4](migration-to-flutter-sdk-34)** - **[Migrer vers la v3.3](migration-to-flutter330)** - **[Migrer vers la v3.0](migration-to-flutter-sdk-v3)** --- # File: migration-to-flutter-sdk-v4 --- --- title: "Migrer vers le SDK Flutter Adapty v. 4.0" description: "Migrez vers le SDK Flutter Adapty v4.0 en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK Flutter Adapty 4.0 introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty().getPaywall(placementId: id)` | `Adapty().getFlow(placementId: id)` | | `Adapty().getPaywallForDefaultAudience(placementId: id)` | `Adapty().getFlowForDefaultAudience(placementId: id)` | | `Adapty().getPaywallProducts(paywall: paywall)` | `Adapty().getPaywallProducts(flow: flow)` | | `Adapty().logShowPaywall(paywall: paywall)` | `Adapty().logShowFlow(flow: flow)` | | `AdaptyPaywall` (type) | `AdaptyFlow` | | `AdaptyPaywallFetchPolicy` (type) | `AdaptyFlowFetchPolicy` | | `AdaptyUI().createPaywallView(paywall: paywall)` | `AdaptyUI().createFlowView(flow: flow)` | | `AdaptyUIPaywallView` (type) | `AdaptyUIFlowView` | | `AdaptyUIPaywallPlatformView` (widget) | `AdaptyUIFlowPlatformView` | | `AdaptyUI().presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI().presentFlowView(view)` / `dismissFlowView(view)` | | `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` | | `AdaptyUI().setPaywallsEventsObserver(observer)` | `AdaptyUI().setFlowsEventsObserver(observer)` | | `paywallViewDid*` callbacks | `flowViewDid*` callbacks | | `paywallViewDidFailRendering` | `flowViewDidReceiveError` | `AdaptyPaywallProduct` conserve son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` prend désormais un `AdaptyFlow`. Vous ne passez plus de `locale` lors de la récupération d'un flow. Les API d'achat et de profil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, etc.) sont inchangées, tout comme les méthodes de vue `present`, `dismiss` et `showDialog`. Certains comportements par défaut ont changé — voir [Changements des comportements par défaut](#default-behavior-changes). ## Versions minimales \{#minimum-versions\} Adapty Flutter SDK 4.0 relève les exigences minimales : - **iOS 15.0** — cible de déploiement iOS minimale, relevée depuis iOS 13.0. - **Xcode 26** ou version ultérieure — le SDK iOS natif utilise Swift tools 6.2. - **Flutter 3.32.0** (Dart 3.8.0) ou version ultérieure. ## Installation \{#installation\} ### Mettre à jour le package \{#update-the-package\} Le package à installer dépend de si votre application utilise le mode enfant. Pour la plupart des applications, mettez à jour `adapty_flutter` vers la v4.0 dans votre `pubspec.yaml` : ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: 4.0.0 ``` Si votre application utilise le mode enfant, spécifiez `adapty_flutter_kids` à la place : ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter_kids: 4.0.0 ``` Ce **package autonome** supprime le code IDFA et de suivi publicitaire pour se conformer aux exigences de l'App Store. Mettez à jour le chemin d'import Dart vers `package:adapty_flutter_kids/adapty_flutter.dart`. Pour le reste, la migration est exactement la même que pour le package standard. Le mode Kids requiert également de désactiver la collecte d'adresses IP dans l'Adapty Dashboard — consultez [Kids Mode](kids-mode-flutter) pour la configuration complète. ### iOS : les SDK natifs passent désormais par Swift Package Manager [Le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), aussi à partir de la v4 le SDK iOS natif **n'est plus distribué via CocoaPods** — le plugin le récupère uniquement via **Swift Package Manager**. Si vous utilisez Flutter 3.32–3.43, activez le support de Swift Package Manager une seule fois : ```bash flutter config --enable-swift-package-manager ``` Flutter 3.44 et versions ultérieures activent Swift Package Manager par défaut, aucune action n'est donc nécessaire. ## Récupérer des flows \{#fetching-flows\} ### getPaywall → getFlow Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et il n'est plus nécessaire de passer un `locale` — lorsque vous affichez un flow, la localisation est résolue automatiquement ; pour les paywalls personnalisés, toutes les locales configurées sont retournées dans `flow.remoteConfigs` : ```diff showLineNumbers - final paywall = await Adapty().getPaywall(placementId: 'YOUR_PLACEMENT_ID', locale: 'en'); + final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); ``` `getPaywallForDefaultAudience` est renommé de la même manière : ```diff showLineNumbers - final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID', locale: 'en'); + final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); ``` Le type de politique de récupération est renommé de `AdaptyPaywallFetchPolicy` en `AdaptyFlowFetchPolicy` ; ses options (`reloadRevalidatingCacheData`, `returnCacheDataElseLoad`, `returnCacheDataIfNotExpiredElseLoad`) restent inchangées. ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` garde son nom mais prend désormais un `AdaptyFlow` via le paramètre `flow` : ```diff showLineNumbers - final products = await Adapty().getPaywallProducts(paywall: paywall); + final products = await Adapty().getPaywallProducts(flow: flow); ``` ### Fichiers de secours \{#fallback-files\} Le format des fichiers de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le dans votre application. ## Modèle de données \{#data-model\} `getFlow` renvoie un `AdaptyFlow` au lieu d'un `AdaptyPaywall`, et la structure de l'objet a changé : | Membre v3 `AdaptyPaywall` | Membre v4 `AdaptyFlow` | Action | |---|---|---| | `remoteConfig` (unique, nullable) | `remoteConfigs` (liste) | Un flow contient un Remote Config par langue configurée. Le getter `remoteConfig` existe toujours et renvoie la première entrée ; pour choisir une langue spécifique, cherchez dans `remoteConfigs` par son `locale`. | | `productIdentifiers` | `productIdentifiers` | Conservé, mais désormais collecté pour toutes les variations de paywall du flow. Les identifiants par variation se trouvent sur `flow.paywalls[i].productIdentifiers`. | | `hasViewConfiguration` | `hasViewConfiguration` | Inchangé. | | `placementId` (déprécié) | supprimé | Utilisez `flow.placement.id`. | | `revision` (déprécié) | supprimé | Utilisez `flow.placement.revision`. | | `vendorProductIds` (déprécié) | supprimé | Utilisez `productIdentifiers`. | | _(nouveau)_ | `paywalls` (liste de `AdaptyFlowPaywall`) | Chaque entrée est une variation de paywall dans le flow, avec son propre `name`, `variationId` et `productIdentifiers`. | `AdaptyPaywallViewConfiguration` n'est plus exposé — la configuration de vue est désormais opaque. Supprimez toute référence à ce type. ## Méthodes de paywall web \{#web-paywall-methods\} `openWebPaywall` et `createWebPaywallUrl` conservent leurs noms, mais le paramètre `paywall` attend désormais un `AdaptyFlowPaywall` (une variante de flow) au lieu d'un `AdaptyPaywall`. Vous pouvez toujours passer un `AdaptyPaywallProduct` à la place. ```diff showLineNumbers final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); - await Adapty().openWebPaywall(paywall: paywall); + if (flow.paywalls.isNotEmpty) { + await Adapty().openWebPaywall(paywall: flow.paywalls[0]); + } ``` ## Suivi des vues de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` est renommé en `logShowFlow` et accepte désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modifications du tableau de bord. ```diff showLineNumbers - await Adapty().logShowPaywall(paywall: paywall); + await Adapty().logShowFlow(flow: flow); ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage de flows ou de paywalls créés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement. ## Affichage des flows \{#displaying-flows\} ### createPaywallView → createFlowView Renommez la méthode et passez l'`AdaptyFlow` via le paramètre `flow`. Les autres paramètres (`loadTimeout`, `preloadProducts`, `customTags`, `customTimers`, `customAssets`, `productPurchaseParams`) restent inchangés, ainsi que les méthodes de la vue `present`, `dismiss` et `showDialog` : ```diff showLineNumbers - final view = await AdaptyUI().createPaywallView(paywall: paywall); + final view = await AdaptyUI().createFlowView(flow: flow); await view.present(); ``` ### AdaptyUIPaywallView → AdaptyUIFlowView Le type de vue est renommé. Sa propriété `paywallVariationId` (dépréciée) est supprimée — utilisez `variationId` : ```diff showLineNumbers - void flowViewDidAppear(AdaptyUIPaywallView view) { + void flowViewDidAppear(AdaptyUIFlowView view) { ``` ### AdaptyUIPaywallPlatformView → AdaptyUIFlowPlatformView Si vous intégrez la vue en tant que widget dans votre arbre de widgets, renommez-la et passez le paramètre `flow`. Les callbacks d'événements (`onDidAppear`, `onDidFinishPurchase`, etc.) conservent leurs noms : ```diff showLineNumbers - AdaptyUIPaywallPlatformView( - paywall: paywall, + AdaptyUIFlowPlatformView( + flow: flow, onDidFinishPurchase: (view, product, purchaseResult) { /* … */ }, ) ``` :::note Une vue de flow créée avec `createFlowView` est à usage unique : après avoir appelé `dismiss()`, la vue est libérée de la mémoire et ne peut plus être présentée de nouveau — appelez `createFlowView` à nouveau pour afficher le flow une nouvelle fois. ::: ## Gestion des événements \{#handling-events\} La classe d'observateur est renommée de `AdaptyUIPaywallsEventsObserver` en `AdaptyUIFlowsEventsObserver`, sa méthode d'enregistrement de `setPaywallsEventsObserver` en `setFlowsEventsObserver`, et tous les callbacks `paywallViewDid*` en `flowViewDid*` : ```diff showLineNumbers - class MyObserver extends AdaptyUIPaywallsEventsObserver { + class MyObserver extends AdaptyUIFlowsEventsObserver { @override - void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { + void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { // … } } - AdaptyUI().setPaywallsEventsObserver(this); + AdaptyUI().setFlowsEventsObserver(this); ``` Trois callbacks sont désormais **obligatoires** — votre observateur ne compilera pas sans eux : - **`flowViewDidFinishPurchase`**: Était optionnel en v3, où le comportement par défaut fermait la vue après un achat. Vous décidez maintenant de la suite : continuer le flow ou appeler `view.dismiss()`. - **`flowViewDidFinishRestore`**: Obligatoire, comme en v3. - **`flowViewDidReceiveError`**: Remplace `paywallViewDidFailRendering` et reçoit désormais aussi les autres erreurs de vue. Deux changements mineurs : - `setFlowsEventsObserver` (et `setOnboardingsEventsObserver`) acceptent désormais `null` pour détacher un observateur précédemment défini, afin que le SDK ne le conserve plus. - Le nouveau callback optionnel `flowViewDidReceiveAnalyticEvent` est ré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. v4 ajoute également des fonctionnalités que vous pouvez activer à la demande : - `AdaptyUI().setObserverModeResolver(...)` avec un `AdaptyUIObserverModeResolver` — gère les achats et restaurations initiés depuis les flows lorsque le SDK s'exécute en [mode Observateur](implement-observer-mode-flutter). Auparavant, cette fonctionnalité n'était disponible que dans les SDK natifs iOS et Android. Voir [Présenter les flows en mode Observateur](flutter-present-flows-in-observer-mode). - `AdaptyUI().setSystemRequestsHandler(...)` avec un `AdaptyUISystemRequestsHandler` — réservé aux requêtes système provenant d'un flow (demandes de permissions OS et demandes d'avis App Store). Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler. ## API supprimées \{#removed-apis\} Ces symboles étaient dépréciés dans la version 3.x et sont supprimés dans la v4 : ### setFallbackPaywalls → setFallback ```diff showLineNumbers - await Adapty().setFallbackPaywalls(assetId); + await Adapty().setFallback(assetId); ``` ### withIdfaCollectionDisabled → withAppleIdfaCollectionDisabled ```diff showLineNumbers configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') - ..withIdfaCollectionDisabled(true), + ..withAppleIdfaCollectionDisabled(true), ``` ### Autres membres supprimés - **`AdaptyPurchaseResultSuccess.jwsTransaction`** : Utilisez `appleJwsTransaction`. - **`AdaptyUIFlowView.paywallVariationId`** : Utilisez `variationId`. - **`AdaptyUIObserver` et `AdaptyUI().setObserver(...)`** : Utilisez `AdaptyUIFlowsEventsObserver` et `setFlowsEventsObserver(...)`. ## Changements de comportement par défaut \{#default-behavior-changes\} Ces changements n'entraînent pas d'erreurs de compilation ; testez-les donc au moment de l'exécution : - **Achat réussi** : En v3, le `paywallViewDidFinishPurchase` par défaut fermait la vue. En v4, `flowViewDidFinishPurchase` est obligatoire et n'a pas de comportement par défaut — fermez la vue vous-même si c'est ce que vous souhaitez. - **Bouton retour système Android** : Il ne ferme plus un flow par défaut. L'action est transmise à `flowViewDidPerformAction` sous la forme `AndroidSystemBackAction` — gérez-la là si vous voulez que le bouton retour ferme le flow. - **Ouverture d'URL** : Le `flowViewDidPerformAction` par défaut gère désormais `OpenUrlAction` en ouvrant l'URL nativement (en respectant le paramètre navigateur intégré ou externe du tableau de bord), en plus de fermer la vue sur `CloseAction`. Surchargez le callback pour gérer les URL vous-même. - **Erreurs de vue** : `flowViewDidReceiveError` est obligatoire, et la fermeture dépend de votre implémentation. Si votre intégration v3 reposait sur la fermeture automatique de la vue en cas d'erreur de rendu, appelez `view.dismiss()` dans ce callback. - **Cycle de vie de la vue** : Fermer une vue de flow ou d'onboarding la libère de la mémoire. Une vue fermée ne peut plus être réaffichée — créez-en une nouvelle à la place. ## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\} L'API onboarding héritée est dépréciée depuis la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, et votre IDE signale les symboles dépréciés via leurs annotations `@Deprecated` — aucun avertissement n'est émis à l'exécution. Ces symboles seront supprimés dans une prochaine version, pensez donc à migrer vos onboardings vers le Flow Builder. Symboles dépréciés : `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView`, `presentOnboardingView`, `dismissOnboardingView`, `setOnboardingsEventsObserver`, `AdaptyOnboarding`, `AdaptyUIOnboardingView`, `AdaptyUIOnboardingPlatformView`, `AdaptyUIOnboardingsEventsObserver`, ainsi que les modèles d'état, de saisie et d'analytique d'onboarding. --- # File: flutter-migration-guide-310 --- --- title: "Guide de migration vers Flutter Adapty SDK 3.10.0" description: "" --- Adapty SDK 3.10.0 est une version majeure qui apporte des améliorations nécessitant toutefois quelques étapes de migration de votre part : 1. Mettre à jour la méthode `makePurchase` pour utiliser `AdaptyPurchaseParameters` à la place des paramètres individuels. 2. Remplacer `vendorProductIds` par `productIdentifiers` dans le modèle `AdaptyPaywall`. ## Mettre à jour la méthode makePurchase \{#update-makepurchase-method\} La méthode `makePurchase` utilise désormais `AdaptyPurchaseParameters` à la place des arguments individuels `subscriptionUpdateParams` et `isOfferPersonalized`. Cela offre une meilleure sécurité des types et permet d'étendre les paramètres d'achat à l'avenir. ```diff showLineNumbers - final purchaseResult = await adapty.makePurchase( - product: product, - subscriptionUpdateParams: subscriptionUpdateParams, - isOfferPersonalized: true, - ); + final parameters = AdaptyPurchaseParametersBuilder() + ..setSubscriptionUpdateParams(subscriptionUpdateParams) + ..setIsOfferPersonalized(true) + ..setObfuscatedAccountId('your-account-id') + ..setObfuscatedProfileId('your-profile-id'); + final purchaseResult = await adapty.makePurchase( + product: product, + parameters: parameters.build(), + ); ``` Si aucun paramètre supplémentaire n'est nécessaire, vous pouvez simplement utiliser : ```dart showLineNumbers final purchaseResult = await adapty.makePurchase( product: product, ); ``` ## Mettre à jour l'utilisation du modèle AdaptyPaywall \{#update-adaptypaywall-model-usage\} La propriété `vendorProductIds` a été dépréciée au profit de `productIdentifiers`. La nouvelle propriété retourne des objets `AdaptyProductIdentifier` au lieu de simples chaînes de caractères, offrant une structure d'informations produit plus cohérente. ```diff showLineNumbers - paywall.vendorProductIds.map((vendorId) => - ListTextTile(title: vendorId) - ).toList() + paywall.productIdentifiers.map((productId) => + ListTextTile(title: productId.vendorProductId) + ).toList() ``` L'objet `AdaptyProductIdentifier` donne accès à l'identifiant de produit du vendor via la propriété `vendorProductId`, conservant ainsi la même fonctionnalité tout en offrant une meilleure structure pour les évolutions futures. ## Compatibilité ascendante \{#backward-compatibility\} Les deux modifications maintiennent la compatibilité ascendante : - Les anciens paramètres de `makePurchase` sont dépréciés mais restent fonctionnels - La propriété `vendorProductIds` est dépréciée mais reste accessible - Le code existant continuera de fonctionner, même si des avertissements de dépréciation apparaîtront Nous vous recommandons de mettre à jour votre code pour utiliser les nouvelles API afin de garantir la compatibilité future et de profiter de la meilleure sécurité des types et extensibilité offertes. --- # File: flutter-migration-guide-38 --- --- title: "Migrer le SDK Adapty Flutter vers v3.8" description: "Migrez vers le SDK Adapty Flutter v3.8 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Adapty SDK 3.8.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre côté. 1. Mettez à jour le nom de la classe observer et de ses méthodes. 2. Mettez à jour le nom de la méthode pour les paywalls de secours. 3. Mettez à jour le nom de la classe view dans les méthodes de gestion des événements. ## Mettre à jour le nom de la classe observer et de ses méthodes \{#update-observer-class-and-method-names\} La classe observer et sa méthode d'enregistrement ont été renommées : ```diff showLineNumbers - class MyObserver extends AdaptyUIObserver { + class MyObserver extends AdaptyUIPaywallsEventsObserver { @override void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) { // Handle action } } // Register observer - AdaptyUI().setObserver(this); + AdaptyUI().setPaywallsEventsObserver(this); ``` ## Mettre à jour le nom de la méthode pour les paywalls de secours \{#update-fallback-paywalls-method-name\} La méthode pour définir les paywalls de secours a été simplifiée : ```diff showLineNumbers try { - await Adapty.setFallbackPaywalls(assetId); + await Adapty.setFallback(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## Mettre à jour le nom de la classe view dans les méthodes de gestion des événements \{#update-view-class-name-in-event-handling-methods\} Toutes les méthodes de gestion des événements utilisent désormais la nouvelle classe `AdaptyUIPaywallView` à la place de `AdaptyUIView` : ```diff showLineNumbers - void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) + void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) - void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product) + void paywallViewDidSelectProduct(AdaptyUIPaywallView view, AdaptyPaywallProduct product) - void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product) + void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) - void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile) + void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyProfile profile) - void paywallViewDidFailPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error) + void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) - void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile) + void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) - void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) + void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) - void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) + void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) - void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error) + void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) ``` --- # File: migration-to-flutter-sdk-34 --- --- title: "Migrer le SDK Flutter Adapty vers la v3.4" description: "Migrez vers le SDK Flutter Adapty v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté. ## Mettre à jour les fichiers de paywall de secours \{#update-fallback-paywall-files\} Mettez à jour vos fichiers de paywall de secours pour assurer la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](flutter-use-fallback-paywalls) par les nouveaux fichiers. ## Mettre à jour l'implémentation du mode Observateur \{#update-implementation-of-observer-mode\} Si vous utilisez le mode Observateur, veillez à mettre à jour son implémentation. Auparavant, différentes méthodes étaient utilisées pour signaler les transactions à Adapty. Dans la nouvelle version, la méthode `reportTransaction` doit être utilisée de manière cohérente sur Android et iOS. Cette méthode signale explicitement chaque transaction à Adapty, garantissant qu'elle est bien reconnue. Si un paywall a été utilisé, transmettez l'ID de variation pour associer la transaction à celui-ci. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: ```diff showLineNumbers - // every time when calling transaction.finish() - if (Platform.isAndroid) { - try { - await Adapty().restorePurchases(); - } on AdaptyError catch (adaptyError) { - // handle the error - } catch (e) { - } - } try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` --- # File: migration-to-flutter330 --- --- title: "Migrer le SDK Adapty Flutter vers v3.3" description: "Migrez vers le SDK Adapty Flutter v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.3.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part. 1. Mettre à jour la méthode de fourniture des paywalls de secours. 2. Supprimer la méthode `getProductsIntroductoryOfferEligibility`. 3. Mettre à jour les configurations d'intégration pour Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase et Google Analytics, Mixpanel, OneSignal, Pushwoosh. 4. Mettre à jour l'implémentation du mode Observer. ## Mettre à jour la méthode de fourniture des paywalls de secours \{#update-method-for-providing-fallback-paywalls\} Auparavant, la méthode attendait le paywall de secours sous forme de chaîne JSON (`jsonString`), mais elle prend désormais le chemin vers le fichier de secours local (`assetId`) à la place. ```diff showLineNumbers import 'dart:async' show Future; import 'dart:io' show Platform; -import 'package:flutter/services.dart' show rootBundle; -final filePath = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; -final jsonString = await rootBundle.loadString(filePath); +final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; try { - await adapty.setFallbackPaywalls(jsonString); + await adapty.setFallbackPaywalls(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Pour un exemple de code complet, consultez la page [Utiliser les paywalls de secours](flutter-use-fallback-paywalls). ## Supprimer la méthode `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\} Avant le SDK Adapty iOS 3.3.0, l'objet produit incluait toujours les offres, que l'utilisateur y soit éligible ou non. Vous deviez vérifier manuellement l'éligibilité avant d'utiliser l'offre. Désormais, l'objet produit n'inclut une offre que si l'utilisateur y est éligible. Cela signifie que vous n'avez plus besoin de vérifier l'éligibilité — si une offre est présente, l'utilisateur est éligible. ## Mettre à jour la configuration du SDK des intégrations tierces \{#update-third-party-integration-sdk-configuration\} Pour que les intégrations fonctionnent correctement avec le SDK Adapty Flutter 3.3.0 et les versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes, comme décrit dans les sections ci-dessous. ### Adjust Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers import 'package:adjust_sdk/adjust.dart'; import 'package:adjust_sdk/adjust_config.dart'; try { final adid = await Adjust.getAdid(); if (adid == null) { // handle the error } + await Adapty().setIntegrationIdentifier( + key: "adjust_device_id", + value: adid, + ); final attributionData = await Adjust.getAttribution(); var attribution = Map<String, String>(); if (attributionData.trackerToken != null) attribution['trackerToken'] = attributionData.trackerToken!; if (attributionData.trackerName != null) attribution['trackerName'] = attributionData.trackerName!; if (attributionData.network != null) attribution['network'] = attributionData.network!; if (attributionData.adgroup != null) attribution['adgroup'] = attributionData.adgroup!; if (attributionData.creative != null) attribution['creative'] = attributionData.creative!; if (attributionData.clickLabel != null) attribution['clickLabel'] = attributionData.clickLabel!; if (attributionData.costType != null) attribution['costType'] = attributionData.costType!; if (attributionData.costAmount != null) attribution['costAmount'] = attributionData.costAmount!.toString(); if (attributionData.costCurrency != null) attribution['costCurrency'] = attributionData.costCurrency!; if (attributionData.fbInstallReferrer != null) attribution['fbInstallReferrer'] = attributionData.fbInstallReferrer!; - Adapty().updateAttribution( - attribution, - source: AdaptyAttributionSource.adjust, - networkUserId: adid, - ); + await Adapty().updateAttribution(attribution, source: "adjust"); } catch (e) { // handle the error } on AdaptyError catch (adaptyError) { // handle the error } ``` ### AirBridge Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers import 'package:airbridge_flutter_sdk/airbridge_flutter_sdk.dart'; final deviceUUID = await Airbridge.state.deviceUUID; try { - final builder = AdaptyProfileParametersBuilder() - ..setAirbridgeDeviceId(deviceUUID); - await Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "airbridge_device_id", + value: deviceUUID, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### Amplitude Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers import 'package:amplitude_flutter/amplitude.dart'; final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); final deviceId = await amplitude.getDeviceId(); final userId = await amplitude.getUserId(); try { - final builder = AdaptyProfileParametersBuilder() - ..setAmplitudeDeviceId(deviceId) - ..setAmplitudeUserId(userId); - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "amplitude_user_id", + value: userId, + ); + await Adapty().setIntegrationIdentifier( + key: "amplitude_device_id", + value: deviceId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### AppMetrica Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers import 'package:appmetrica_plugin/appmetrica_plugin.dart'; final deviceId = await AppMetrica.deviceId; if (deviceId != null) { try { - final builder = AdaptyProfileParametersBuilder() - ..setAppmetricaDeviceId(deviceId) - ..setAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID"); - - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "appmetrica_device_id", + value: deviceId, + ); + await Adapty().setIntegrationIdentifier( + key: "appmetrica_profile_id", + value: "YOUR_ADAPTY_CUSTOMER_USER_ID", + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` ### AppsFlyer Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers import 'package:appsflyer_sdk/appsflyer_sdk.dart'; AppsflyerSdk appsflyerSdk = AppsflyerSdk(<YOUR_OPTIONS>); appsflyerSdk.onInstallConversionData((data) async { try { final appsFlyerUID = await appsFlyerSdk.getAppsFlyerUID(); - await Adapty().updateAttribution( - data, - source: AdaptyAttributionSource.appsflyer, - networkUserId: appsFlyerUID, - ); + await Adapty().setIntegrationIdentifier( + key: "appsflyer_id", + value: appsFlyerUID, + ); + + await Adapty().updateAttribution(data, source: "appsflyer"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } }); appsflyerSdk.initSdk( registerConversionDataCallback: true, registerOnAppOpenAttributionCallback: true, registerOnDeepLinkingCallback: true, ); ``` ### Branch Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers FlutterBranchSdk.initSession().listen((data) async { try { + await Adapty().setIntegrationIdentifier( + key: "branch_id", + value: <BRANCH_IDENTITY_ID>, + ); - await Adapty().updateAttribution(data, source: AdaptyAttributionSource.branch); + await Adapty().updateAttribution(data, source: "branch"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ); ``` ### Firebase et Google Analytics Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Firebase et Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers final appInstanceId = await FirebaseAnalytics.instance.appInstanceId; try { - final builder = AdaptyProfileParametersBuilder() - ..setFirebaseAppInstanceId(appInstanceId); - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "firebase_app_instance_id", + value: appInstanceId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### Mixpanel Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers final mixpanel = await Mixpanel.init("Your Token", trackAutomaticEvents: true); final distinctId = await mixpanel.getDistinctId(); try { - final builder = AdaptyProfileParametersBuilder() - ..setMixpanelUserId(distinctId); - await Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "mixpanel_user_id", + value: distinctId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### OneSignal Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration OneSignal](onesignal#sdk-configuration). ```diff showLineNumbers OneSignal.shared.setSubscriptionObserver((changes) { final playerId = changes.to.userId; if (playerId != null) { - final builder = - AdaptyProfileParametersBuilder() - ..setOneSignalPlayerId(playerId); - // ..setOneSignalSubscriptionId(playerId); try { - Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "one_signal_player_id", + value: playerId, + ); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle error } } }); ``` ### Pushwoosh Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers final hwid = await Pushwoosh.getInstance.getHWID; - final builder = AdaptyProfileParametersBuilder() - ..setPushwooshHWID(hwid); try { - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "pushwoosh_hwid", + value: hwid, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## Mettre à jour l'implémentation du mode Observer \{#update-observer-mode-implementation\} Mettez à jour la façon dont vous associez les paywalls aux transactions. Auparavant, vous utilisiez la méthode `setVariationId` pour assigner le `variationId`. Désormais, vous pouvez inclure le `variationId` directement lors de l'enregistrement de la transaction via la nouvelle méthode `reportTransaction`. Consultez l'exemple de code final dans [Associer des paywalls aux transactions d'achat en mode Observer](report-transactions-observer-mode-flutter). :::warning N'oubliez pas d'enregistrer la transaction à l'aide de la méthode `reportTransaction`. Si vous omettez cette étape, Adapty ne reconnaîtra pas la transaction, n'accordera pas les niveaux d'accès, ne l'inclura pas dans les analyses et ne l'enverra pas aux intégrations. Cette étape est indispensable ! ::: ```diff showLineNumbers try { - await Adapty().setVariationId("YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID"); + // every time when calling transaction.finish() + await Adapty().reportTransaction( + "YOUR_TRANSACTION_ID", + variationId: "PAYWALL_VARIATION_ID", // optional + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` --- # File: migration-to-flutter-sdk-v3 --- --- title: "Migrer le SDK Flutter Adapty vers v3.0" description: "Migrez vers le SDK Flutter Adapty v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Adapty Paywall Builder](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et à ses riches capacités de design, vos paywalls deviendront plus efficaces et plus rentables. :::info Veuillez noter que la bibliothèque AdaptyUI est dépréciée et fait désormais partie intégrante du SDK Adapty. ::: ## Supprimer le SDK AdaptyUI \{#remove-adaptyui-sdk\} 1. AdaptyUI devient un module du SDK Adapty. Supprimez donc `adapty_ui_flutter` de votre fichier `pubspec.yaml` : ```diff showLineNumbers dependencies: + adapty_flutter: ^3.2.1 - adapty_flutter: ^2.10.3 - adapty_ui_flutter: ^2.1.3 ``` 2. Exécutez : ```bash showLineNumbers title="Bash" flutter pub get ``` ## Configurer les SDK Adapty \{#configure-adapty-sdks\} Auparavant, vous deviez utiliser les fichiers `Adapty-Info.plist` et `AndroidManifest.xml` pour configurer le SDK Adapty. Désormais, il n'est plus nécessaire d'utiliser des fichiers supplémentaires. Vous pouvez fournir tous les paramètres requis directement lors de l'activation. Il vous suffit de configurer le SDK Adapty une seule fois, généralement au démarrage du cycle de vie de votre application. ### Activer le module Adapty du SDK Adapty \{#activate-adapty-module-of-adapty-sdk\} 1. Supprimez l'import du SDK AdaptyUI de votre application comme suit : ```diff showLineNumbers import 'package:adapty_flutter/adapty_flutter.dart'; - import 'package:adapty_ui_flutter/adapty_ui_flutter.dart'; ``` 2. Mettez à jour l'activation du SDK Adapty comme ceci : ```diff showLineNumbers try { - Adapty().activate(); + await Adapty().activate( + configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') + ..withLogLevel(AdaptyLogLevel.debug) + ..withObserverMode(false) + ..withCustomerUserId(null) + ..withIpAddressCollectionDisabled(false) + ..withIdfaCollectionDisabled(false), + ); } catch (e) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | ----------------------------------- | -------- | ------------------------------------------------------------ | | **PUBLIC_SDK_KEY** | requis | La clé que vous pouvez trouver dans le champ **Public SDK key** des paramètres de votre application dans Adapty : [**App settings**-> onglet **General** -> sous-section **API keys**](https://app.adapty.io/settings/general) | | **withLogLevel** | optionnel | Adapty enregistre les erreurs et d'autres informations essentielles pour vous donner une vue sur le fonctionnement de votre application. Les niveaux disponibles sont les suivants :<ul><li> error : seules les erreurs seront enregistrées.</li><li> warn : les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques mais méritent attention seront enregistrés.</li><li> info : les erreurs, avertissements et messages d'information importants, comme ceux qui tracent le cycle de vie des différents modules, seront enregistrés.</li><li> verbose : toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera enregistrée.</li></ul> | | **withObserverMode** | optionnel | <p>Une valeur booléenne contrôlant le [mode Observer](observer-vs-full-mode). Activez-le si vous gérez vous-même les achats et le statut des abonnements, et utilisez Adapty uniquement pour envoyer des événements d'abonnement et des données analytiques.</p><p>La valeur par défaut est `false`.</p><p></p><p>🚧 En mode Observer, le SDK Adapty ne fermera aucune transaction. Assurez-vous donc de les gérer vous-même.</p> | | **withCustomerUserId** | optionnel | Un identifiant de l'utilisateur dans votre système. Nous l'envoyons dans les événements d'abonnement et d'analyse pour attribuer les événements au bon profil. Vous pouvez également retrouver vos utilisateurs par `customerUserId` dans le menu [**Profiles and Segments**](https://app.adapty.io/profiles/users). | | **withIdfaCollectionDisabled** | optionnel | <p>Définissez à `true` pour désactiver la collecte et le partage de l'IDFA.</p><p>le partage de l'adresse IP de l'utilisateur.</p><p>La valeur par défaut est `false`.</p><p>Pour plus de détails sur la collecte de l'IDFA, consultez la section [Intégration Analytics](analytics-integration#disable-collection-of-advertising-identifiers).</p> | | **withIpAddressCollectionDisabled** | optionnel | <p>Définissez à `true` pour désactiver la collecte et le partage de l'adresse IP de l'utilisateur.</p><p>La valeur par défaut est `false`.</p> | ### Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Vous devez configurer le module AdaptyUI uniquement si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder) : ```dart showLineNumbers title="Dart" try { final mediaCache = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB ); await AdaptyUI().activate( configuration: AdaptyUIConfiguration(mediaCache: mediaCache), observer: <AdaptyUIObserver Implementation>, ); } catch (e) { // handle the error } ``` Notez que la configuration d'AdaptyUI est optionnelle : vous pouvez activer le module AdaptyUI sans sa configuration. Cependant, si vous utilisez la configuration, tous les paramètres y sont requis. Paramètres : | Paramètre | Présence | Description | | :------------------------------ | :------- | :----------------------------------------------------------- | | **memoryStorageTotalCostLimit** | requis | Limite de coût total du stockage en octets. | | **memoryStorageCountLimit** | requis | Limite du nombre d'éléments dans le stockage en mémoire. | | **diskStorageSizeLimit** | requis | Limite de taille des fichiers sur le disque du stockage en octets. 0 signifie aucune limite. | --- # End of Documentation _Generated on: 2026-08-04T15:08:26.011Z_ _Successfully processed: 53/53 files_ # IOS - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:26.013Z Total files: 53 --- # File: ios-sdk-overview --- --- title: "Présentation du SDK iOS" description: "Découvrez le SDK iOS d'Adapty et ses fonctionnalités clés." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-iOS.svg?style=flat&logo=apple)](https://github.com/adaptyteam/AdaptySDK-iOS/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le SDK iOS d'Adapty pour vous libérer de la complexité des achats intégrés, afin que vous puissiez vous concentrer sur ce que vous faites le mieux : créer des applications formidables. Voici ce que nous gérons pour vous : - Traitement des achats, validation des reçus et gestion des abonnements prêts à l'emploi - Création et test de flows et de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans configuration — cohortes, LTV, churn et analyse d'entonnoir inclus - Statut d'abonnement utilisateur toujours à jour entre les sessions et les appareils - Intégration de votre application avec des services d'attribution marketing et d'analyse en une seule ligne de code :::note Avant de plonger dans le code, vous devez intégrer Adapty avec App Store Connect et configurer vos produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Démarrer \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons couvrir dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-ios) : Ajoutez le SDK comme dépendance à votre projet et activez-le dans le code. 2. [Activer les achats via des flows](ios-quickstart-paywalls) : Configurez le flow d'achat pour que les utilisateurs puissent acheter des produits. Pour créer votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](ios-quickstart-manual). 3. [Vérifier le statut d'abonnement](ios-check-subscription-status) : Vérifiez automatiquement l'état d'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (optionnel)](ios-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir que leurs données sont stockées de façon cohérente sur tous les appareils. ### Voir en action \{#see-it-in-action\} Vous voulez voir comment tout s'assemble ? Nous avons ce qu'il vous faut : - **Exemples d'applications** : Consultez nos [exemples complets](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples) qui illustrent la configuration complète ## Concepts principaux \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts clés qui font fonctionner Adapty. L'approche d'Adapty repose sur un principe simple : seuls les placements sont codés en dur dans votre application. Tout le reste — produits, designs de paywalls, tarifs et offres — peut être géré de façon flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre application : abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Des produits regroupés avec une configuration, rattachés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, créée dans le Flow Builder. Adapty affiche l'interface et gère l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous créez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](ios-quickstart-manual). Dans le code du SDK, les deux sont récupérés via la même méthode `getFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Considérez les placements comme le « où » et le « quand » de votre stratégie de monétisation. Les placements courants comprennent : - `main` - L'emplacement principal de votre paywall - `onboarding` - Affiché pendant le flow d'onboarding de l'utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits de votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque les utilisateurs achètent un produit, leur profil se voit attribuer un **niveau d'accès** que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-ios --- --- title: "Installer et configurer le SDK iOS" description: "Guide étape par étape pour installer le SDK Adapty sur iOS pour les applications à abonnement." --- Le SDK Adapty comprend deux modules clés pour une intégration fluide dans votre application mobile : - **Core Adapty** : ce SDK essentiel est requis pour qu'Adapty fonctionne correctement dans votre application. - **AdaptyUI** : ce module optionnel est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [applications exemples](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Pour une présentation complète de l'implémentation, vous pouvez également regarder les vidéos : <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="iOS (SwiftUI)" default> <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/cSChHc8k2zA?si=KhNFhqXccIzYwTcm" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> </TabItem> <TabItem value="uikit" label="iOS (UIKit)" default> <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/WEUnlaAjSI0?si=sjXKVVb56tEHDKzJ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> </TabItem> </Tabs> ## Prérequis \{#requirements\} Le SDK Adapty pour iOS nécessite iOS 15.0 ou version ultérieure. :::important Adapty SDK 3.15.7+ est requis lors de la compilation avec Xcode 26.4 ou version ultérieure. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-iOS.svg?style=flat&logo=apple)](https://github.com/adaptyteam/AdaptySDK-iOS/releases) Le SDK Adapty s'installe via Swift Package Manager. Dans Xcode, allez dans **File** -> **Add Package Dependency...**. Notez que les étapes pour ajouter des dépendances de package peuvent varier selon les versions d'Xcode ; consultez la documentation Xcode si nécessaire. 1. Saisissez l'URL du dépôt : ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. Sélectionnez la version (la dernière version stable est recommandée) et cliquez sur **Add Package**. 3. Dans la fenêtre **Choose Package Products**, sélectionnez les modules dont vous avez besoin : - **Adapty** (module principal) - **AdaptyUI** (facultatif - uniquement si vous prévoyez d'utiliser Paywall Builder) :::note Remarque : - Pour activer le [Mode Enfants](kids-mode) dans SDK 3.x, sélectionnez **Adapty_KidsMode** à la place de **Adapty**. Dans SDK 4.0 et versions ultérieures, sélectionnez les modules habituels — le Mode Enfants est activé via le trait de package `KidsMode`. - Ne sélectionnez pas d'autres packages dans la liste — vous n'en aurez pas besoin. ::: 4. Cliquez sur **Add Package** pour terminer l'installation. 5. **Vérifiez l'installation :** dans le navigateur de projet, vous devriez voir « Adapty » (et « AdaptyUI » si sélectionné) sous **Package Dependencies**. ## Activer le module Adapty du SDK \{#activate-adapty-module-of-adapty-sdk\} Activez le SDK dans le code de votre application. :::note Le SDK n'a besoin d'être activé qu'une seule fois dans votre application. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard Adapty.logLevel = .verbose // recommended for development and the first production release let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` </TabItem> <TabItem value="swift" label="UIKit" default> ```swift showLineNumbers // In your AppDelegate class: // If you only use an AppDelegate, place the following code in the // application(_:didFinishLaunchingWithOptions:) method. // If you use a SceneDelegate, place the following code in the // scene(_:willConnectTo:options:) method. Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(logLevel: .verbose) // recommended for development and the first production release let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> :::important Attendez que `activate` soit résolu avant d'appeler toute autre méthode du SDK Adapty. Consultez [l'ordre des appels dans le SDK iOS](ios-sdk-call-order) pour la séquence complète. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), commencez par [activer le module AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) ci-dessous, puis suivez le [démarrage rapide avec Paywall Builder](ios-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [démarrage rapide pour les paywalls personnalisés](ios-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder) et avez [installé le module AdaptyUI](sdk-installation-ios#install-adapty-sdk), vous devez également activer AdaptyUI. :::important Dans votre code, vous devez activer le module principal Adapty avant d'activer AdaptyUI. ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers title="Swift" @main struct YourApp: App { init() { // ...ConfigurationBuilder steps // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } // main body... } } ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift showLineNumbers title="UIKit" // If you only use an AppDelegate, place the following code in the // application(_:didFinishLaunchingWithOptions:) method. // If you use a SceneDelegate, place the following code in the // scene(_:willConnectTo:options:) method. Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(logLevel: .verbose) // recommended for development let config = configurationBuilder.build() try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> :::tip En option, lors de l'activation d'AdaptyUI, vous pouvez [remplacer les paramètres de mise en cache par défaut pour les paywalls](#media-cache-configuration-for-paywalls-in-adaptyui). ::: ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Seules les erreurs seront journalisées | | `warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais qui méritent attention, seront journalisés | | `info` | Les erreurs, avertissements et divers messages d'information seront journalisés | | `verbose` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc. sera journalisée | ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(logLevel: .verbose) // recommended for development ``` #### Rediriger les messages du système de journalisation \{#redirect-the-logging-system-messages\} Si vous avez besoin d'envoyer les messages de log d'Adapty vers votre propre système ou de les sauvegarder dans un fichier, utilisez la méthode `setLogHandler` et implémentez votre logique de journalisation personnalisée à l'intérieur. Ce gestionnaire reçoit des enregistrements de log contenant le contenu du message et son niveau de sévérité. ```swift showLineNumbers title="Swift" Adapty.setLogHandler { record in writeToLocalFile("Adapty \(record.level): \(record.message)") } ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs à moins que vous ne les envoyiez explicitement, mais vous pouvez mettre en place des politiques de sécurité des données supplémentaires pour vous conformer aux directives du store ou du pays concerné. #### Désactiver la collecte et le partage de l'IDFA \{#disable-idfa-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `idfaCollectionDisabled` sur `true` pour désactiver la collecte et le partage de l'IDFA. Utilisez ce paramètre pour respecter les directives de l'App Store Review Guidelines ou éviter de déclencher l'invite App Tracking Transparency lorsque l'IDFA n'est pas nécessaire pour votre application. La valeur par défaut est `false`. Pour plus d'informations sur la collecte de l'IDFA, consultez la section [Intégration Analytics](analytics-integration#disable-collection-of-advertising-identifiers). ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(idfaCollectionDisabled: true) ``` #### Désactiver la collecte et le partage de l'adresse IP \{#disable-ip-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` sur `true` pour désactiver la collecte et le partage de l'adresse IP de l'utilisateur. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, respecter les réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'IP ne sont pas nécessaires pour votre application. ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(ipAddressCollectionDisabled: true) ``` #### Configuration du cache multimédia pour les paywalls dans AdaptyUI \{#media-cache-configuration-for-paywalls-in-adaptyui\} Notez que la configuration d'AdaptyUI est optionnelle. Vous pouvez activer le module AdaptyUI sans configuration. Cependant, si vous utilisez la configuration, tous les paramètres sont obligatoires. ```swift showLineNumbers title="Swift" // Configure AdaptyUI let adaptyUIConfiguration = AdaptyUI.Configuration( mediaCacheConfiguration: .init( memoryStorageTotalCostLimit: 100 * 1024 * 1024, memoryStorageCountLimit: .max, diskStorageSizeLimit: 100 * 1024 * 1024 ) ) // Activate AdaptyUI AdaptyUI.activate(configuration: adaptyUIConfiguration) ``` Paramètres : | Paramètre | Présence | Description | | :-------------------------- | :------- | :----------------------------------------------------------- | | memoryStorageTotalCostLimit | requis | Limite de coût total du stockage en octets. | | memoryStorageCountLimit | requis | Limite du nombre d'éléments dans le stockage en mémoire. | | diskStorageSizeLimit | requis | Limite de taille de fichier sur le disque en octets. 0 signifie aucune limite. | ### Comportement de finalisation des transactions \{#transaction-finishing-behavior\} :::info Cette fonctionnalité est disponible à partir de la version 3.12.0 du SDK. ::: Par défaut, Adapty finalise automatiquement les transactions après leur validation. Cependant, si vous avez besoin d'une validation avancée (validation côté serveur, détection de fraude ou logique métier personnalisée), vous pouvez configurer le SDK pour utiliser la finalisation manuelle des transactions. ```swift showLineNumbers title="Swift" let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(transactionsFinishBehavior: .manual) // .auto is the default ``` Pour plus de détails sur la façon de finaliser les transactions, consultez le [guide](ios-transaction-management). ### Effacer les données lors d'une restauration de sauvegarde \{#clear-data-on-backup-restore\} Lorsque `clearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, y compris les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état propre. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(clearDataOnBackup: true) // default – false ``` ## Dépannage \{#troubleshooting\} #### Erreur de concurrence Swift 6 avec Tuist \{#swift-6-concurrency-error-with-tuist\} Lors d'une compilation avec [Tuist](https://tuist.dev/), vous pouvez rencontrer des erreurs de compilation liées à la concurrence stricte de Swift 6. Les symptômes typiques incluent des incompatibilités d'attribut `@Sendable` dans `AdaptyUIBuilderLogic` ou des erreurs de Sendability similaires entre modules. Cela se produit parce que Tuist génère des projets Xcode à partir de packages SPM mais ne conserve pas le paramètre `swift-tools-version: 6.0`. En conséquence, certaines cibles Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`) compilent avec les règles Swift 5 tandis que d'autres utilisent Swift 6, ce qui crée des incompatibilités `@Sendable` entre modules. **Correction** : Mettez à niveau vers Adapty SDK **3.15.5** ou une version ultérieure, ce qui résout le problème indépendamment des versions mixtes du langage Swift. **Solution de contournement** : Si vous ne pouvez pas effectuer la mise à niveau, définissez explicitement Swift 6 pour les trois cibles Adapty dans votre configuration Tuist : ```swift showLineNumbers targetSettings: [ "Adapty": .init().swiftVersion("6"), "AdaptyUI": .init().swiftVersion("6"), "AdaptyUIBuilder": .init().swiftVersion("6"), ] ``` --- # File: ios-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK iOS" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez plutôt un paywall — voir [Implémenter des paywalls manuellement](ios-quickstart-manual). - [**Placements**](placements) – où et quand afficher les flows dans votre app (par exemple `main`, `onboarding`, `settings`). Vous associez des flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre app. Choisissez celle qui correspond à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère l'intégralité du flux d'achat, la validation des reçus et la gestion des abonnements en coulisses. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre app, mais récupérez quand même l'objet flow depuis Adapty pour conserver de la flexibilité dans les offres de produits. Voir le [guide](ios-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limitations dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.** Si vous préférez construire l'interface du paywall vous-même, voir [Implémenter des paywalls manuellement](ios-quickstart-manual). ::: Pour afficher un flow créé dans Adapty Flow Builder, vous n'avez besoin que de : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre app. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre app. Par exemple, ouvrez des liens ou fermez le flow lorsque les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. [Connectez votre app à l'App Store](initial_ios) dans l'Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-ios) dans votre code. Ce guide utilise les APIs du SDK Adapty iOS v4. ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter des flows différents pour différentes audiences ou de lancer des [tests A/B](ab-tests). Pour obtenir un flow créé dans Adapty Flow Builder, vous devez : 1. Récupérer l'objet `flow` par l'ID du [placement](placements) via la méthode `getFlow` et vérifier qu'il dispose d'une configuration de vue. 2. Obtenir la configuration de vue via la méthode `getFlowConfiguration`. Elle contient les éléments d'interface et le style nécessaires pour afficher le flow. ```swift func loadFlow() async { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } ``` ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez la configuration du flow, quelques lignes suffisent pour l'afficher. <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> En SwiftUI, lors de l'affichage du flow, vous devez également gérer les événements. `didFinishPurchase`, `didFailPurchase`, `didFinishRestore`, `didFailRestore` et `didReceiveError` sont obligatoires. Pour les tests, vous pouvez simplement copier le code du snippet ci-dessous pour journaliser ces événements. :::tip Le flow ne se ferme pas automatiquement après un achat réussi. Dans `didFinishPurchase`, passez votre binding de présentation à `false` pour le fermer, ou ne faites rien pour laisser le flow continuer vers les écrans suivants. ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didFinishPurchase: { product, purchaseResult in print("Purchase finished successfully") flowPresented = false // or do nothing to let the flow continue }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in flowPresented = false print("Flow error: \(error)") } ) ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift func presentFlow(with config: AdaptyUI.FlowConfiguration) { let flowController = try AdaptyUI.flowController( with: config, delegate: self ) present(flowController, animated: true) } ``` Implémentez `AdaptyFlowControllerDelegate` pour gérer les événements. Au minimum, implémentez les quatre méthodes sans implémentation par défaut. Notez que le contrôleur ne se ferme pas tout seul après un achat réussi — fermez-le dans `didFinishPurchase`, ou ne faites rien pour laisser le flow continuer vers les écrans suivants : ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } } ``` </TabItem> </Tabs> :::info Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](ios-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Lorsque les utilisateurs cliquent sur des boutons, le SDK iOS gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des liens. Cependant, d'autres boutons ont des identifiants personnalisés ou prédéfinis et nécessitent une gestion dans votre code. Vous pouvez également vouloir remplacer leur comportement par défaut. Par exemple, voici comment gérer le bouton de fermeture. En UIKit, le SDK ferme le contrôleur automatiquement lorsque `.close` se déclenche — ne surchargez que si vous souhaitez un comportement personnalisé. En SwiftUI, vous devez passer votre binding `isPresented` à `false` vous-même. :::tip Consultez nos guides sur la gestion des [actions](handle-paywall-actions) et des [événements](ios-handling-events) des boutons. ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow when the user taps close default: break } }, didFinishPurchase: { product, purchaseResult in flowPresented = false }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior — override only if needed default: break } } } ``` </TabItem> </Tabs> ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'app. [Testez vos achats en mode sandbox](test-purchases-in-sandbox) pour vous assurer de pouvoir effectuer un achat de test. Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](ios-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment toutes les étapes de ce guide peuvent être intégrées ensemble dans votre app. <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> ```swift struct ContentView: View { @State private var flowPresented = false @State private var flowConfiguration: AdaptyUI.FlowConfiguration? @State private var isLoading = false @State private var hasInitialized = false var body: some View { VStack { if isLoading { ProgressView("Loading...") } else { Text("Your App Content") } } .task { guard !hasInitialized else { return } await initializeFlow() hasInitialized = true } .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFinishPurchase: { product, purchaseResult in print("Purchase finished successfully") flowPresented = false // or do nothing to let the flow continue }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in print("Flow error: \(error)") flowPresented = false } ) } private func initializeFlow() async { isLoading = true defer { isLoading = false } await loadFlow() flowPresented = true } private func loadFlow() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } catch { print("Failed to load: \(error)") } } } ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift class ViewController: UIViewController { private var flowConfiguration: AdaptyUI.FlowConfiguration? override func viewDidLoad() { super.viewDidLoad() Task { await initializeFlow() } } private func initializeFlow() async { do { flowConfiguration = try await loadFlow() if let flowConfiguration { await MainActor.run { presentFlow(with: flowConfiguration) } } } catch { print("Error initializing: \(error)") } } private func loadFlow() async throws -> AdaptyUI.FlowConfiguration? { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return nil } return try await AdaptyUI.getFlowConfiguration(forFlow: flow) } private func presentFlow(with config: AdaptyUI.FlowConfiguration) { guard let flowController = try? AdaptyUI.flowController( with: config, delegate: self ) else { return } present(flowController, animated: true) } } extension ViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed for \(product.vendorProductId): \(error)") guard error.adaptyErrorCode != .paymentCancelled else { return } let message = switch error.adaptyErrorCode { case .paymentNotAllowed: "Purchases are not allowed on this device." default: "Purchase failed. Please try again." } let alert = UIAlertController(title: "Purchase Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") controller.dismiss(animated: true) } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError) { print("Flow error: \(error)") controller.dismiss(animated: true) } } ``` </TabItem> </Tabs> --- # File: ios-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK iOS" description: "Découvrez comment vérifier le statut d'abonnement dans votre application iOS avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — s'il faut leur afficher un paywall ou leur accorder l'accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appelez `getProfile` si vous avez besoin des données de profil les plus récentes immédiatement (par exemple au lancement de l'application) ou si vous souhaitez forcer une mise à jour. - Configurez des **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement dès que le statut d'abonnement change. :::important Par défaut, le niveau d'accès `premium` existe déjà dans Adapty. Si vous n'avez pas besoin de configurer plus d'un niveau d'accès, vous pouvez simplement utiliser `premium`. ::: ### Récupérer le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> </Tabs> ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Si vous souhaitez recevoir automatiquement les mises à jour du profil dans votre application : 1. Conformez un type de votre choix au protocole `AdaptyDelegate` et implémentez la méthode `didLoadLatestProfile` — Adapty appellera automatiquement cette méthode dès que le statut d'abonnement de l'utilisateur change. Dans l'exemple ci-dessous, nous utilisons un type `SubscriptionManager` pour gérer les flux d'abonnement et le profil de l'utilisateur. Ce type peut être injecté en tant que dépendance ou configuré comme singleton dans une application UIKit, ou ajouté à l'environnement SwiftUI depuis la structure principale de l'application. 2. Stockez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser dans toute votre application sans effectuer de requêtes réseau supplémentaires. ```swift class SubscriptionManager: AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { let hasAccess = profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false // Update UI, unlock content, etc. } } // Set delegate after Adapty activation Adapty.delegate = subscriptionManager ``` :::note Adapty appelle automatiquement `didLoadLatestProfile` au démarrage de votre application, fournissant les données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Connecter le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates concernant l'affichage de paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'accès à des sections premium, ou avant d'afficher un contenu spécifique. <Tabs> <TabItem value="swiftui" label="SwiftUI" default> ```swift private func checkAccessLevel() async -> Bool { do { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } catch { print("Error checking access level: \(error)") return false } } // In your initialization logic: let hasAccess = await checkAccessLevel() if !hasAccess { paywallPresented = true // Show paywall if no access } ``` </TabItem> <TabItem value="uikit" label="UIKit"> ```swift private func checkAccessLevel() async throws -> Bool { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } // In your initialization logic: let hasAccess = try await checkAccessLevel() if !hasAccess { presentPaywall(with: paywallConfiguration) } ``` </TabItem> </Tabs> ## Étapes suivantes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, [découvrez comment travailler avec les profils utilisateurs](ios-quickstart-identify) pour vous assurer qu'il s'aligne avec votre système d'authentification existant et les autorisations de partage d'accès payant. Si vous n'avez pas votre propre système d'authentification, ce n'est pas un problème, Adapty gérera les utilisateurs pour vous, mais vous pouvez quand même lire le [guide](ios-quickstart-identify) pour comprendre comment Adapty fonctionne avec les utilisateurs anonymes. --- # File: ios-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK iOS" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés." --- :::important Ce guide vous concerne si vous disposez de votre propre système d'authentification. Vous y apprendrez comment travailler avec les profils utilisateur dans Adapty afin de les aligner avec votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez le **customer user ID** pour faire le lien entre les profils Adapty et votre système d'authentification interne. Voici les différences entre utilisateurs anonymes et identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil sur toutes les sessions et tous les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'app | Les données des utilisateurs identifiés persistent entre les installations | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lors de l'activation du SDK au premier lancement de l'app, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'app, cet achat est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'app ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme lors de l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, ses achats sont automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. :::note Les restaurations depuis une sauvegarde se comportent différemment des réinstallations. Par défaut, lorsqu'un utilisateur restaure depuis une sauvegarde, le SDK conserve les données en cache et ne crée pas de nouveau profil. Vous pouvez configurer ce comportement avec le paramètre `clearDataOnBackup`. [En savoir plus](sdk-installation-ios#clear-data-on-backup-restore). ::: Ainsi, avec des utilisateurs anonymes, de nouveaux profils seront créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. ## Utilisateurs identifiés \{#identified-users\} Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils ont un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après qu'ils se soient connectés ou inscrits), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez pas encore utilisé ce customer user ID**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez en dur la valeur du paramètre, tous les utilisateurs seront considérés comme un seul. ::: Attendez toujours que `identify` soit résolu (`await`) avant d'appeler d'autres méthodes du SDK. Les appels simultanés produisent l'erreur `#3006 profileWasChanged` ou atterrissent sur le profil anonyme. Voir [Ordre des appels dans le SDK iOS](ios-sdk-call-order). <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> </Tabs> ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID au moment d'activer le SDK, vous pouvez l'inclure dans la méthode `activate` plutôt que d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`. Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé) ou un nouveau. Si vous en passez un nouveau, le profil créé lors de l'activation sera automatiquement lié à ce customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées en fonction des ID d'appareils. Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'app. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une nouvelle installation, ni de l'utilisation d'un customer user ID existant. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'app sans réinstallation ne génère pas d'événements d'installation supplémentaires. Si vous souhaitez compter les installations en fonction des utilisateurs uniques plutôt que des appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` </TabItem> </Tabs> ### Déconnecter les utilisateurs \{#log-users-out\} Si votre application dispose d'un bouton de déconnexion, utilisez la méthode `logout`. :::important La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` </TabItem> </Tabs> :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur non connecté effectue un achat, Adapty le lie à son ID de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (déjà lié à un profil), vous devez récupérer le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](ios-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](ios-check-subscription-status) pour que les données se synchronisent automatiquement. ## Prochaines étapes \{#next-steps\} Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre app ! Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](test-purchases-in-sandbox) : Vérifiez que tout fonctionne comme prévu - [**Onboardings**](ios-onboardings) : Engagez vos utilisateurs avec des onboardings et favorisez la rétention - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code - [**Définir des attributs de profil personnalisés**](setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateur et créez des segments pour lancer des tests A/B ou afficher des paywalls différents selon les utilisateurs --- # File: adapty-sdk-integration-skill --- --- title: "Intégrer Adapty dans votre application iOS avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application iOS de bout en bout avec votre outil de codage IA." --- :::important La compétence est en bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor) à la place — il guide votre outil IA à travers chaque étape avec la bonne documentation. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor --- --- title: "Intégrer Adapty dans votre app iOS avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre app iOS avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre app iOS avec un outil de codage IA — vous lui fournissez la bonne documentation Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite une configuration dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire avec un skill LLM interactif, ou manuellement via le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre app, vos produits, niveaux d'accès, paywalls et placements directement — sans avoir à ouvrir le Dashboard à chaque étape. Vous devez uniquement [connecter votre store](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris pour savoir quand ouvrir le Dashboard afin de connecter votre store. ### Approche manuelle \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir. 1. **Connectez votre app store** : Dans l'Adapty Dashboard, allez dans **App settings → General**. C'est indispensable pour que les achats fonctionnent. [Connecter l'App Store](integrate-payments) 2. **Copiez votre clé SDK publique** : Dans l'Adapty Dashboard, allez dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez à `Adapty.activate("YOUR_PUBLIC_SDK_KEY")`. 3. **Créez au moins un produit** : Dans l'Adapty Dashboard, rendez-vous sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les transmet via des flows ou des paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un flow ou un paywall et un placement** : Dans l'Adapty Dashboard, créez un flow (ou un paywall si vous construisez l'interface vous-même), puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID de placement est la chaîne que vous passez à `Adapty.getFlow("YOUR_PLACEMENT_ID")`. [Créer un flow](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : Dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels["premium"]`. Le niveau d'accès `premium` par défaut convient à la plupart des apps. Si les utilisateurs payants ont accès à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` vs. un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Dites à votre LLM : « Ma clé SDK publique est X, mon ID de placement est Y » pour qu'il puisse générer le bon code d'initialisation et de récupération du paywall. ::: ### À configurer quand vous êtes prêt \{#set-up-when-ready\} Ces éléments ne sont pas indispensables pour commencer à coder, mais vous en aurez besoin au fur et à mesure que votre intégration évolue : - **Tests A/B** : Configurez-les sur la page **Placements**. Aucun changement de code requis. [Tests A/B](ab-tests) - **Flows et placements supplémentaires** : Ajoutez d'autres appels `getFlow` avec différents IDs de placement. - **Intégrations analytics** : Configurez-les sur la page **Integrations**. La procédure varie selon l'intégration. Voir [intégrations analytics](analytics-integration) et [intégrations attribution](attribution-integration). ## Fournir la documentation Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bons docs en fonction de vos questions — pas besoin de coller des URLs manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, lancez : ``` npx ctx7 setup ``` Cela détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub de Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the iOS SDK ``` :::warning Même si Context7 évite de coller des liens manuellement, l'ordre d'implémentation est important. Suivez le [parcours d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour que tout fonctionne correctement. ::: ### Utiliser les docs en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle page de documentation Adapty en texte brut Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor.md](https://adapty.io/docs/fr/adapty-cursor.md). Chaque étape du [parcours d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc « À envoyer à votre LLM » avec des liens `.md` à coller. Pour accéder à plus de documentation en une fois, consultez les [fichiers index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Parcours d'implémentation \{#implementation-walkthrough\} La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devriez voir une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de plonger dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode de planification (comme le mode plan de Cursor ou de Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire du code. Indiquez à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides à suivre : - [**Adapty Flow Builder**](adapty-flow-builder) : Vous créez des flows dans le builder no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](ios-quickstart-manual) : Vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats. - [**Mode Observer**](observer-vs-full-mode) : Vous conservez votre infrastructure d'achats existante et utilisez Adapty uniquement pour les analytics et les intégrations. Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le quickstart](ios-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Installez le package SDK Adapty via Swift Package Manager dans Xcode et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionnera sans ça. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-ios) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-ios.md ``` :::tip[Checkpoint] - **Attendu :** L'app se build et se lance. La console Xcode affiche le log d'activation d'Adapty. - **Piège :** « Public API key is missing » → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings. ::: ### Afficher les flows ou paywalls et gérer les achats \{#show-flows-or-paywalls-and-handle-purchases\} Récupérez un flow ou un paywall par son ID de placement, affichez-le et gérez les événements d'achat. Les guides nécessaires dépendent de votre approche pour les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Flow Builder" default> **Guides :** - [Activer les achats avec Flow Builder (quickstart)](ios-quickstart-paywalls) - [Récupérer les flows et leur configuration](get-pb-paywalls) - [Afficher les flows](ios-present-paywalls) - [Gérer les événements de flow](ios-handling-events) - [Répondre aux actions des boutons](handle-paywall-actions) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/ios-quickstart-paywalls.md - https://adapty.io/docs/fr/get-pb-paywalls.md - https://adapty.io/docs/fr/ios-present-paywalls.md - https://adapty.io/docs/fr/ios-handling-events.md - https://adapty.io/docs/fr/handle-paywall-actions.md ``` :::tip[Checkpoint] - **Attendu :** Le flow s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Piège :** Flow vide ou erreur `getFlow` → vérifiez que l'ID de placement correspond exactement à celui du tableau de bord et que le placement a une audience assignée. ::: </TabItem> <TabItem value="manual" label="Paywalls manuels"> **Guides :** - [Activer les achats dans votre paywall personnalisé (quickstart)](ios-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products) - [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls) - [Effectuer des achats](making-purchases) - [Restaurer les achats](restore-purchase) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/ios-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products.md - https://adapty.io/docs/fr/present-remote-config-paywalls.md - https://adapty.io/docs/fr/making-purchases.md - https://adapty.io/docs/fr/restore-purchase.md ``` :::tip[Checkpoint] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Piège :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Mode Observer"> **Guides :** - [Vue d'ensemble du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode) - [Signaler les transactions en mode Observer](report-transactions-observer-mode) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode.md - https://adapty.io/docs/fr/report-transactions-observer-mode.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty. - **Piège :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les App Store Server Notifications sont configurées. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez le profil utilisateur pour détecter un niveau d'accès actif et restreindre le contenu premium. **Guide :** [Vérifier le statut de l'abonnement](ios-check-subscription-status) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/ios-check-subscription-status.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox, `profile.accessLevels["premium"]?.isActive` retourne `true`. - **Piège :** `accessLevels` vide après un achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Liez les comptes utilisateurs de votre app aux profils Adapty pour que les achats persistent sur tous les appareils. :::important Ignorez cette étape si votre app ne gère pas l'authentification. ::: **Guide :** [Identifier les utilisateurs](ios-quickstart-identify) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/ios-quickstart-identify.md ``` :::tip[Checkpoint] - **Attendu :** Après avoir appelé `Adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Piège :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution au profil anonyme. ::: ### Préparer la mise en production \{#prepare-for-release\} Une fois votre intégration validée en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt. **Guide :** [Checklist de mise en production](release-checklist) À envoyer à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Checkpoint] - **Attendu :** Tous les éléments de la checklist sont confirmés : connexion au store, notifications serveur, flux d'achat, vérifications des niveaux d'accès et exigences de confidentialité. - **Piège :** App Store Server Notifications manquantes → configurez-les dans **App settings → iOS SDK** sinon les événements n'apparaîtront pas dans le tableau de bord. ::: ## Fichiers index de documentation en texte brut \{#plain-text-doc-index-files\} Si vous avez besoin de donner à votre LLM un contexte plus large au-delà des pages individuelles, nous hébergeons des fichiers index qui listent ou regroupent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : Liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par ex. ChatGPT), vous devrez télécharger `llms.txt` et le joindre au chat en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : L'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement quand vous avez besoin de la vue d'ensemble complète. - Sous-ensembles spécifiques iOS [`ios-llms.txt`](https://adapty.io/docs/fr/ios-llms.txt) et [`ios-llms-full.txt`](https://adapty.io/docs/fr/ios-llms-full.txt) : Des sous-ensembles par plateforme qui économisent des tokens par rapport au site complet. --- # File: ios-paywalls --- --- title: "Flows et paywalls - iOS" description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre app iOS." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['get-pb-paywalls', 'ios-present-paywalls', 'ios-handling-events', 'handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](ios-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['ios-quickstart-manual', 'fetch-paywalls-and-products', 'present-remote-config-paywalls', 'making-purchases']} /> Pour plus de guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](ios-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['ios-use-fallback-paywalls', 'localizations-and-locale-codes', 'ios-web-paywall']} /> --- # File: get-pb-paywalls --- --- title: "Récupérer les flows et paywalls - iOS" description: "Récupérez les flows et paywalls depuis Adapty dans votre app iOS." --- <SDKv4> <MethodPromo method="getFlow" /> Après avoir [conçu votre flow ou votre paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre app mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration de vue, comme décrit ci-dessous. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une app mobile ? Consultez nos [apps d'exemple](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-ios) dans votre app mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre app mobile. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. Vous devez néanmoins récupérer son ID via le placement, sa configuration de vue, puis le présenter dans votre app mobile. Récupérez le flow ou le paywall et sa [configuration de vue](get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible — idéalement bien avant de l'afficher. Dès que vous récupérez la configuration de vue, le SDK commence à télécharger et mettre en cache ses images en arrière-plan. Plus vous la récupérez tôt, plus ces téléchargements ont le temps de se terminer. Au moment d'afficher le flow ou le paywall, sa configuration et ses images peuvent déjà être en cache et prêtes à l'emploi. Pour récupérer un flow ou un paywall, utilisez la méthode `getFlow` : <Tabs> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow/paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow/paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé au redémarrage de l'app et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 s | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en interne.</p> | Paramètres de réponse : | Paramètre | Description | | :-------- | :---------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, les Remote Configs et un indicateur `hasViewConfiguration` précisant si le flow inclut une configuration de vue. Pour récupérer les produits réels en vue d'un préchargement, d'une interface personnalisée ou de vérifications programmatiques, appelez `getPaywallProducts(flow:)`. | ## Récupérer la configuration de vue \{#fetch-the-view-configuration\} Après avoir récupéré le flow ou le paywall, vérifiez s'il inclut une configuration de vue via `flow.hasViewConfiguration`. Cet indicateur distingue la façon dont le placement a été conçu dans l'Adapty Dashboard : - **`true`** — le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall). Adapty génère l'interface pour vous. Continuez avec les étapes ci-dessous pour récupérer la configuration de vue et [présenter le flow ou le paywall](ios-present-paywalls). - **`false`** — le placement est un paywall personnalisé sans interface Builder. Utilisez la méthode `getFlowConfiguration` pour charger la configuration de vue. ```swift showLineNumbers guard flow.hasViewConfiguration else { // handle as remote config paywall return } let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) ``` Paramètres : | Paramètre | Présence | Description | | :----------------------- | :------------- | :---------- | | **forFlow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | | **locale** | <p>optionnel</p><p>par défaut : `nil`</p> | L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Attendu sous la forme d'un code de langue avec un ou deux sous-tags séparés par `-` (ex. : `en`, `pt-br`). Voir [Localisations et codes de langue](localizations-and-locale-codes). | | **loadTimeout** | par défaut : 5 s | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en interne. | | **products** | optionnel | Fournissez un tableau d'objets `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | | **systemRequestsHandler** | optionnel | Un objet conforme à `AdaptySystemRequestsHandler` qui gère les demandes d'autorisations système et d'évaluation déclenchées par les actions du flow. Requis uniquement si votre flow inclut de telles actions. | | **assetsResolver** | optionnel | Un dictionnaire `[String: AdaptyCustomAsset]` qui remplace les images et vidéos dans le flow/paywall. Voir [Personnaliser les assets](#customize-assets). | | **timerResolver** | optionnel | Un objet conforme à `AdaptyTimerResolver` qui fournit les dates de fin pour les timers définis par le développeur. Voir [Configurer les timers définis par le développeur](#set-up-developer-defined-timers). | Une fois chargé, [présentez le flow/paywall](ios-present-paywalls). ## Récupérer un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs ont une connexion lente, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer le flow ou le paywall avec la méthode `getFlow`, comme indiqué dans la section [Récupérer un flow/paywall](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'app (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment basé sur les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow ou du paywall, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, utilisez `getFlow` décrit [ci-dessus](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé au redémarrage de l'app et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p> | ## Personnaliser les assets \{#customize-assets\} Pour personnaliser les images et vidéos dans votre paywall/flow, implémentez les assets personnalisés. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle d'assets personnalisés, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. - Fournir la résolution en pixels d'une vidéo afin que le lecteur réserve l'espace de mise en page (ratio = `width / height`) avant le chargement de la vidéo. Passez `nil` pour ignorer cela. Voici un exemple de fourniture d'assets personnalisés via un simple dictionnaire : ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image and a known resolution "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!), resolution: CGSize(width: 1080, height: 1920) ) ), ] let flowConfig = try await AdaptyUI.getFlowConfiguration( forFlow: flow, assetsResolver: customAssets ) ``` :::note Si un asset est introuvable, le paywall/flow utilisera son apparence par défaut. ::: ## Configurer les timers définis par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des timers personnalisés dans votre app mobile, créez un objet conforme au protocole `AdaptyTimerResolver`. Cet objet définit comment chaque timer personnalisé doit être rendu. Si vous préférez, vous pouvez utiliser directement un dictionnaire `[String: Date]`, car il est déjà conforme à ce protocole. Voici un exemple : ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID** des timers définis par le développeur que vous avez configurés dans l'Adapty Dashboard. Le `timerResolver` garantit que votre app met à jour dynamiquement chaque timer avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin du timer, comme le Nouvel An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures qui a démarré lorsque l'utilisateur a ouvert le paywall. </SDKv4> <SDKv3> Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre app mobile. La première étape consiste à récupérer le paywall associé au placement ainsi que sa configuration de vue, comme décrit ci-dessous. Notez que ce sujet concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez [Récupérer les paywalls et produits pour les paywalls Remote Config](fetch-paywalls-and-products). :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une app mobile ? Consultez nos [apps d'exemple](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des paywalls dans votre app mobile</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-ios) dans votre app mobile. </details> ## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre app mobile. Un tel paywall contient à la fois ce qui doit être affiché et comment l'afficher. Vous devez néanmoins récupérer son ID via le placement, sa configuration de vue, puis le présenter dans votre app mobile. Pour des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les présenter à l'utilisateur. Pour récupérer un paywall, utilisez la méthode `getPaywall` : <Tabs> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Voir [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre façon de les utiliser.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé au redémarrage de l'app et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 s | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en interne.</p> | Paramètres de réponse : | Paramètre | Description | | :-------- | :---------- | | Paywall | Un objet [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) avec une liste d'IDs de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. | ## Récupérer la configuration de vue d'un paywall conçu avec le Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Veillez à activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible à la récupération. ::: Après avoir récupéré le paywall, vérifiez s'il inclut une configuration de vue, ce qui indique qu'il a été créé avec le Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si la configuration de vue est présente, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls). Utilisez la méthode `getPaywallConfiguration` pour charger la configuration de vue. ```swift showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, products: products ) // use loaded configuration } catch { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | :----------------------- | :------------- | :---------- | | **paywall** | requis | Un objet `AdaptyPaywall` pour obtenir un contrôleur pour le paywall souhaité. | | **loadTimeout** | par défaut : 5 s | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en interne. | | **products** | optionnel | Fournissez un tableau d'objets `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](localizations-and-locale-codes). ::: Une fois chargé, [présentez le paywall](ios-present-paywalls). ## Récupérer un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs ont une connexion lente, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour cela, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer le paywall avec la méthode `getPaywall`, comme indiqué dans la section [Récupérer un paywall](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'app (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment basé sur les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du paywall, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, utilisez `getPaywall` décrit [ci-dessus](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.2 du SDK iOS. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Voir [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre façon de les utiliser.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé au redémarrage de l'app et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p> | ## Personnaliser les assets \{#customize-assets\} Pour personnaliser les images et vidéos dans votre paywall, implémentez les assets personnalisés. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle d'assets personnalisés, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK iOS Adapty vers la version 3.7.0 ou supérieure. ::: Voici un exemple de fourniture d'assets personnalisés via un simple dictionnaire : ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!) ) ), ] let paywallConfig = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, assetsResolver: customAssets ) ``` :::note Si un asset est introuvable, le paywall utilisera son apparence par défaut. ::: ## Configurer les timers définis par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des timers personnalisés dans votre app mobile, créez un objet conforme au protocole `AdaptyTimerResolver`. Cet objet définit comment chaque timer personnalisé doit être rendu. Si vous préférez, vous pouvez utiliser directement un dictionnaire `[String: Date]`, car il est déjà conforme à ce protocole. Voici un exemple : ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID** des timers définis par le développeur que vous avez configurés dans l'Adapty Dashboard. Le `timerResolver` garantit que votre app met à jour dynamiquement chaque timer avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin du timer, comme le Nouvel An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures qui a démarré lorsque l'utilisateur a ouvert le paywall. </SDKv3> --- # File: ios-present-paywalls --- --- title: "Afficher les flows & paywalls - iOS" description: "Présentez les flows et paywalls aux utilisateurs dans votre application iOS." --- <SDKv4> <MethodPromo method="getFlow" label="Afficher les flows et paywalls" /> Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. Pour obtenir l'objet `AdaptyUI.FlowConfiguration` utilisé ci-dessous, consultez [Récupérer les flows et paywalls](get-pb-paywalls). ## Présenter les flows et paywalls avec SwiftUI \{#present-flows-and-paywalls-in-swiftui\} ### Présenter comme une vue modale \{#present-as-a-modal-view\} Pour afficher un flow ou un paywall sur l'écran de l'appareil comme une vue modale, utilisez le modificateur `.flow` dans SwiftUI. L'appel minimal requiert `isPresented`, `flowConfiguration` et les cinq callbacks obligatoires : ```swift showLineNumbers title="SwiftUI" .flow( isPresented: $flowPresented, flowConfiguration: <AdaptyUI.FlowConfiguration>, didFinishPurchase: { _, _ in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { _, _ in /* handle the error */ }, didFinishRestore: { _ in /* check access level and dismiss */ }, didFailRestore: { _ in /* handle the error */ }, didReceiveError: { _ in flowPresented = false } ) ``` Pour plus de contrôle, ajoutez des callbacks optionnels comme `didPerformAction` pour gérer les appuis sur les boutons : ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false // ensure that you manage this variable state and set it to `true` at the moment you want to show the flow or paywall var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: <AdaptyUI.FlowConfiguration>, didPerformAction: { action in switch action { case .close: flowPresented = false default: // Handle other actions break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) } ``` Paramètres : | Paramètre | Requis | Description | |:-----------------------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | requis | Un binding qui détermine si l'écran du flow ou du paywall est affiché. | | **flowConfiguration** | requis | Un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow ou du paywall. Utilisez la méthode `AdaptyUI.getFlowConfiguration(forFlow:)`. Consultez [Récupérer les flows et paywalls](get-pb-paywalls) pour plus de détails. | | **didFinishPurchase** | requis | Invoqué lorsque `Adapty.makePurchase()` se termine avec succès. Le flow ne se ferme pas automatiquement — mettez votre binding de présentation à `false` ici, ou ne faites rien pour laisser le flow continuer après l'achat. | | **didFailPurchase** | requis | Invoqué lorsque `Adapty.makePurchase()` échoue. | | **didFinishRestore** | requis | Invoqué lorsque `Adapty.restorePurchases()` se termine avec succès. | | **didFailRestore** | requis | Invoqué lorsque `Adapty.restorePurchases()` échoue. | | **didReceiveError** | requis | Invoqué en cas d'erreur de rendu ou d'erreur d'exécution provenant du script du flow (par exemple, une exception JavaScript, code `AdaptyUIError` `4105`). Pour les erreurs de rendu, [contactez le support Adapty](mailto:support@adapty.io). | | **fullScreen** | optionnel | Détermine si le flow ou le paywall s'affiche en plein écran ou sous forme de feuille. Par défaut : `true`. | | **didAppear** | optionnel | Invoqué lorsque la vue du flow ou du paywall a été présentée. | | **didDisappear** | optionnel | Invoqué lorsque la vue du flow ou du paywall a été fermée. | | **didPerformAction** | optionnel | Invoqué lorsqu'un utilisateur clique sur un bouton. Deux identifiants d'action sont prédéfinis : `close` et `openURL` ; les autres sont personnalisés et peuvent être définis dans le builder. | | **didSelectProduct** | optionnel | Invoqué lorsqu'un produit est sélectionné pour l'achat par l'utilisateur ou par le système. | | **didStartPurchase** | optionnel | Invoqué lorsque l'utilisateur commence le processus d'achat. | | **didFinishWebPaymentNavigation** | optionnel | Invoqué lorsque la navigation de paiement web se termine. | | **didStartRestore** | optionnel | Invoqué lorsque l'utilisateur démarre le processus de restauration. | | **didFailLoadingProducts** | optionnel | Invoqué lorsque des erreurs surviennent lors du chargement des produits. Retournez `true` pour relancer le chargement. | | **didPartiallyLoadProducts** | optionnel | Invoqué lorsque les produits sont partiellement chargés. | | **showAlertItem** | optionnel | Un binding qui gère l'affichage des éléments d'alerte au-dessus du flow ou du paywall. | | **showAlertBuilder** | optionnel | Une fonction pour afficher la vue d'alerte. | | **placeholderBuilder** | optionnel | Une fonction pour afficher la vue de remplacement pendant le chargement du flow ou du paywall. Par défaut : une `ProgressView`. | Consultez la rubrique [iOS - Gestion des événements](ios-handling-events) pour plus de détails sur les paramètres. ### Présenter comme une vue non modale \{#present-as-a-non-modal-view\} Vous pouvez également présenter les flows et paywalls comme destinations de navigation ou vues intégrées dans le flux de navigation de votre application. Utilisez `AdaptyFlowView` directement dans vos vues SwiftUI : ```swift showLineNumbers title="SwiftUI" AdaptyFlowView( flowConfiguration: <AdaptyUI.FlowConfiguration>, didFinishPurchase: { product, purchaseResult in // Dismiss the view, or do nothing to let the flow continue }, didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didReceiveError: { error in // Handle the error (rendering or JS exception from the flow script). } ) ``` ## Présenter les flows et paywalls avec UIKit \{#present-flows-and-paywalls-in-uikit\} Pour afficher le flow ou le paywall sur l'écran de l'appareil, procédez comme suit : 1. Initialisez le flow visuel que vous souhaitez afficher en utilisant la méthode `AdaptyUI.flowController(with:delegate:)` : ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: <AdaptyUI.FlowConfiguration>, delegate: <AdaptyFlowControllerDelegate> ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :----------------------- | :------- | :---------- | | **flowConfiguration** | requis | Un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow ou du paywall. Utilisez la méthode `AdaptyUI.getFlowConfiguration(forFlow:)`. Consultez la rubrique [Récupérer les flows et paywalls](get-pb-paywalls) pour plus de détails. | | **delegate** | requis | Un `AdaptyFlowControllerDelegate` pour écouter les événements du flow et du paywall. Consultez la rubrique [Gérer les événements de flow & paywall](ios-handling-events) pour plus de détails. | Valeur retournée : | Objet | Description | | :---------------------- | :----------------------------------------------------------------- | | **AdaptyFlowController** | Un objet représentant l'écran du flow ou du paywall demandé. | 2. Une fois l'objet créé avec succès, vous pouvez l'afficher sur l'écran de l'appareil : ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: </SDKv4> <SDKv3> Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. Pour obtenir l'objet `AdaptyUI.PaywallConfiguration` utilisé ci-dessous, consultez [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls). ## Présenter les paywalls avec SwiftUI \{#present-paywalls-in-swiftui\} ### Présenter comme une vue modale \{#present-as-a-modal-view\} Pour afficher le paywall visuel sur l'écran de l'appareil comme une vue modale, utilisez le modificateur `.paywall` dans SwiftUI : ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false // ensure that you manage this variable state and set it to `true` at the moment you want to show the paywall var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishPurchase: { product, profile in paywallPresented = false }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` Paramètres : | Paramètre | Requis | Description | |:----------------------------------|:-------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | requis | Un binding qui détermine si l'écran du paywall est affiché. | | **paywallConfiguration** | requis | Un objet `AdaptyUI.PaywallConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **didFailPurchase** | requis | Invoqué lorsque `Adapty.makePurchase()` échoue. | | **didFinishRestore** | requis | Invoqué lorsque `Adapty.restorePurchases()` se termine avec succès. | | **didFailRestore** | requis | Invoqué lorsque `Adapty.restorePurchases()` échoue. | | **didFailRendering** | requis | Invoqué si une erreur survient lors du rendu de l'interface. Dans ce cas, [contactez le support Adapty](mailto:support@adapty.io). | | **fullScreen** | optionnel | Détermine si le paywall s'affiche en plein écran ou sous forme de modal. Par défaut : `true`. | | **didAppear** | optionnel | Invoqué lorsque la vue du paywall a été présentée. | | **didDisappear** | optionnel | Invoqué lorsque la vue du paywall a été fermée. | | **didPerformAction** | optionnel | Invoqué lorsqu'un utilisateur clique sur un bouton. Différents boutons ont différents identifiants d'action. Deux identifiants d'action sont prédéfinis : `close` et `openURL`, les autres sont personnalisés et peuvent être définis dans le builder. | | **didSelectProduct** | optionnel | Invoqué lorsqu'un produit est sélectionné pour l'achat par l'utilisateur ou par le système. | | **didStartPurchase** | optionnel | Invoqué lorsque l'utilisateur commence le processus d'achat. | | **didFinishPurchase** | optionnel | Invoqué lorsque `Adapty.makePurchase()` se termine avec succès. | | **didFinishWebPaymentNavigation** | optionnel | Invoqué lorsque la navigation de paiement web se termine. | | **didStartRestore** | optionnel | Invoqué lorsque l'utilisateur démarre le processus de restauration. | | **didFailLoadingProducts** | optionnel | Invoqué lorsque des erreurs surviennent lors du chargement des produits. Retournez `true` pour relancer le chargement. | | **didPartiallyLoadProducts** | optionnel | Invoqué lorsque les produits sont partiellement chargés. | | **showAlertItem** | optionnel | Un binding qui gère l'affichage des éléments d'alerte au-dessus du paywall. | | **showAlertBuilder** | optionnel | Une fonction pour afficher la vue d'alerte. | | **placeholderBuilder** | optionnel | Une fonction pour afficher la vue de remplacement pendant le chargement du paywall. | Consultez la rubrique [iOS - Gestion des événements](ios-handling-events) pour plus de détails sur les paramètres. ### Présenter comme une vue non modale \{#present-as-a-non-modal-view\} Vous pouvez également présenter les paywalls comme destinations de navigation ou vues intégrées dans le flux de navigation de votre application. Utilisez `AdaptyPaywallView` directement dans vos vues SwiftUI : ```swift showLineNumbers title="SwiftUI" AdaptyPaywallView( paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didFailRendering: { error in // Handle rendering error } ) ``` ## Présenter les paywalls avec UIKit \{#present-paywalls-in-uikit\} Pour afficher le paywall visuel sur l'écran de l'appareil, procédez comme suit : 1. Initialisez le paywall visuel que vous souhaitez afficher en utilisant la méthode `.paywallController(for:products:viewConfiguration:delegate:)` : ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: <paywall configuration object>, delegate: <AdaptyPaywallControllerDelegate> ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :----------------------- | :------- | :---------- | | **paywall configuration** | requis | Un objet `AdaptyUI.PaywallConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **delegate** | requis | Un `AdaptyPaywallControllerDelegate` pour écouter les événements du paywall. Consultez la rubrique [Gestion des événements de paywall](ios-handling-events) pour plus de détails. Valeur retournée : | Objet | Description | | :---------------------- | :------------------------------------------------------- | | **AdaptyPaywallController** | Un objet représentant l'écran du paywall demandé. | 2. Une fois l'objet créé avec succès, vous pouvez l'afficher sur l'écran de l'appareil : ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: </SDKv3> --- # File: handle-paywall-actions --- --- title: "Répondre aux actions des flows - iOS" description: "Gérez les actions des boutons et traitez les entrées utilisateur dans les flows de paywall et d'onboarding de votre app iOS." --- <SDKv4> Si vous créez des flows ou des paywalls avec l'Adapty Flow Builder ou le Paywall Builder, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide montre comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **Seules la fermeture des flows/paywalls et l'ouverture des URL sont gérées automatiquement.** Toutes les autres actions de bouton nécessitent une implémentation appropriée dans le code de l'app. ::: :::note Le SDK iOS peut répondre aux demandes de permissions système, comme les notifications push ou l'accès à la caméra, via un `AdaptySystemRequestsHandler`. Les flows ne déclenchent pas encore ces demandes, vous n'avez donc pas besoin de les gérer pour l'instant. ::: ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui ferme votre flow ou paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close`. :::info Dans le SDK iOS, l'action `close` déclenche par défaut la fermeture du flow ou du paywall. Vous pouvez toutefois remplacer ce comportement dans votre code si nécessaire. Par exemple, fermer un flow peut déclencher l'ouverture d'un autre. ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow or paywall default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` ## Ouvrir des URL depuis les flows et les paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par ex. conditions d'utilisation et restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par ex. **Terms of use** ou **Privacy policy**) : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openURL` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK iOS, l'action `openURL` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois remplacer ce comportement dans votre code si nécessaire. ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre flow ou paywall : ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .custom(id): if id == "openNewPaywall" { // Display another flow or paywall } default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` </SDKv4> <SDKv3> Si vous créez des paywalls avec le Paywall Builder Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide montre comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **Seules les achats, les restaurations, la fermeture des paywalls et l'ouverture des URL sont gérés automatiquement.** Toutes les autres actions de bouton nécessitent une implémentation appropriée dans le code de l'app. ::: ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui ferme votre paywall : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le paywall. :::info Dans le SDK iOS, l'action `close` déclenche par défaut la fermeture du paywall. Vous pouvez toutefois remplacer ce comportement dans votre code si nécessaire. Par exemple, fermer un paywall peut déclencher l'ouverture d'un autre. ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior break } } ``` ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par ex. conditions d'utilisation et restauration des achats), ajoutez un élément **Link** dans le Paywall Builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par ex. **Terms of use** ou **Privacy policy**) : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK iOS, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois remplacer ce comportement dans votre code si nécessaire. ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior break } } ``` ## Se connecter à l'app \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre app : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `login` qui identifie votre utilisateur. ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .login: // Show a login screen let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") controller.present(loginVC, animated: true) } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre paywall : ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .custom(id): if id == "openNewPaywall" { // Display another paywall } } break } } ``` </SDKv3> --- # File: ios-handling-events --- --- title: "Gérer les événements de flow et de paywall - iOS" description: "Gérez les événements de flow et de paywall dans votre application iOS." --- <SDKv4> :::important Ce guide couvre la gestion des événements pour les achats, les restaurations, la sélection de produits et l'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 de boutons](handle-paywall-actions) pour en savoir plus. ::: Les flows et les paywalls 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 les pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez ci-dessous comment répondre à ces événements. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [applications exemples](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et les autres fonctionnalités de base. ::: ## Gestion des événements dans SwiftUI \{#handling-events-in-swiftui\} Pour contrôler ou surveiller les processus qui se déroulent sur l'écran de flow ou de paywall dans votre application mobile, utilisez le modificateur `.flow` dans SwiftUI : ```swift showLineNumbers title="Swift" @State var flowPresented = false var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { product in /* Handle the event */ }, didStartPurchase: { product in /* Handle the event */ }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false }, didFailLoadingProducts: { error in // Return `true` to retry loading return false } ) } ``` Vous pouvez n'enregistrer que les paramètres de fermeture dont vous avez besoin et omettre ceux dont vous n'avez pas besoin. | Paramètre | Requis | Description | |:-----------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | requis | Un binding qui détermine si l'écran du flow ou du paywall est affiché. | | **flowConfiguration** | requis | Un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow ou du paywall. Consultez [Obtenir des flows et des paywalls](get-pb-paywalls) pour plus de détails. | | **didFinishPurchase** | requis | Appelé lorsque `Adapty.makePurchase()` se termine avec succès. Le flow ne se ferme pas automatiquement — définissez votre binding de présentation sur `false` ici, ou ne faites rien pour laisser le flow continuer après l'achat. | | **didFailPurchase** | requis | Appelé lorsque `Adapty.makePurchase()` échoue. | | **didFinishRestore** | requis | Appelé lorsque `Adapty.restorePurchases()` se termine avec succès. | | **didFailRestore** | requis | Appelé lorsque `Adapty.restorePurchases()` échoue. | | **didReceiveError** | requis | Appelé lorsque le flow rencontre une erreur de rendu ou une erreur d'exécution provenant du script du flow (par exemple, une exception JavaScript, code `AdaptyUIError` `4105`). En cas d'erreur de rendu, [contactez le support Adapty](mailto:support@adapty.io). | | **placeholderBuilder** | optionnel | Une fonction pour afficher la vue de remplacement pendant le chargement du flow ou du paywall. Par défaut, une `ProgressView`. | | **fullScreen** | optionnel | Détermine si le flow ou le paywall s'affiche en plein écran ou sous forme de feuille. Par défaut `true`. | | **didAppear** | optionnel | Appelé lorsque la vue du flow ou du paywall apparaît à l'écran. | | **didDisappear** | optionnel | Appelé lorsque la vue du flow ou du paywall a été fermée. | | **didPerformAction** | optionnel | Appelé lorsqu'un utilisateur clique sur un bouton. Deux identifiants d'action sont prédéfinis : `close` et `openURL` ; les autres sont personnalisés et peuvent être définis dans le builder. | | **didSelectProduct** | optionnel | Appelé lorsqu'un produit est sélectionné pour l'achat par l'utilisateur ou par le système. | | **didStartPurchase** | optionnel | Appelé lorsque l'utilisateur commence le processus d'achat. | | **didFinishWebPaymentNavigation** | optionnel | Appelé lorsque la navigation de paiement web se termine. | | **didStartRestore** | optionnel | Appelé lorsque l'utilisateur démarre le processus de restauration. | | **didFailLoadingProducts** | optionnel | Appelé lorsque des erreurs surviennent pendant le chargement des produits. Retournez `true` pour relancer le chargement. | | **didPartiallyLoadProducts** | optionnel | Appelé lorsque les produits sont partiellement chargés. | | **showAlertItem** | optionnel | Un binding qui gère l'affichage des éléments d'alerte au-dessus du flow ou du paywall. | | **showAlertBuilder** | optionnel | Une fonction pour afficher la vue d'alerte. | ## Gestion des événements dans UIKit \{#handling-events-in-uikit\} Pour les applications UIKit, les événements sont gérés via le protocole `AdaptyFlowControllerDelegate`. Consultez [Afficher les flows & paywalls - iOS](ios-present-paywalls) pour savoir comment configurer `AdaptyFlowController` avec `AdaptyFlowControllerDelegate`. Le protocole déclare 13 méthodes. Quatre d'entre elles n'ont pas d'implémentation par défaut et doivent être implémentées lors de la conformité : `didFinishPurchase`, `didFailPurchase`, `didFinishRestoreWith` et `didFailRestoreWith`. Les autres fournissent des implémentations no-op par défaut et peuvent être remplacées si vous souhaitez un comportement personnalisé. Les méthodes sont regroupées ci-dessous par objectif. ### Cycle de vie \{#lifecycle\} ```swift showLineNumbers title="Swift" func flowControllerDidAppear(_ controller: AdaptyFlowController) { } func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } ``` Ces méthodes se déclenchent lorsque la vue du flow ou du paywall est affichée ou masquée. ### Actions utilisateur \{#user-actions\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action ) { } ``` Cas de `AdaptyUI.Action` : - `.close` — par défaut, ferme le contrôleur. Surchargez cette action pour maintenir le contrôleur à l'écran ou effectuer un nettoyage supplémentaire. - `.openURL(url:)` — par défaut, ouvre l'URL avec `UIApplication.shared.open(...)`. - `.custom(id:)` — déclenché pour les boutons avec un identifiant d'action personnalisé défini dans le builder. ### Sélection du produit \{#product-selection\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didSelectProduct product: AdaptyPaywallProduct ) { } ``` Invoqué lorsqu'un produit est sélectionné pour achat par l'utilisateur ou par le système. Le produit contient toutes les informations sur l'offre (l'éligibilité est déterminée automatiquement en v4 — il n'existe pas de type `AdaptyPaywallProductWithoutDeterminingOffer` distinct). ### Événements d'achat \{#purchase-events\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didStartPurchase product: AdaptyPaywallProduct ) { } func flowController( _ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController( _ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` `didFinishPurchase` et `didFailPurchase` n'ont pas d'implémentation par défaut et doivent être implémentés. Le contrôleur ne se ferme pas automatiquement après un achat réussi — appelez `controller.dismiss(animated:)` le moment venu, ou ne faites rien pour laisser un flow multi-écrans continuer après l'achat. ### Événements de restauration \{#restore-events\} ```swift showLineNumbers title="Swift" func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } func flowController( _ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile ) { } func flowController( _ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError ) { } ``` `didFinishRestoreWith` et `didFailRestoreWith` n'ont pas d'implémentation par défaut. Vérifiez que le `AdaptyProfile` retourné contient le niveau d'accès souhaité avant de fermer le contrôleur. ### Erreurs de flow et erreurs de chargement des produits \{#flow-errors-and-product-loading-errors\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError ) { } func flowController( _ controller: AdaptyFlowController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { // Return `true` to retry product loading; default returns `false`. return false } func flowController( _ controller: AdaptyFlowController, didPartiallyLoadProducts failedIds: [String] ) { } ``` `didReceiveError` se déclenche pour les erreurs de rendu et les erreurs d'exécution provenant du script du flow (exceptions JavaScript, code `AdaptyUIError` `4105`). Pour les erreurs de rendu, [contactez le support Adapty](mailto:support@adapty.io). Pour les erreurs de chargement, retournez `true` depuis `didFailLoadingProductsWith` pour réessayer — utile en cas de problèmes réseau passagers. ### Navigation de paiement web \{#web-payment-navigation\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, error: AdaptyError? ) { } ``` Invoqué après la fin d'une navigation de paiement web, qu'elle ait réussi ou échoué. </SDKv4> <SDKv3> :::important 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 des boutons](handle-paywall-actions) pour plus de détails. ::: Les paywalls configurés avec le [Paywall Builder](adapty-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 les pressions 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 ci-dessous comment réagir à ces événements. Ce guide concerne uniquement les **paywalls du nouveau Paywall Builder**, qui nécessitent le SDK Adapty v3.0 ou une version ultérieure. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Gestion des événements dans SwiftUI \{#handling-events-in-swiftui\} Pour contrôler ou surveiller les processus se déroulant sur l'écran du paywall dans votre application mobile, utilisez le modificateur `.paywall` dans SwiftUI : ```swift showLineNumbers title="Swift" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: paywall, viewConfiguration: viewConfig, didPerformAction: { action in switch action { case .close: paywallPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { /* Handle the event */ }, didStartPurchase: { /* Handle the event */ }, didFinishPurchase: { product, info in /* Handle the event */ }, didFailPurchase: { product, error in /* Handle the event */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { /* Handle the event */ }, didFailRestore: { /* Handle the event */ }, didFailRendering: { error in paywallPresented = false }, didFailLoadingProducts: { error in return false } ) } ``` Vous pouvez n'enregistrer que les paramètres de closure dont vous avez besoin, et omettre ceux dont vous n'avez pas besoin. Dans ce cas, les paramètres de closure inutilisés ne seront pas créés. | Paramètre | Requis | Description | |:----------------------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | requis | Un binding qui gère l'affichage ou non de l'écran du paywall. | | **paywallConfiguration** | requis | Un objet `AdaptyUI.PaywallConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)`. Consultez la rubrique [Récupérer les paywalls du Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **didFailPurchase** | requis | Déclenché lorsqu'un achat échoue en raison d'erreurs (ex. : paiement non autorisé, problème réseau, produit invalide). Non déclenché en cas d'annulation par l'utilisateur ou de paiement en attente. | | **didFinishRestore** | requis | Déclenché lorsqu'un achat se termine avec succès. | | **didFailRestore** | requis | Déclenché lorsque la restauration d'un achat échoue. | | **didFailRendering** | requis | Déclenché si une erreur survient lors du rendu de l'interface. Dans ce cas, [contactez le support Adapty](mailto:support@adapty.io). | | **fullScreen** | optionnel | Détermine si le paywall s'affiche en plein écran ou en modal. Par défaut à `true`. | | **didAppear** | optionnel | Déclenché lorsque la vue du paywall apparaît à l'écran. Également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall et qu'un paywall web s'ouvre dans un navigateur intégré. | | **didDisappear** | optionnel | Déclenché lorsque la vue du paywall est fermée. Également déclenché lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. | | **didPerformAction** | optionnel | Déclenché lorsqu'un utilisateur clique sur un bouton. Les différents boutons ont des identifiants d'action différents. Deux identifiants sont prédéfinis : `close` et `openURL`, les autres sont personnalisés et peuvent être définis dans le builder. | | **didSelectProduct** | optionnel | Déclenché lorsqu'un produit est sélectionné pour l'achat (par l'utilisateur ou par le système). | | **didStartPurchase** | optionnel | Déclenché lorsque l'utilisateur commence le processus d'achat. | | **didFinishPurchase** | optionnel | Déclenché lorsqu'un achat se termine avec succès. | | **didFinishWebPaymentNavigation** | optionnel | Déclenché après une tentative d'ouverture d'un [paywall web](web-paywall) pour un achat, qu'elle ait réussi ou échoué. | | **didStartRestore** | optionnel | Déclenché lorsque l'utilisateur lance le processus de restauration. | | **didFailLoadingProducts** | optionnel | Déclenché lorsque des erreurs surviennent pendant le chargement des produits. Retournez `true` pour relancer le chargement. | | **didPartiallyLoadProducts** | optionnel | Déclenché lorsque les produits sont partiellement chargés. | | **showAlertItem** | optionnel | Un binding qui gère l'affichage des éléments d'alerte au-dessus du paywall. | | **showAlertBuilder** | optionnel | Une fonction pour afficher la vue d'alerte. | | **placeholderBuilder** | optionnel | Une fonction pour afficher la vue de remplacement pendant le chargement du paywall. | ## Gestion des événements dans UIKit \{#handling-events-in-uikit\} Pour contrôler ou surveiller les processus qui se déroulent sur l'écran du paywall dans votre application mobile, implémentez les méthodes `AdaptyPaywallControllerDelegate`. ### Événements générés par l'utilisateur \{#user-generated-events\} #### Sélection d'un produit \{#product-selection\} Lorsqu'un utilisateur sélectionne un produit pour l'acheter, cette méthode est appelée : ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer ) { } ``` <Details> <summary>Exemple d'événement (cliquer pour agrandir)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### Achat démarré \{#started-purchase\} Si un utilisateur initie le processus d'achat, cette méthode sera invoquée : ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didStartPurchase product: AdaptyPaywallProduct) { } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> Cette fonction ne sera pas appelée en mode Observer. Consultez la rubrique [iOS - Présenter les paywalls Paywall Builder en mode Observer](ios-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat démarré via un paywall web \{#started-purchase-using-a-web-paywall\} Si un utilisateur initie le processus d'achat via un [paywall web](web-paywall), cette méthode sera invoquée : ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, shouldContinueWebPaymentNavigation product: AdaptyPaywallProduct ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### Achat réussi ou annulé \{#successful-or-canceled-purchase\} Si l'achat réussit, cette méthode sera appelée : ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer, purchaseResult: AdaptyPurchaseResult ) { } } ``` <Details> <summary>Exemples d'événements (Cliquez pour développer)</summary> ```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": "cancelled" } } ``` </Details> Nous recommandons de fermer le paywall dans ce cas. Cette méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [iOS - Présenter les paywalls du Paywall Builder en mode Observer](ios-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Achat échoué \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode est appelée. Cela inclut les erreurs StoreKit (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations utilisateur déclenchent `didFinishPurchase` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode. ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```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" } } } ``` </Details> Elle ne sera pas invoquée en mode Observer. Consultez la rubrique [iOS - Présenter des paywalls Paywall Builder en mode Observer](ios-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails. #### Échec d'un achat via un paywall web \{#failed-purchase-using-a-web-paywall\} Si `Adapty.openWebPaywall()` échoue, cette méthode sera invoquée : ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailWebPaymentNavigation product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> #### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée : ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishRestoreWith profile: AdaptyProfile ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```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" } ] } } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur dispose du `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](subscription-status) pour savoir comment le vérifier. #### Échec de la restauration \{#failed-restore\} Si la restauration d'un achat échoue, cette méthode sera appelée : ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRestoreWith error: AdaptyError ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> ### Récupération et rendu des données \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne transmettez pas le tableau de produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur. Si cette opération échoue, AdaptyUI signalera l'erreur en appelant cette méthode : ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { return true } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> Si vous renvoyez `true`, AdaptyUI répétera la requête après 2 secondes. #### Erreurs de rendu \{#rendering-errors\} Si une erreur survient lors du rendu de l'interface, elle sera signalée par cette méthode : ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRenderingWith error: AdaptyError ) { } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> Dans une situation normale, de telles erreurs ne devraient pas se produire. Si vous en rencontrez une, veuillez nous en informer. </SDKv3> --- # File: ios-use-fallback-paywalls --- --- title: "iOS - Utiliser les fallbacks" description: "Gérez les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles" --- To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} 1. Ajoutez le fichier JSON de secours à votre bundle de projet : ouvrez le menu **File** dans XCode et sélectionnez l'option **Add Files to "YourProjectName"**. 2. Appelez la méthode `.setFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { if let urlPath = Bundle.main.url(forResource: fileName, withExtension: "json") { try await Adapty.setFallback(fileURL: urlPath) } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers if let url = Bundle.main.url(forResource: "ios_fallback", withExtension: "json") { Adapty.setFallback(fileURL: url) } ``` </TabItem> </Tabs> Paramètres : | Paramètre | Description | | :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **fileURL** | Chemin vers le fichier de configuration de secours. | --- # File: localizations-and-locale-codes --- --- title: "Utiliser les localisations et codes de langue dans le SDK iOS" description: "Gérez les localisations et codes de langue de votre app pour toucher un public mondial dans votre app iOS." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu lorsqu'Adapty choisit la localisation d'un flow et lorsque vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. C'est pourquoi Adapty s'appuie sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prévoir quelle localisation reçoit un utilisateur. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty recherche la localisation correspondant à la locale d'un utilisateur, voici ce qui se passe : 1. La chaîne de locale est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est trouvée à nouveau, Adapty retourne le contenu dans la locale par défaut du flow Cette approche permet à `'pt_BR'`, `pt-BR` et `pt-br` de pointer vers la même localisation. ## Implémenter les localisations \{#implementing-localizations\} Dans le SDK v4, vous ne passez pas de code de langue lors de la récupération d'un flow — `getFlow` renvoie le flow avec l'ensemble de ses localisations. - **Flows créés dans le builder** : le SDK ne lit pas la locale de l'appareil, vous devez donc la résoudre dans votre application et la passer à `AdaptyUI.getFlowConfiguration(forFlow:locale:)`. Ce paramètre est optionnel — omettez-le et le flow s'affiche en `en`, ou dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow n'a pas de localisation `en`. - **Paywalls personnalisés (Remote Config)** : `getFlow` renvoie toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée contient un code `locale` et le contenu de la configuration (`jsonString`, ou le `dictionary` analysé). Sélectionnez l'entrée qui correspond à l'utilisateur, avec votre propre logique de secours : ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first // read your values from config?.dictionary } catch { // handle the error } ``` Les règles de correspondance des codes de langue décrites ci-dessus expliquent comment Adapty normalise les codes `locale` stockés dans chaque Remote Config. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Il existe plusieurs situations où les codes de langue entrent en jeu — par exemple, lorsque vous essayez de récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de langue étant complexes et pouvant varier d'une plateforme à l'autre, nous nous appuyons sur un standard interne pour toutes les plateformes que nous supportons. Cependant, en raison de cette complexité, il est vraiment important de comprendre exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin que vous receviez toujours ce que vous attendez. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty reçoit un appel du SDK avec le code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de locale reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. On recherche ensuite la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si aucune correspondance n'est trouvée non plus, on renvoie le contenu dans la locale par défaut du paywall Ainsi, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Implémentation des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous posez des questions sur les localisations, il y a de grandes chances que vous travailliez déjà avec des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty souhaité dans chacun de vos fichiers pour les localisations correspondantes. Extrayez ensuite la valeur de cette clé lors de l'appel à notre SDK, comme ceci : ```swift showLineNumbers // 1. Modify your Localizable.strings files /* Localizable.strings - Spanish */ adapty_paywalls_locale = "es"; /* Localizable.strings - Portuguese (Brazil) */ adapty_paywalls_locale = "pt-br"; // 2. Extract and use the locale code let locale = NSLocalizedString("adapty_paywalls_locale", comment: "") // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` Ainsi, vous gardez un contrôle total sur la localisation qui sera récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : l'autre façon \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement des codes de langue pour chaque localisation. Cela consiste à extraire un code de langue depuis d'autres objets fournis par votre plateforme, comme ceci : ```swift showLineNumbers let locale = Locale.current.identifier // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` Notez que nous ne recommandons pas cette approche pour plusieurs raisons : 1. Sur iOS, les langues préférées et la locale actuelle ne sont pas identiques. Pour que la localisation soit correctement sélectionnée, vous devrez soit vous appuyer sur la logique d'Apple, qui fonctionne automatiquement si vous utilisez l'approche recommandée avec des fichiers de chaînes localisées, soit la recréer vous-même. 2. Il est difficile de prédire ce que le serveur d'Adapty recevra exactement. Par exemple, sur iOS, il est possible d'obtenir une locale comme `ar_OM@numbers='latn'` sur un appareil et de l'envoyer à notre serveur. Dans ce cas, vous obtiendrez non pas la localisation `ar-om` que vous recherchiez, mais plutôt `ar`, ce qui est probablement inattendu. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: ios-troubleshoot-paywall-builder --- --- title: "Troubleshoot Paywall Builder in iOS SDK" description: "Troubleshoot Paywall Builder in iOS SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK iOS. ## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La méthode `getPaywallConfiguration` ne parvient pas à récupérer la configuration du paywall. **Raison** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le nombre de vues du paywall affiche le double du chiffre attendu. **Raison** : Vous appelez peut-être `logShowFlow` (SDK iOS v4+) / `logShowPaywall` dans votre code, ce qui duplique le compteur de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls créés avec ces outils, les analytics sont suivis automatiquement — vous n'avez donc pas besoin d'utiliser cette méthode. **Solution** : Vérifiez que vous n'appelez pas `logShowFlow` (SDK iOS v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder qui ne sont pas abordés ci-dessus. **Solution** : Mettez à jour le SDK vers la dernière version à l'aide des [guides de migration](ios-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions récentes du SDK. --- # File: ios-present-paywall-builder-paywalls-in-observer-mode --- --- title: "Afficher les paywalls Paywall Builder en mode Observer dans le SDK iOS" description: "Apprenez à afficher les paywalls PB en mode observer pour de meilleures informations." --- Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez [iOS - Afficher les paywalls Paywall Builder](ios-present-paywalls). ::: <SDKv4> <details> <summary>Avant de commencer à afficher des flows (cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez le [guide d'installation du SDK iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](get-pb-paywalls) dans le code de votre application mobile. </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. Implémentez l'objet `AdaptyObserverModeResolver`. Le protocole est identique à celui du SDK v3 — le mode observer lui-même ne change pas entre le rendu des flows et des paywalls : ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // call onStartPurchase / onFinishPurchase to notify AdaptyUI about the purchase progress } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // call onStartRestore / onFinishRestore to notify AdaptyUI about the restore progress } ``` 2. Créez un objet de configuration de flow en passant votre resolver comme paramètre `observerModeResolver:` : ```swift showLineNumbers title="Swift" do { let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: <AdaptyObserverModeResolver> ) } catch { // handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :----------------------- | :-------- | :----------------------------------------------------------------------------------------------------------------------- | | **forFlow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow(placementId:)`. Voir [Obtenir les flows et paywalls](get-pb-paywalls). | | **observerModeResolver** | requis | L'`AdaptyObserverModeResolver` que vous avez implémenté ci-dessus. | 3. Initialisez le contrôleur de flow avec `AdaptyUI.flowController(with:delegate:)` : ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: flowConfiguration, delegate: <AdaptyFlowControllerDelegate> ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------- | | **flowConfiguration** | requis | Un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow. Voir [Obtenir les flows et paywalls](get-pb-paywalls). | | **delegate** | requis | Un `AdaptyFlowControllerDelegate` pour écouter les événements du flow. Voir [Gérer les événements de flow & paywall](ios-handling-events). | Retourne : | Objet | Description | | :------------------- | :----------------------------------------------------------- | | AdaptyFlowController | Un objet représentant l'écran de flow demandé. | 4. Affichez le contrôleur : ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> En SwiftUI, récupérez la configuration du flow avec le resolver et passez-la au modificateur `.flow` : ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false @State var flowConfiguration: AdaptyUI.FlowConfiguration? var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) .task { flowConfiguration = try? await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: <AdaptyObserverModeResolver> ) } } ``` Le paramètre `observerModeResolver:` sur `getFlowConfiguration` est ce qui permet au flow rendu de respecter votre logique d'achat personnalisée — le modificateur lui-même utilise les mêmes callbacks qu'en mode complet. :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> </Tabs> </SDKv4> <SDKv3> <Tabs groupId="current-os" queryString> <TabItem value="sdk3" label="Paywall Builder (SDK 3.x)" default> <details> <summary>Avant de commencer à afficher des paywalls (cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques par framework pour [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des paywalls, assignez-leur des produits](create-paywall) et personnalisez-les avec le Paywall Builder dans l'Adapty Dashboard. 5. [Créez des placements et assignez-leur vos paywalls](create-placement) dans l'Adapty Dashboard. 6. [Récupérez les paywalls Paywall Builder et leur configuration](get-pb-paywalls) dans le code de votre application mobile. </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. Implémentez l'objet `AdaptyObserverModeResolver` : ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore } ``` L'événement `observerMode(didInitiatePurchase:onStartPurchase:onFinishPurchase:)` vous informe que l'utilisateur a initié un achat. Vous pouvez déclencher votre propre flow d'achat personnalisé en réponse à ce callback. L'événement `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)` vous informe que l'utilisateur a initié une restauration. Vous pouvez déclencher votre propre flow de restauration personnalisé en réponse à ce callback. N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. Cela est nécessaire pour le bon comportement du paywall, notamment pour afficher le loader : | Callback | Description | | :----------------- | :----------------------------------------------------------------------------------------------- | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | 2. Créez un objet de configuration de paywall : ```swift showLineNumbers title="Swift" do { let paywallConfiguration = try AdaptyUI.getPaywallConfiguration( forPaywall: <paywall object>, observerModeResolver: <AdaptyObserverModeResolver> ) } catch { // handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | requis | Un objet `AdaptyPaywall` pour obtenir un contrôleur pour le paywall souhaité. | | **ObserverModeResolver** | requis | L'objet `AdaptyObserverModeResolver` que vous avez implémenté à l'étape précédente. | 3. Initialisez le paywall visuel que vous souhaitez afficher avec la méthode `.paywallController(for:products:viewConfiguration:delegate:)` : ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: <paywall configuration object>, delegate: <AdaptyPaywallControllerDelegate> ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | requis | Un objet `AdaptyUI.PaywallConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **Delegate** | requis | Un `AdaptyPaywallControllerDelegate` pour écouter les événements du paywall. Consultez la rubrique [Gestion des événements paywall](ios-handling-events) pour plus de détails. | Retourne : | Objet | Description | | :---------------------- | :----------------------------------------------------------- | | AdaptyPaywallController | Un objet représentant l'écran de paywall demandé. | Une fois l'objet créé avec succès, vous pouvez l'afficher ainsi : ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> Pour afficher le paywall visuel sur l'écran de l'appareil, utilisez le modificateur `.paywall` en SwiftUI : ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: <paywall configuration object>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :------------------------ | :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | requis | Un objet `AdaptyUI.PaywallConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **Products** | optionnel | Fournissez un tableau d'objets `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | | **TagResolver** | optionnel | Définissez un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu du paywall, remplacés dynamiquement par des chaînes spécifiques pour un contenu personnalisé. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | | **ObserverModeResolver** | optionnel | L'objet `AdaptyObserverModeResolver` que vous avez implémenté à l'étape précédente. | Paramètres de closure : | Paramètre de closure | Description | | :------------------- | :--------------------------------------------------------------------------------------------- | | **didFinishRestore** | Invoqué si `Adapty.restorePurchases()` réussit. | | **didFailRestore** | Invoqué si `Adapty.restorePurchases()` échoue. | | **didFailRendering** | Invoqué si une erreur survient lors du rendu de l'interface. | Consultez la rubrique [iOS - Gestion des événements](ios-handling-events) pour les autres paramètres de closure. :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> </Tabs> </TabItem> <TabItem value="sdk2" label="Legacy Paywall Builder (SDK up to 2.x)" default> <details> <summary>Avant de commencer à afficher des paywalls (cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios). 1. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques par framework pour [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk) et [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 2. [Créez des produits](create-product) dans l'Adapty Dashboard. 3. [Configurez des paywalls, assignez-leur des produits](create-paywall) et personnalisez-les avec le Paywall Builder dans l'Adapty Dashboard. 4. [Créez des placements et assignez-leur vos paywalls](create-placement) dans l'Adapty Dashboard. 5. [Récupérez les paywalls Paywall Builder et leur configuration](get-pb-paywalls) dans le code de votre application mobile. </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. Implémentez l'objet `AdaptyObserverModeDelegate` : ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } ``` L'événement `paywallController(_:didInitiatePurchase:onStartPurchase:onFinishPurchase:)` vous informe que l'utilisateur a initié un achat. Vous pouvez déclencher votre propre flow d'achat personnalisé en réponse à cet événement. N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat. Cela est nécessaire pour le bon comportement du paywall, notamment pour afficher le loader : | Callback | Description | | :--------------- | :--------------------------------------------------------------------------------------------- | | onStartPurchase | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | 2. Initialisez le paywall visuel que vous souhaitez afficher avec la méthode `.paywallController(for:products:viewConfiguration:delegate:observerModeDelegate:)` : ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( for: <paywall object>, products: <paywall products array>, viewConfiguration: <LocalizedViewConfiguration>, delegate: <AdaptyPaywallControllerDelegate> observerModeDelegate: <AdaptyObserverModeDelegate> ) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :----------------------- | :-------- | :----------------------------------------------------------- | | **Paywall** | requis | Un objet `AdaptyPaywall` pour obtenir un contrôleur pour le paywall souhaité. | | **Products** | optionnel | Fournissez un tableau d'objets `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | | **ViewConfiguration** | requis | Un objet `AdaptyUI.LocalizedViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.getViewConfiguration(paywall:locale:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **Delegate** | requis | Un `AdaptyPaywallControllerDelegate` pour écouter les événements du paywall. Consultez la rubrique [Gestion des événements paywall](ios-handling-events) pour plus de détails. | | **ObserverModeDelegate** | requis | L'objet `AdaptyObserverModeDelegate` que vous avez implémenté à l'étape précédente. | | **TagResolver** | optionnel | Définissez un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu du paywall, remplacés dynamiquement par des chaînes spécifiques pour un contenu personnalisé. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | Retourne : | Objet | Description | | :---------------------- | :----------------------------------------------------------- | | AdaptyPaywallController | Un objet représentant l'écran de paywall demandé. | Une fois l'objet créé avec succès, vous pouvez l'afficher ainsi : ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> Pour afficher le paywall visuel sur l'écran de l'appareil, utilisez le modificateur `.paywall` en SwiftUI : ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: <paywall object>, configuration: <LocalizedViewConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false }, observerModeDidInitiatePurchase: { product, onStartPurchase, onFinishPurchase in // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase }, ) } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------------- | :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | requis | Un objet `AdaptyPaywall` pour obtenir un contrôleur pour le paywall souhaité. | | **Product** | optionnel | Fournissez un tableau d'objets `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | | **Configuration** | requis | Un objet `AdaptyUI.LocalizedViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `AdaptyUI.getViewConfiguration(paywall:locale:)`. Consultez la rubrique [Récupérer les paywalls Paywall Builder et leur configuration](get-pb-paywalls) pour plus de détails. | | **TagResolver** | optionnel | Définissez un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu du paywall, remplacés dynamiquement par des chaînes spécifiques pour un contenu personnalisé. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | Paramètres de closure : | Paramètre de closure | Description | | :---------------------------------- | :--------------------------------------------------------------------------------------------- | | **didFinishRestore** | Invoqué si `Adapty.restorePurchases()` réussit. | | **didFailRestore** | Invoqué si `Adapty.restorePurchases()` échoue. | | **didFailRendering** | Invoqué si une erreur survient lors du rendu de l'interface. | | **observerModeDidInitiatePurchase** | Invoqué lorsqu'un utilisateur initie un achat. | Consultez la rubrique [iOS - Gestion des événements](ios-handling-events) pour les autres paramètres de closure. :::warning N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat. ::: </TabItem> </Tabs> </TabItem> </Tabs> </SDKv3> --- # File: ios-implement-paywalls-manually --- --- title: "Implémenter des paywalls manuellement dans le SDK iOS" description: "Découvrez comment implémenter des paywalls manuellement dans votre application iOS avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty via la méthode `makePurchase`. Adapty se charge alors de tous les scénarios utilisateur, et vous n'avez plus qu'à gérer les résultats de l'achat. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['ios-quickstart-manual', 'fetch-paywalls-and-products', 'present-remote-config-paywalls', 'making-purchases', 'restore-purchase', 'ios-troubleshoot-purchases', 'ios-transaction-management']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, tout en profitant des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode', 'report-transactions-observer-mode', 'ios-present-paywall-builder-paywalls-in-observer-mode', 'ios-troubleshoot-purchases']} /> --- # File: ios-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé sur iOS SDK" description: "Intégrez le SDK Adapty dans vos paywalls iOS personnalisés pour activer les achats intégrés." --- Ce guide décrit comment intégrer Adapty dans vos paywalls personnalisés. Gardez un contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les précédents. :::important **Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la solution la plus simple pour activer les achats, utilisez [Adapty Flow Builder](ios-quickstart-paywalls). Avec Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère automatiquement toute la logique d'achat, et vous pouvez tester différents designs sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. - [**Placements**](placements) – où et quand vous affichez les paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de différents paywalls à différents utilisateurs. Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En gros, ils représentent simplement votre façon de gérer les produits que vous vendez dans votre application. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](ios-quickstart-identify) pour comprendre les spécificités et vous assurer que vous gérez correctement les utilisateurs. ## Étape 1. Récupérer les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID de [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau de produits pour ce flow à l'aide de la méthode `getPaywallProducts`. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func loadPaywall() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let products = try await Adapty.getPaywallProducts(flow: flow) // Use products to build your custom paywall UI } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func loadPaywall() { Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // Use products to build your custom paywall UI case let .failure(error): // Handle the error } } case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) async { do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) { Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Apple exige que toutes les applications avec des abonnements proposent un moyen aux utilisateurs de restaurer leurs achats. Bien que les achats soient automatiquement restaurés lorsqu'un utilisateur se connecte avec son identifiant Apple, vous devez quand même implémenter un bouton de restauration dans votre application. Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et retournera le profil mis à jour. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func restorePurchases() async { do { let profile = try await Adapty.restorePurchases() // Restore successful, profile updated } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func restorePurchases() { Adapty.restorePurchases { result in switch result { case let .success(profile): // Restore successful, profile updated case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. [Testez vos achats en mode sandbox](test-purchases-in-sandbox) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Ensuite, [vérifiez si les utilisateurs ont finalisé leur achat](ios-check-subscription-status) pour déterminer s'il faut afficher le paywall ou accorder l'accès aux fonctionnalités payantes. --- # File: fetch-paywalls-and-products --- --- title: "Récupérer les paywalls et produits pour les paywalls de configuration distante dans le SDK iOS" description: "Récupérez les paywalls et produits dans le SDK iOS Adapty pour améliorer la monétisation des utilisateurs." --- <SDKv4> Avant d'afficher les Remote Configs et les paywalls personnalisés, vous devez récupérer leurs informations. Notez que cette rubrique concerne les Remote Configs et les paywalls personnalisés. Pour récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez les <InlineTooltip tooltip="guides pour récupérer les flows et paywalls dans votre application">[iOS](get-pb-paywalls), [Android](android-get-pb-paywalls), [React Native](react-native-get-pb-paywalls), [Flutter](flutter-get-pb-paywalls), et [Unity](unity-get-pb-paywalls)</InlineTooltip>. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et incorporez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et incorporez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-ios) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) est une combinaison de produits provenant de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) à l'aide de la méthode `getFlow`. :::important **Ne codez pas en dur les identifiants de produit.** Le seul identifiant à coder en dur est l'identifiant du placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un flow retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser en cours de session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont retournés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en arrière-plan.</p> | :::note Dans la v4, le paramètre `locale` a été déplacé hors de `getFlow` et placé dans `getFlowConfiguration` (utilisé uniquement lors du rendu avec AdaptyUI). Pour les paywalls personnalisés, toutes les locales disponibles sont retournées ensemble dans `flow.remoteConfigs` — choisissez celle qui correspond à la langue de l'appareil de l'utilisateur ou au paramètre de votre application. ::: N'encodez pas en dur les identifiants de produits ! Puisque les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer avec le temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à encoder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, un tableau `remoteConfigs` (une entrée par locale configurée) et un indicateur `hasViewConfiguration`. Pour récupérer les produits du flow, appelez `getPaywallProducts(flow:)`. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez interroger le tableau de produits qui lui correspond : <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(flow: flow) // the requested products array } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // the requested products array case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) contenant : l'identifiant du produit, le nom du produit, le prix, la devise, la durée de l'abonnement, et plusieurs autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil lui-même. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.localizedPrice`. Cette localisation est basée sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme de nombre avec `product.price`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. semaine, mois, année, etc.), utilisez `product.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionPeriod`. De là, vous pouvez accéder à l'enum `unit` pour obtenir la durée (c.-à-d. jour, semaine, mois, année ou inconnu). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `.month` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionOffer`. Cet objet contient les propriétés suivantes :<br/>• `offerType` : un enum avec les valeurs `introductory`, `promotional` et `winBack`. Les essais gratuits et les abonnements à prix réduit initiaux seront de type `introductory`.<br/>• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, attendez-vous à voir `0` ici.<br/>• `localizedPrice` : un prix formaté de la remise selon la locale de l'utilisateur.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre avec cette propriété. Elle fonctionne de la même manière pour les offres que ce qui est décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée de la remise selon la locale de l'utilisateur. | :::note Dans la v4, tous les produits retournés par `getPaywallProducts(flow:)` incluent déjà les informations d'éligibilité aux offres. L'appel séparé `getPaywallProductsWithoutDeterminingOffer` de la v3 a été supprimé. ::: ## Accélérer la récupération des flows avec un flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher. Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous avez besoin d'afficher des flows différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (ancienne), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment basé sur les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des flows, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, continuez à utiliser `getFlow` décrit [ci-dessus](fetch-paywalls-and-products#fetch-flow-information). ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs font face à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter des requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant d'afficher un Remote Config ou des paywalls personnalisés, vous devez récupérer les informations correspondantes. Notez que cette rubrique porte sur les Remote Configs et les paywalls personnalisés. Pour savoir comment récupérer des paywalls créés avec le Paywall Builder, consultez les guides pour <InlineTooltip tooltip="guides sur la récupération des paywalls Paywall Builder dans votre app">[iOS](get-pb-paywalls), [Android](android-get-pb-paywalls), [React Native](react-native-get-pb-paywalls), [Flutter](flutter-get-pb-paywalls), et [Unity](unity-get-pb-paywalls)</InlineTooltip>. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-ios) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits provenant à la fois de l'App Store et de Google Play. Ces produits multiplateforme sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **Ne codez pas les identifiants de produits en dur.** Le seul identifiant à coder en dur est l'identifiant de placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK essaie de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser en cours de session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comporter différentes requêtes en arrière-plan.</p> | N'encodez pas les IDs de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent évoluer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit les afficher tous les 3 sans nécessiter de modification du code. La seule chose à encoder en dur est l'ID du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config, et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois le paywall récupéré, vous pouvez interroger le tableau de produits qui lui correspond : <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(paywall: paywall) // the requested products array } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProducts(paywall: paywall) { result in switch result { case let .success(products): // the requested products array case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) contenant : l'identifiant du produit, le nom, le prix, la devise, la durée d'abonnement et plusieurs autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher le prix dans une version localisée, utilisez `product.localizedPrice`. Cette localisation est basée sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme numérique via `product.price`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. semaine, mois, année, etc.), utilisez `product.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire jour, semaine, mois, année ou inconnu). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `.month` dans la propriété `unit` et `3` dans la propriété `numberOfUnits`. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionOffer`. Cet objet contient les propriétés suivantes :<br/>• `offerType` : un enum avec les valeurs `introductory`, `promotional` et `winBack`. Les essais gratuits et les abonnements initialement remisés seront de type `introductory`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, la valeur sera `0`.<br/>• `localizedPrice` : le prix de la remise formaté selon la locale de l'utilisateur.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Son fonctionnement est le même que celui décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : la période d'abonnement de la remise formatée selon la locale de l'utilisateur. | ## Vérifier l'éligibilité aux offres de lancement sur iOS \{#check-intro-offer-eligibility-on-ios\} Par défaut, la méthode `getPaywallProducts` vérifie l'éligibilité aux offres de lancement, promotionnelles et de reconquête. Si vous avez besoin d'afficher des produits avant que le SDK détermine l'éligibilité aux offres, utilisez plutôt la méthode `getPaywallProductsWithoutDeterminingOffer`. :::note Après avoir affiché les produits initiaux, pensez à appeler la méthode `getPaywallProducts` habituelle pour mettre à jour les produits avec les informations d'éligibilité aux offres correctes. ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) // the requested products array without subscriptionOffer } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) { result in switch result { case let .success(products): // the requested products array without subscriptionOffer case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> ## Accélérer la récupération des paywalls avec le paywall de l'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs ont une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment basé sur les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](fetch-paywalls-and-products#fetch-paywall-information). ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.2 du SDK iOS. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données mises en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé qu'en cas de réinstallation ou de nettoyage manuel.</p> | </SDKv3> --- # File: present-remote-config-paywalls --- --- title: "Afficher un paywall configuré via Remote Config dans le SDK iOS" description: "Découvrez comment présenter des paywalls Remote Config dans Adapty pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre vue paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé. N'oubliez pas de [vérifier si un utilisateur est éligible à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios) et d'adapter la vue paywall pour gérer le cas où il l'est. ## Récupérer le Remote Config du flow et l'afficher \{#get-flow-remote-config-and-present-it\} En v4, un flow contient une entrée `AdaptyRemoteConfig` par locale configurée dans le tableau `remoteConfigs`. Choisissez la locale correspondant à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in let flow = try? result.get() let config = flow?.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow?.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } ``` </TabItem> </Tabs> À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler en une page visuellement attractive. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, pour une expérience fluide et agréable sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la mise en place du flow d'achat. Quand l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](fallback-paywalls). Ce paywall de secours s'affiche à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Bien que les données d'achat soient collectées automatiquement, l'enregistrement des vues de paywall nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowFlow(flow)` — il sera alors pris en compte dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les vues automatiquement dans ces cas. ::: ```swift showLineNumbers try await Adapty.logShowFlow(flow) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :------- |:-----------------------------------------------------------------------------------------| | **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow(placementId:)`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre vue paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé configuré via Remote Config. N'oubliez pas de [vérifier si un utilisateur est éligible à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios) et d'adapter la vue paywall pour gérer le cas où il l'est. ## Récupérer le Remote Config du paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour récupérer le Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") let headerText = paywall.remoteConfig?.dictionary?["header_text"] as? String } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") { result in let paywall = try? result.get() let headerText = paywall?.remoteConfig?.dictionary?["header_text"] as? String } ``` </TabItem> </Tabs> À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler en une page visuellement attractive. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, pour une expérience fluide et agréable sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la mise en place du flow d'achat. Quand l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](fallback-paywalls). Ce paywall de secours s'affiche à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Bien que les données d'achat soient collectées automatiquement, l'enregistrement des vues de paywall nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowPaywall(paywall)` — il sera alors pris en compte dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```swift showLineNumbers Adapty.logShowPaywall(paywall) ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:-----------------------------------------------------------------------------------------| | **paywall** | obligatoire | Un objet [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall). | </SDKv3> --- # File: making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK iOS" description: "Guide pour gérer les achats intégrés et les abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape indispensable pour proposer aux utilisateurs l'accès à du contenu ou des services premium. Cependant, présenter ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour personnaliser vos paywalls. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode séparée appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode est la porte d'entrée permettant aux utilisateurs d'interagir avec les paywalls et de procéder à leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de sa publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter une seule étape. Sans cela, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](ios-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } } catch { // Handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } case let .failure(error): // Handle the error } } ``` </TabItem> </Tabs> Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Si la requête a abouti, la réponse contient cet objet. Un objet [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur au sein de l'application.</p><p>Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.</p> | :::warning **Remarque :** si vous utilisez encore StoreKit d'Apple en version inférieure à v2.0 et le SDK Adapty en version inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple. ::: ## Achats intégrés depuis l'App Store \{#in-app-purchases-from-the-app-store\} Lorsqu'un utilisateur initie un achat dans l'App Store et que la transaction est transmise à votre application, vous avez deux options : - **Traiter la transaction immédiatement :** Retournez `true` dans `shouldAddStorePayment`. L'écran d'achat Apple s'affichera immédiatement. - **Stocker l'objet produit pour un traitement ultérieur :** Retournez `false` dans `shouldAddStorePayment`, puis appelez `makePurchase` avec le produit stocké plus tard. Cela peut être utile si vous souhaitez afficher quelque chose de personnalisé à l'utilisateur avant de déclencher un achat. Voici le code complet : ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. The Apple purchase system screen will show automatically. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` when the timing is appropriate func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## Utiliser des codes de réduction sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie de code de réduction dans votre application : ```swift showLineNumbers Adapty.presentCodeRedemptionSheet() ``` :::danger D'après nos observations, la feuille de saisie de code de réduction peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, vous devez ouvrir l'URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: --- # File: restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec le SDK iOS" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à du contenu précédemment acheté — abonnements ou achats intégrés — sans être facturés à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leur contenu acheté sans repayer. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.restorePurchases()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.restorePurchases() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.restorePurchases { [weak self] result in switch result { case let .success(profile): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> Paramètres de réponse : | Paramètre | Description | |---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Un objet [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.</p><p>Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.</p> | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: ios-transaction-management --- --- title: "Gestion avancée des transactions dans le SDK iOS" description: "Terminez les transactions manuellement dans votre application iOS avec le SDK Adapty." --- :::note La gestion avancée des transactions est prise en charge dans le SDK iOS Adapty à partir de la version 3.12. ::: La gestion avancée des transactions dans Adapty vous donne plus de contrôle sur la façon dont les transactions sont gérées, vérifiées et finalisées. Elle introduit trois fonctionnalités optionnelles qui fonctionnent ensemble : | Fonctionnalité | Objectif | |-------------------------------------------------------------|----------| | [`appAccountToken`](#assign-appaccounttoken) | Lie les transactions Apple à votre identifiant utilisateur interne | | [`jwsTransaction`](#access-the-jws-representation) | Fournit le payload de transaction signé par Apple pour la validation | | [Finalisation manuelle](#control-transaction-finishing-behavior) | Vous permet de finaliser les transactions uniquement après confirmation du succès par votre backend | Ensemble, ces outils vous permettent de construire des flux de validation personnalisés robustes pendant qu'Adapty continue de synchroniser les transactions avec son backend. :::important La plupart des applications n'en ont pas besoin. Par défaut, Adapty valide et finalise automatiquement les transactions StoreKit. Utilisez ce guide uniquement si vous gérez votre propre validation côté backend ou si vous souhaitez contrôler entièrement le cycle de vie des achats. ::: ## Assigner `appAccountToken` \{#assign-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de lier les transactions de l'App Store à l'identité interne de vos utilisateurs. StoreKit associe ce token à chaque transaction, ce qui permet à votre backend de faire correspondre les données App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications App Store restent correctement liés. Vous pouvez définir le token de deux façons — lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `appAccountToken` avec `customerUserId`. Si vous ne passez que le token, il ne sera pas inclus dans la transaction. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: <APP_ACCOUNT_TOKEN>) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: <APP_ACCOUNT_TOKEN>) { error in if let error { // handle the error } } ``` </TabItem> </Tabs> ## Accéder à la représentation JWS \{#access-the-jws-representation\} Lorsque vous effectuez un achat, le résultat inclut la transaction Apple au [format JWS Compact Serialization](https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo). Vous pouvez transmettre cette valeur à votre backend pour une validation ou une journalisation indépendante. ```swift let result = try await Adapty.makePurchase(product: paywallProduct) let jwsRepresentation = result.jwsTransaction ``` ## Contrôler le comportement de finalisation des transactions \{#control-transaction-finishing-behavior\} Par défaut, Adapty finalise automatiquement les transactions StoreKit après validation. Si vous devez différer la finalisation jusqu'à ce que votre backend confirme le succès, définissez le comportement de finalisation sur manuel. Dans ce mode : - Adapty valide quand même les achats et les synchronise avec son backend. - Les transactions restent non finalisées jusqu'à ce que vous appeliez explicitement `finish()`. ```swift var configBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_API_KEY") .with(transactionFinishBehavior: .manual) try await Adapty.activate(with: configBuilder.build()) ``` Lorsque vous utilisez la finalisation manuelle des transactions, vous devez implémenter la méthode delegate `onUnfinishedTransaction` pour gérer les transactions non finalisées : ```swift showLineNumbers title="Swift" extension YourApp: AdaptyDelegate { func onUnfinishedTransaction(_ transaction: AdaptyUnfinishedTransaction) async { // Perform your custom validation logic here // When ready, finish the transaction await transaction.finish() } } ``` Pour obtenir toutes les transactions non finalisées en cours, utilisez la méthode `getUnfinishedTransactions()` : ```swift let unfinishedTransactions = try await Adapty.getUnfinishedTransactions() ``` --- # File: implement-observer-mode --- --- title: "Implémenter le mode Observateur dans le SDK iOS" description: "Implémentez le mode observateur dans Adapty pour suivre les événements d'abonnement utilisateur dans le SDK iOS." --- Si vous avez déjà votre propre infrastructure d'achat et que vous n'êtes pas prêt à passer entièrement à Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration fluide avec les systèmes d'attribution et d'analytics. Si cela correspond à vos besoins, vous devez uniquement : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. 2. [Signaler les transactions](report-transactions-observer-mode) depuis votre infrastructure d'achat existante à Adapty. Si vous avez également besoin des paywalls et des tests A/B, une configuration supplémentaire est requise, comme décrit ci-dessous. ## Configuration du mode Observateur \{#observer-mode-setup\} Activez le mode Observateur si vous gérez vous-même les achats et le statut des abonnements, et que vous utilisez Adapty pour envoyer les événements d'abonnement et les analytics. :::important En mode Observateur, le SDK Adapty ne fermera aucune transaction — assurez-vous donc de les gérer vous-même. ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: configurationBuilder) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` </TabItem> <TabItem value="swift" label="UIKit" default> ```swift showLineNumbers Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | observerMode | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observateur \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observateur. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls à Remote Config](present-remote-config-paywalls). Pour les paywalls Paywall Builder, suivez les guides de configuration spécifiques pour [iOS](ios-present-paywall-builder-paywalls-in-observer-mode). 3. [Associez les paywalls](report-transactions-observer-mode) aux transactions d'achat. --- # File: report-transactions-observer-mode --- --- title: "Déclarer les transactions en Observer Mode dans le SDK iOS" description: "Déclarez les transactions d'achat en Observer Mode d'Adapty pour obtenir des informations sur les utilisateurs et suivre les revenus dans le SDK iOS." --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+ (current)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez déclarer les transactions depuis votre app store. Il est indispensable de mettre cela en place **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour déclarer explicitement chaque transaction afin qu'Adapty puisse la reconnaître. :::warning **Ne sautez pas la déclaration des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors de la déclaration d'une transaction. Cela relie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) } catch { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | --------------- | ---------- | ------------------------------------------------------------ | | **transaction** | obligatoire | <ul><li> Pour StoreKit 1 : SKPaymentTransaction.</li><li> Pour StoreKit 2 : Transaction.</li></ul> | | **variationId** | optionnel | L'identifiant unique de la variante du paywall. Récupérez-le depuis la propriété `variationId` de l'objet [AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall). | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez déclarer les transactions depuis votre app store ou les restaurer. Il est indispensable de mettre cela en place **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour envoyer les données de transaction à Adapty. :::warning **Ne sautez pas la déclaration des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `withVariationId` lors de la déclaration d'une transaction. Cela relie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) } catch { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | --------------- | ---------- | ------------------------------------------------------------ | | **transaction** | obligatoire | <ul><li> Pour StoreKit 1 : SKPaymentTransaction.</li><li> Pour StoreKit 2 : Transaction.</li></ul> | | **variationId** | optionnel | L'identifiant unique de la variante du paywall. Récupérez-le depuis la propriété `variationId` de l'objet [AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall). | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> **Déclaration des transactions** - Les versions jusqu'à 3.1.x écoutent automatiquement les transactions dans l'App Store, la déclaration manuelle n'est donc pas nécessaire. - La version 3.2 ne prend pas en charge l'Observer Mode. **Association des paywalls aux transactions** Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous comptez utiliser des paywalls et/ou des tests A/B en Observer Mode, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de le faire correctement avant de publier votre application, sinon cela entraînera des erreurs dans les analyses. ```swift let variationId = paywall.variationId // There are two overloads: for StoreKit 1 and StoreKit 2 Adapty.setVariationId(variationId, forPurchasedTransaction: transactionId) { error in if error == nil { // successful binding } } ``` Paramètres de la requête : | Paramètre | Présence | Description | | ------------- | ---------- | ------------------------------------------------------------ | | variationId | obligatoire | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall). | | transactionId | obligatoire | <p>Pour StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</p><p>Pour StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</p> | </TabItem> </Tabs> --- # File: ios-troubleshoot-purchases --- --- title: "Troubleshoot purchases in iOS SDK" description: "Troubleshoot purchases in iOS SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK iOS. ## AdaptyError.cantMakePayments en mode observer \{#adaptyerrorcantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` en utilisant `makePurchase` en mode observer. **Raison** : En mode observer, vous devez gérer les achats de votre côté, et non utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observer. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observer. Consultez [Implémenter le mode Observer](implement-observer-mode) pour plus de détails. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui est introuvable. **Raison** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de complétion d'achat liés au sandbox. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés aux achats non couverts ci-dessus. **Solution** : Migrez le SDK vers la dernière version en utilisant les [guides de migration](ios-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: ios-web-paywall --- --- title: "Implémenter des web paywalls dans le SDK iOS" description: "Configurez un web paywall pour accepter des paiements sans les frais ni les audits de l'App Store." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre web paywall dans le tableau de bord](web-paywall) et d'avoir installé le SDK Adapty version 3.6.1 ou ultérieure. ::: ## Ouvrir des web paywalls \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les web paywalls à l'aide de la méthode SDK. La méthode `.openWebPaywall` : 1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte le retour de vos utilisateurs dans l'app, puis appelle `.getProfile` à intervalles courts pour vérifier si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'app presque immédiatement. ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product) } catch { print("Failed to open web paywall: \(error)") } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall(product)` qui génère des URL par paywall et ajoute également les données du produit aux URL. 2. `openWebPaywall(paywall)` qui génère des URL par paywall sans ajouter les données du produit aux URL. À utiliser lorsque vos produits dans le paywall Adapty diffèrent de ceux du web paywall. ::: ## Gérer les erreurs \{#handle-errors\} | Erreur | Description | Action recommandée | |-----------------------------------------|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | Le paywall n'a pas d'URL d'achat web configurée | Vérifiez si le paywall a été correctement configuré dans l'Adapty Dashboard | | AdaptyError.productWithoutPurchaseUrl | Le produit n'a pas d'URL d'achat web | Vérifiez la configuration du produit dans l'Adapty Dashboard | | AdaptyError.failedOpeningWebPaywallUrl | Impossible d'ouvrir l'URL dans le navigateur | Vérifiez les paramètres de l'appareil ou proposez une autre méthode d'achat | | AdaptyError.failedDecodingWebPaywallUrl | Échec de l'encodage des paramètres dans l'URL | Vérifiez que les paramètres de l'URL sont valides et correctement formatés | ## Exemple d'implémentation \{#implementation-example\} ```swift showLineNumbers title="Swift" class SubscriptionViewController: UIViewController { var paywall: AdaptyPaywall? @IBAction func purchaseButtonTapped(_ sender: UIButton) { guard let paywall = paywall, let product = paywall.products.first else { return } Task { await offerWebPurchase(for: product) } } func offerWebPurchase(for paywallProduct: AdaptyPaywallProduct) async { do { // Attempt to open web paywall try await Adapty.openWebPaywall(for: paywallProduct) } catch let error as AdaptyError { switch error { case .paywallWithoutPurchaseUrl, .productWithoutPurchaseUrl: showAlert(message: "Web purchase is not available for this product.") case .failedOpeningWebPaywallUrl: showAlert(message: "Could not open web browser. Please try again.") default: showAlert(message: "An error occurred: \(error.localizedDescription)") } } catch { showAlert(message: "An unexpected error occurred.") } } // Helper methods private func showAlert(message: String) { /* ... */ } } ``` :::note Lorsque les utilisateurs reviennent dans l'app, actualisez l'interface pour refléter les mises à jour du profil. `AdaptyDelegate` recevra et traitera les événements de mise à jour du profil. ::: ## Ouvrir des web paywalls dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} :::important L'ouverture des web paywalls dans un navigateur intégré est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les web paywalls s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les web paywalls dans un navigateur intégré. La page d'achat web s'affiche alors directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans quitter l'app. Pour activer cette option, définissez le paramètre `in` sur `.inAppBrowser` : ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product, in: .inAppBrowser) // default – .externalBrowser } catch { print("Failed to open web paywall: \(error)") } ``` --- # File: ios-user --- --- title: "Utilisateurs et accès dans le SDK iOS" description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application iOS avec le SDK Adapty." --- <CustomDocCardList /> --- # File: identifying-users --- --- title: "Identifier les utilisateurs dans le SDK iOS" description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées." --- Adapty crée un ID de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera transmis à toutes les intégrations. ## Définir le Customer User ID lors de la configuration \{#set-customer-user-id-on-configuration\} Si vous disposez d'un ID utilisateur au moment de la configuration, passez-le simplement comme paramètre `customerUserId` à la méthode `.activate()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` </TabItem> </Tabs> :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Définir le Customer User ID après la configuration \{#set-customer-user-id-after-configuration\} Si vous ne disposez pas d'un ID utilisateur lors de la configuration du SDK, vous pouvez le définir plus tard à tout moment avec la méthode `.identify()`. Les cas les plus courants pour utiliser cette méthode sont après une inscription ou une connexion, lorsque l'utilisateur passe d'un utilisateur anonyme à un utilisateur authentifié. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> </Tabs> Paramètres de la requête : - **Customer User ID** (requis) : un identifiant utilisateur sous forme de chaîne de caractères. :::warning Resoumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces situations, le SDK Adapty basculera automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, comme des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez resoumettre ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ## Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` </TabItem> </Tabs> Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`. ## Définir l'appAccountToken \{#set-appaccounttoken\} L'[`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un UUID qui aide StoreKit 2 d'Apple à identifier les utilisateurs sur plusieurs installations et appareils. À partir du SDK Adapty iOS 3.10.2, vous pouvez passer l'`appAccountToken` lors de la configuration du SDK ou lors de l'identification d'un utilisateur : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) { error in if let error { // handle the error } } ``` </TabItem> </Tabs> Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`. ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK iOS" description: "Apprenez à définir des attributs utilisateur dans Adapty pour améliorer la segmentation des audiences." --- Vous pouvez définir des attributs optionnels comme l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Ces attributs peuvent ensuite être utilisés pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir des attributs utilisateur, appelez la méthode `.updateProfile()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) Adapty.updateProfile(params: builder.build()) { error in if error != nil { // handle the error } } ``` </TabItem> </Tabs> Notez que les attributs définis précédemment via la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés autorisées `<Key>` de `AdaptyProfileParameters.Builder` et les valeurs `<Value>` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum, valeurs autorisées : `female`, `male`, `other` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, et les exploiter dans vos analyses pour identifier quelles métriques produit influencent le plus les revenus. ```swift showLineNumbers do { builder = try builder.with(customAttribute: "value1", forKey: "key1") } catch { // handle key/value validation error } ``` Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` : ```swift showLineNumbers do { builder = try builder.withRemoved(customAttributeForKey: "key2") } catch { // handle error } ``` Il peut arriver que vous ayez besoin de consulter les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut ne pas être à jour, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment — les attributs côté serveur ont donc pu changer depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clés peuvent comporter jusqu'à 30 caractères. Ils peuvent contenir des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre décimal, avec 50 caractères maximum. --- # File: subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK iOS" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention." --- Avec Adapty, suivre le statut d'abonnement est simple. Vous n'avez pas à insérer manuellement des identifiants de produits dans votre code. Il vous suffit de vérifier le statut d'abonnement d'un utilisateur en contrôlant l'existence d'un [niveau d'accès](access-level) actif. Avant de commencer à vérifier le statut d'abonnement, configurez les [notifications serveur App Store](enable-app-store-server-notifications). ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). Nous recommandons de récupérer le profil au démarrage de votre application, par exemple lorsque vous [identifiez un utilisateur](identifying-users#set-customer-user-id-on-configuration), puis de le mettre à jour à chaque modification. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander constamment. Pour être notifié des mises à jour du profil, écoutez les changements comme décrit dans la section [Écouter les mises à jour du statut d'abonnement](subscription-status#listening-for-subscription-status-updates) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> </Tabs> Paramètres de la réponse : | Paramètre | Description | | --------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile | <p>Un objet [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.</p><p></p><p>La méthode `.getProfile` fournit le résultat le plus à jour, car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion Internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données en cache sont retournées. Il est également important de noter que le SDK Adapty met à jour le cache `AdaptyProfile` régulièrement afin de maintenir ces informations aussi à jour que possible.</p> | La méthode `.getProfile()` vous fournit le profil utilisateur depuis lequel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de journal et que vous vendez des abonnements à différents sujets indépendamment, vous pouvez créer des niveaux d'accès « sports » et « science ». Mais la plupart du temps, vous n'aurez besoin que d'un seul niveau d'accès ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès par défaut « premium ». Voici un exemple pour vérifier le niveau d'accès « premium » par défaut : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() let isPremium = profile.accessLevels["premium"]?.isActive ?? false // grant access to premium features } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get(), profile.accessLevels["premium"]?.isActive ?? false { // grant access to premium features } } ``` </TabItem> </Tabs> ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir les messages d'Adapty, vous devez effectuer quelques configurations supplémentaires : ```swift showLineNumbers Adapty.delegate = self // To receive subscription updates, extend `AdaptyDelegate` with this method: nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { // handle any changes to subscription state } ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache implémenté dans le SDK Adapty stocke le statut d'abonnement du profil. Cela signifie que même si le serveur est indisponible, les données en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil. Il est toutefois important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier les éventuelles mises à jour liées au profil. En cas de modifications — nouvelles transactions ou autres changements — elles sont transmises aux données en cache afin de les maintenir synchronisées avec le serveur. --- # File: ios-deal-with-att --- --- title: "Gérer l'ATT dans le SDK iOS" description: "Démarrez avec Adapty sur iOS pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers if #available(iOS 14, macOS 11.0, *) { let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) Adapty.updateProfile(params: builder.build()) { [weak self] error in if error != nil { // handle the error } } } ``` </TabItem> </Tabs> :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de transmettre les données en temps opportun aux intégrations que vous avez configurées. ::: --- # File: kids-mode --- --- title: "Mode Enfants dans le SDK iOS" description: "Activez facilement le mode Enfants pour respecter les politiques Apple. Aucune donnée IDFA ni publicitaire collectée dans le SDK iOS." --- <SDKv4> Si votre application iOS est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour répondre à ces politiques et passer les révisions de l'App Store. ## Qu'est-ce qui est requis ? \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte de : - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `<Prénom.NomDeFamille>` sera inévitablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activation du mode Enfants \{#enabling-kids-mode\} ### Mises à jour dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte d'adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Mises à jour dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} À partir du SDK 4.0, le mode Enfants est un trait de package Swift nommé `KidsMode`. L'activation de ce trait exclut IDFA et AdSupport de l'ensemble du SDK lors de la compilation — vous conservez les modules habituels **Adapty** et **AdaptyUI** ainsi que les instructions d'import habituelles `import Adapty` / `import AdaptyUI`. :::note Le trait `KidsMode` est disponible à partir de la version 4.0 du SDK. À partir du SDK 4.0, le SDK s'installe uniquement via Swift Package Manager — CocoaPods n'est plus pris en charge. ::: <Tabs> <TabItem value="xcode" label="Xcode" default> 1. [Installez le SDK Adapty](sdk-installation-ios) normalement, en sélectionnant les modules habituels **Adapty** et **AdaptyUI**. 2. Dans Xcode 26.4 ou ultérieur, ouvrez les paramètres de votre projet, accédez à la vue **Package Dependencies** et activez le trait **KidsMode** pour la dépendance AdaptySDK-iOS. :::note Les versions de Xcode antérieures à 26.4 ne permettent pas d'activer des traits pour un projet Xcode depuis l'interface. Dans ce cas, ajoutez un petit package Swift local qui dépend d'Adapty avec le trait `KidsMode` activé (voir l'onglet **Package.swift**), et faites dépendre la cible de votre application de ce package. ::: </TabItem> <TabItem value="spm" label="Package.swift"> Si vous ajoutez Adapty comme dépendance dans `Package.swift`, activez le trait dans la déclaration du package. Les traits nécessitent `swift-tools-version` 6.1 ou ultérieur. ```swift showLineNumbers title="Package.swift" .package( url: "https://github.com/adaptyteam/AdaptySDK-iOS.git", from: "4.0.0", traits: ["KidsMode"] ) ``` </TabItem> </Tabs> </SDKv4> <SDKv3> Si votre application iOS est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour répondre à ces politiques et passer les révisions de l'App Store. ## Qu'est-ce qui est requis ? \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte de : - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `<Prénom.NomDeFamille>` sera inévitablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activation du mode Enfants \{#enabling-kids-mode\} ### Mises à jour dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte d'adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Mises à jour dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, désactivez la collecte de l'IDFA et de l'adresse IP de l'utilisateur. <Tabs> <TabItem value="spm" label="Swift Package Manager" default> Si vous utilisez Swift Package Manager, vous pouvez activer le mode Enfants en sélectionnant le module **Adapty_KidsMode** dans Xcode lors de l'installation du SDK. Dans Xcode, accédez à **File** -> **Add Package Dependency...**. Notez que les étapes d'ajout de dépendances de package peuvent varier selon les versions de Xcode, référez-vous donc à la documentation Xcode si nécessaire. 1. Saisissez l'URL du dépôt : ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. Sélectionnez la version (la dernière version stable est recommandée) et cliquez sur **Add Package**. 3. Dans la fenêtre **Choose Package Products**, sélectionnez les modules dont vous avez besoin : - **Adapty_KidsMode** (module principal) - **AdaptyUI_KidsMode** (optionnel - uniquement si vous prévoyez d'utiliser le Paywall Builder) Vous n'aurez besoin d'aucun autre package. 4. Cliquez sur **Add Package** pour terminer l'installation. 5. Dans votre code, écrivez `import Adapty_KidsMode` à la place de `import Adapty`, et `import AdaptyUI_KidsMode` à la place de `import AdaptyUI` : ```swift ``` </TabItem> <TabItem value="cocoapods" label="CocoaPods"> 1. Mettez à jour votre Podfile : - Si vous **n'avez pas** de section `post_install`, ajoutez l'intégralité du bloc de code ci-dessous. - Si vous **avez** déjà une section `post_install`, fusionnez les lignes surlignées avec elle. ```ruby showLineNumbers title="Podfile" def adapty_enable_kids_mode(installer) installer.pods_project.targets.each do |target| next unless target.name == 'Adapty' target.build_configurations.each do |config| flags = config.build_settings['OTHER_SWIFT_FLAGS'] || '$(inherited)' flags = flags.join(' ') if flags.is_a?(Array) config.build_settings['OTHER_SWIFT_FLAGS'] = "#{flags} -DADAPTY_KIDS_MODE" end target.frameworks_build_phase.files.dup.each do |bf| target.frameworks_build_phase.remove_build_file(bf) if bf.display_name.to_s.include?('AdSupport') end end installer.pods_project.save Dir.glob(File.join(installer.sandbox.root, 'Target Support Files', '**', '*.xcconfig')).each do |xc| File.write(xc, File.read(xc).gsub(/\s*-framework\s+"?AdSupport"?/, '')) end end post_install do |installer| # ... conservez le contenu existant de votre post_install (Flutter en ajoute un automatiquement) ... adapty_enable_kids_mode(installer) # <-- activer le mode Enfants Adapty end ``` 2. Exécutez la commande suivante pour appliquer les modifications : ```sh showLineNumbers title="Shell" pod install ``` </TabItem> </Tabs> </SDKv3> --- # File: ios-onboardings --- --- title: "Onboardings dans le SDK iOS" description: "Découvrez comment utiliser les onboardings dans votre application iOS avec le SDK Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui offre des animations plus fluides, un rendu cohérent avec l'interface iOS, des temps de chargement plus rapides et aucune dépendance à un runtime WebView. Consultez [Obtenir des flows & paywalls](get-pb-paywalls) et [Afficher des flows & paywalls](ios-present-paywalls) pour commencer. ::: <CustomDocCardList /> --- # File: get-onboardings --- --- title: "Récupérer les onboardings et leur configuration" description: "Apprenez à récupérer les onboardings dans Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une expérience iOS cohérente, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows & paywalls](get-pb-paywalls) et [Afficher des flows & paywalls](ios-present-paywalls) pour commencer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer l'onboarding associé au placement ainsi que sa configuration de vue, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé [le SDK Adapty iOS, Android, React Native ou Flutter](installation-of-adapty-sdks) version 3.8.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'intégralité de l'expérience — le contenu affiché, la façon dont il est présenté, et la manière dont les interactions utilisateur (comme les réponses aux quiz ou les saisies de formulaires) sont traitées. Le conteneur suit également automatiquement les événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi des vues séparé. Pour des performances optimales, récupérez la configuration de l'onboarding suffisamment tôt pour que les images aient le temps de se télécharger avant d'être affichées aux utilisateurs. Pour obtenir un onboarding, utilisez la méthode `getOnboarding` : ```swift showLineNumbers do { let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // the requested onboarding } catch { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatoire | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de locale](localizations-and-locale-codes) pour plus d'informations sur les codes de locale et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne verront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé qu'en cas de réinstallation ou de nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en interne.</p> | Paramètres de réponse : | Paramètre | Description | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://swift.adapty.io/documentation/adapty/adaptyonboarding) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. | ## Accélérer la récupération des onboardings avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un onboarding par défaut pour garantir une expérience fluide plutôt que de ne rien afficher. Pour y remédier, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer l'onboarding via la méthode `getOnboarding`, comme détaillé dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : Peut créer des difficultés pour la prise en charge de plusieurs versions d'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions s'affichent incorrectement. - **Absence de personnalisation** : Affiche uniquement le contenu pour l'audience « All Users », sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si la récupération plus rapide l'emporte sur ces inconvénients dans votre cas, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```swift showLineNumbers Adapty.getOnboardingForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(onboarding): // the requested onboarding case let .failure(error): // handle the error } } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatoire | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de locale](localizations-and-locale-codes) pour plus d'informations sur les codes de locale et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne verront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé qu'en cas de réinstallation ou de nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache régulièrement mis à jour décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | --- # File: ios-present-onboardings --- --- title: "Présenter les onboardings dans le SDK iOS" description: "Découvrez comment présenter des onboardings sur iOS pour booster vos conversions et vos revenus." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui vous offre des animations plus fluides, un rendu cohérent avec l'interface iOS, des temps de chargement plus rapides et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows et paywalls](get-pb-paywalls) et [Afficher des flows et paywalls](ios-present-paywalls) pour démarrer. ::: Si vous avez personnalisé un onboarding avec le builder, vous n'avez pas à vous soucier de son rendu dans votre code d'application mobile pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et la façon dont il doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez installé [le SDK Adapty iOS](sdk-installation-ios) version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Présenter des onboardings en Swift \{#present-onboardings-in-swift\} Pour afficher l'onboarding visuel sur l'écran de l'appareil, procédez comme suit : 1. Obtenez la configuration de vue de l'onboarding avec la méthode `.getOnboardingConfiguration`. 2. Initialisez l'onboarding visuel que vous souhaitez afficher avec la méthode `.onboardingController` : Paramètres de la requête : | Paramètre | Présence | Description | |:---------------------------------|:----------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding configuration** | requis | Un objet `AdaptyUI.OnboardingConfiguration` contenant toutes les propriétés de l'onboarding. Utilisez la méthode `AdaptyUI.getOnboardingConfiguration` pour l'obtenir. | | **delegate** | requis | Un `AdaptyOnboardingControllerDelegate` pour écouter les événements de l'onboarding. | Retourne : | Objet | Description | |:---------------------------------|:---------------------------------------------------------------| | **AdaptyOnboardingController** | Un objet représentant l'écran d'onboarding demandé | 3. Une fois l'objet créé avec succès, vous pouvez l'afficher à l'écran de l'appareil : ```swift showLineNumbers title="Swift" import Adapty import AdaptyUI // 0. Get an onboarding if you haven't done it yet let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Create Onboarding View Controller let onboardingController = try AdaptyUI.onboardingController( with: configuration, delegate: <AdaptyOnboardingControllerDelegate> ) // 3. Present it to the user present(onboardingController, animated: true) ``` ## Présenter des onboardings en SwiftUI \{#present-onboardings-in-swiftui\} Pour afficher l'onboarding visuel sur l'écran de l'appareil en SwiftUI : ```swift showLineNumbers title="SwiftUI" // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Display the Onboarding View within your view hierarchy AdaptyOnboardingView( configuration: configuration, placeholder: { Text("Your Placeholder View") }, onCloseAction: { action in // hide the onboarding view }, onError: { error in // handle the error } ) ``` ## Ajouter des transitions fluides entre l'écran de démarrage et l'onboarding \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\} Par défaut, entre l'écran de démarrage et l'onboarding, un écran de chargement s'affiche jusqu'à ce que l'onboarding soit entièrement chargé. Si vous souhaitez rendre cette transition plus fluide, vous pouvez la personnaliser et soit prolonger l'écran de démarrage, soit afficher autre chose. Pour cela, définissez un placeholder (ce qui sera affiché pendant le chargement de l'onboarding). Si vous définissez un placeholder, l'onboarding se chargera en arrière-plan et s'affichera automatiquement une fois prêt. <Tabs> <TabItem value="swift" label="UIKit"> ```swift showLineNumbers extension YourOnboardingManagerClass: AdaptyOnboardingControllerDelegate { func onboardingsControllerLoadingPlaceholder( _ controller: AdaptyOnboardingController ) -> UIView? { // instantiate and return the UIView which will be presented while onboarding is being loaded } } ``` </TabItem> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers AdaptyOnboardingView( configuration: configuration, placeholder: { // define your placeholder view, which will be presented while onboarding is being loaded }, // the rest of the implementation ) ``` </TabItem> </Tabs> ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15.1. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web directement dans votre application, sans avoir à changer d'app. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `.externalBrowser` : ```swift showLineNumbers let configuration = try AdaptyUI.getOnboardingConfiguration( forOnboarding: onboarding, externalUrlsPresentation: .externalBrowser // default – .inAppBrowser ) ``` --- # File: ios-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK iOS" description: "Gérez les événements liés à l'onboarding sur iOS avec Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu cohérent avec iOS, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Récupérer les flows et paywalls](get-pb-paywalls) et [Afficher les flows et paywalls](ios-present-paywalls) pour commencer. ::: Avant de commencer, vérifiez que : 1. Vous avez installé le [SDK Adapty iOS](sdk-installation-ios) en version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Les onboardings configurés avec le builder génèrent des événements auxquels votre app peut réagir. Découvrez ci-dessous comment gérer ces événements. Pour contrôler ou surveiller les processus qui se déroulent sur l'écran d'onboarding dans votre application mobile, implémentez les méthodes de `AdaptyOnboardingControllerDelegate`. ## Actions personnalisées \{#custom-actions\} Dans le builder, vous pouvez ajouter une action **personnalisée** à un bouton et lui attribuer un identifiant. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez ensuite utiliser cet identifiant dans votre code et le traiter comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé tel que **Login** ou **Allow notifications**, la méthode déléguée `onboardingController` sera déclenchée avec le cas `.custom(id:)` et le paramètre `actionId` correspond à l'**Action ID** défini dans le builder. Vous pouvez créer vos propres identifiants, par exemple "allowNotifications". ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) { if action.actionId == "allowNotifications" { // Request notification permissions } } func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) { // Handle errors } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton auquel l'action **Close** est associée. <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Notez que vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: Par exemple : ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) { controller.dismiss(animated: true) } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall si vous souhaitez l'afficher à l'intérieur de l'onboarding. Si vous voulez ouvrir un paywall après la fermeture de l'onboarding, il existe une approche plus directe : gérez [`AdaptyOnboardingsCloseAction`](#closing-onboarding) et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La méthode la plus fluide pour utiliser des paywalls dans les onboardings consiste à définir l'action ID comme étant égal à l'identifiant de placement du paywall. Ainsi, après le déclenchement de `AdaptyOnboardingsOpenPaywallAction`, vous pouvez utiliser l'identifiant de placement pour récupérer et ouvrir le paywall immédiatement. Notez qu'une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous présentez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding en arrière-plan par programmation. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue de l'onboarding avant de présenter le paywall. ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onPaywallAction action: AdaptyOnboardingsOpenPaywallAction) { // Dismiss onboarding before presenting the flow controller.dismiss(animated: true) { Task { do { // Get the flow using the placement ID from the action let flow = try await Adapty.getFlow(placementId: action.actionId) // Get the flow configuration let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow ) // Create and present the flow controller let flowController = try AdaptyUI.flowController( with: flowConfiguration, delegate: self ) // Present the flow from the root view controller if let rootVC = UIApplication.shared.windows.first?.rootViewController { rootVC.present(flowController, animated: true) } } catch { // Handle any errors that occur during flow loading print("Failed to present flow: \(error)") } } } } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Lorsqu'un onboarding finit de se charger, cette méthode est appelée : ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, didFinishLoading action: OnboardingsDidFinishLoadingAction) { // Handle loading completion } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## Suivi de la navigation \{#tracking-navigation\} La méthode `onAnalyticsEvent` est appelée lorsque divers événements analytiques se produisent durant le flow d'onboarding. L'objet `event` peut être de l'un des types suivants : |Type | Description | |------------|-------------| | `onboardingStarted` | Lorsque l'onboarding a été chargé | | `screenPresented` | Lorsqu'un écran est affiché | | `screenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque les utilisateurs effectuent une action pour quitter l'écran. | | `secondScreenPresented` | Lorsque le deuxième écran est affiché | | `userEmailCollected` | Déclenché lorsque l'e-mail de l'utilisateur est collecté via le champ de saisie | | `onboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, [attribuez l'ID `final` au dernier écran](design-onboarding). | | `unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `screensTotal` | Nombre total d'écrans dans le flow | Voici un exemple d'utilisation des événements analytiques pour le suivi : ```swift func onboardingController(_ controller: AdaptyOnboardingController, onAnalyticsEvent event: AdaptyOnboardingsAnalyticsEvent) { switch event { case .onboardingStarted(let meta): // Track onboarding start trackEvent("onboarding_started", meta: meta) case .screenPresented(let meta): // Track screen presentation trackEvent("screen_presented", meta: meta) case .screenCompleted(let meta, let elementId, let reply): // Track screen completion with user response trackEvent("screen_completed", meta: meta, elementId: elementId, reply: reply) case .onboardingCompleted(let meta): // Track successful onboarding completion trackEvent("onboarding_completed", meta: meta) case .unknown(let meta, let name): // Handle unknown events trackEvent(name, meta: meta) // Handle other cases as needed } } ``` <Details> <summary>Exemples d'événements (cliquer pour développer)</summary> ```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 } } ``` </Details> --- # File: ios-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK iOS" description: "Enregistrez et utilisez les données des onboardings dans votre application iOS avec le SDK Adapty." --- :::tip **À partir du SDK v4**, vous pouvez créer des [flows](get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui vous offre des animations plus fluides, un look and feel iOS cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et des paywalls](get-pb-paywalls) et [Afficher des flows et des paywalls](ios-present-paywalls) pour commencer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de texte, la méthode `onStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Store user preferences or responses switch action.params { case .select(let params): // Handle single selection case .multiSelect(let params): // Handle multiple selections case .input(let params): // Handle text input case .datePicker(let params): // Handle date selection } } ``` L'objet `action` contient : | Paramètre | Description | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | Un identifiant unique pour l'élément de saisie. Vous pouvez l'utiliser pour associer les questions aux réponses lors de leur enregistrement. | | `params` | L'objet de données de saisie de l'utilisateur contenant les propriétés de type et de valeur. | | `params.type` | Le type d'élément de saisie. Peut être :<br/>• `"select"` - Sélection unique parmi des options<br/>• `"multiSelect"` - Sélections multiples parmi des options<br/>• `"input"` - Champ de saisie de texte<br/>• `"datePicker"` - Sélection de date | | `params.value` | La ou les valeurs sélectionnées ou saisies par l'utilisateur. La structure dépend du type :<br/>• `select` : Objet avec `id`, `value`, `label`<br/>• `multiSelect` : Tableau d'objets avec `id`, `value`, `label`<br/>• `input` : Objet avec `type`, `value`<br/>• `datePicker` : Objet avec `day`, `month`, `year` | <Details> <summary>Exemples de données enregistrées (peuvent différer selon votre implémentation)</summary> ```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 } } } ``` </Details> ## Cas d'usage \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de lui demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci : ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Store user preferences or responses switch action.params { case .input(let params): // Handle text input let builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field switch action.elementId { case "name": builder.with(firstName: params.value.value) case "email": builder.with(email: params.value.value) default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` ### Personnaliser les paywalls selon les réponses \{#customize-paywalls-based-on-answers\} En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et assignez des ID significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs ID et [définissez des attributs personnalisés](setting-user-attributes) pour les utilisateurs. ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Handle quiz responses and set custom attributes switch action.params { case .select(let params): // Handle quiz selection let builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes switch action.elementId { case "experience": // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) try? builder.with(customAttribute: params.value.value, forKey: "experience") default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](ios-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](ios-handling-onboarding-events#opening-a-paywall). --- # File: ios-best-practices --- --- title: "Meilleures pratiques avec le SDK iOS" description: "Modèles de référence pour intégrer le SDK Adapty sur iOS — ordre des appels, gestion des erreurs et autres règles de production." --- <CustomDocCardList /> --- # File: ios-sdk-call-order --- --- title: "Ordre d'appel dans le SDK iOS" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs intermittentes #2002 en appelant les méthodes du SDK Adapty dans le bon ordre." --- `Adapty.activate()` doit se terminer avant tout autre appel de méthode du SDK Adapty. Tant qu'il n'est pas résolu, le SDK n'a aucun état. Tout appel émis avant ou en parallèle de `activate()` échoue avec [`#2002 notActivated`](ios-sdk-error-handling#network-errors). Si votre application authentifie les utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty.identify()` à ce moment-là. N'appelez pas de méthodes liées aux actions utilisateur avant que `identify` ne soit résolu. Les appels qui s'exécutent en parallèle échouent avec [`#3006 profileWasChanged`](ios-sdk-error-handling#general-errors), ou atterrissent sur le profil anonyme créé à l'activation. Lorsque cela se produit, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété d'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et d'analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre parcours dépend de deux choses : le moment où vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou d'analytics. - **Étapes 2 et 5** : Obligatoires pour chaque application. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou d'analytics (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et récupère l'identifiant utilisateur client après le lancement. Si vous disposez de l'identifiant utilisateur client au lancement de l'application, passez-le directement dans `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, donc l'étape 4 est inutile. | Étape | Appel | Quand | Notes | |-------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou d'analytics (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'application, en premier | Attendez le callback d'UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `Adapty.activate(with: config)` avec `customerUserId` défini sur la config | Lancement de l'application, après l'étape 1, si vous avez l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `Adapty.activate(with: config)` sans `customerUserId` | Lancement de l'application, après l'étape 1, si vous n'avez pas l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `Adapty.setIntegrationIdentifier(...)` pour chaque MMP | Après l'étape 2, avant tout appel lié aux actions utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. | | 4 | `try await Adapty.identify("YOUR_USER_ID")` | Après l'étape 3 (ou l'étape 2 si pas de MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Toujours `await`. Les appels concurrents pendant `identify` produisent `#3006 profileWasChanged`. | | 5 | `getPaywall`, `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 si pas de MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne la perte d'accès premium pour les utilisateurs de retour, l'absence d'`appsflyer_id` sur les profils, et des paywalls renvoyés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si les utilisateurs achètent via un checkout web (Stripe, Paddle, FunnelFox) et installent ensuite l'application native, le premier `activate()` sur l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flux d'authentification ou le référent d'installation), passez-le directement dans `activate()`. Sinon, l'achat web reste invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque checkout web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: ios-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK iOS" description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour iOS." --- Une récupération de paywall fiable sur iOS repose sur trois éléments : un rendu rapide, le retour du paywall ciblé par audience, et un repli élégant en cas de réseau lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir. :::tip Ces règles supposent que `Adapty.activate()` et `Adapty.identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK iOS](ios-sdk-call-order). ::: ## Règles et pièges \{#rules-and-pitfalls\} | À faire | À éviter | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements simultanément au lancement. | La pré-récupération en masse bloque le thread principal et provoque un écran noir pendant la salve. | | Appelez `getPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `onProfileUpdate`. | Appeler `getPaywall` dans `App.init()`. | L'attribution n'est pas encore disponible. Le paywall se résout sur l'audience par défaut et ignore silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment sur `getPaywall`. | Sans timeout, les utilisateurs avec une mauvaise connexion voient un écran vide jusqu'à ce que le réseau réponde — ou ferment l'application. | Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour une mauvaise connectivité \{#tune-for-poor-connectivity\} Pour les marchés avec une connectivité systématiquement mauvaise (zones rurales, transports en commun, régions affectées par le routage) : - Définissez `fetchPolicy: .returnCacheDataElseLoad` sur chaque récupération sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans le tableau de bord Adapty. - Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le timeout se déclenche. - Ne conditionnez pas l'affichage du paywall à `getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: ios-show-aa-targeted-paywall --- --- title: "Afficher un paywall ciblé par AA au premier lancement dans le SDK iOS" description: "Attendez l'attribution Apple Ads avant de demander le paywall sur iOS en utilisant AdaptyProfile.appliedAttributionSources." --- L'attribution Apple Ads (AA) arrive de manière asynchrone après `Adapty.activate()`. Si vous appelez `getPaywall` trop tôt, l'attribution n'a souvent pas encore été reçue et Adapty résout le placement par rapport à l'audience par défaut — contournant ainsi vos paywalls segmentés par AA. `AdaptyProfile.appliedAttributionSources` permet à l'app de détecter quand l'attribution AA a été appliquée au profil, afin que la requête de paywall puisse attendre que la segmentation AA se résolve correctement. ## Avant de commencer \{#before-you-start\} Vous avez besoin de : - SDK Adapty iOS **3.17.1** ou version ultérieure. - Apple Ads configuré pour l'app dans Adapty. Voir [Apple Ads](apple-search-ads). ## Fonctionnement \{#how-it-works\} Après `Adapty.activate()`, le SDK demande l'attribution Apple Ads à Apple en arrière-plan et transmet le résultat au backend d'Adapty. Lorsqu'AA devient la source d'attribution active pour le profil, le SDK délivre un `AdaptyProfile` mis à jour dont le tableau `appliedAttributionSources` contient `.appleAds`. Un tableau vide peut signifier l'un des cas suivants : - L'attribution Apple Ads n'a pas encore été traitée pour ce profil. - Aucune attribution n'est arrivée du tout. Même avec un tableau vide, `getPaywall` reste sûr à appeler — Adapty résout la requête par rapport à l'audience qui correspond à l'état actuel du profil, généralement l'audience par défaut. :::important L'attente s'applique uniquement au **premier lancement**. Une fois l'attribution Apple Ads enregistrée, elle est stockée définitivement sur le profil. À chaque lancement suivant, le profil en cache contient déjà `.appleAds` dans `appliedAttributionSources`, `didLoadLatestProfile` se déclenche immédiatement avec cette valeur, et `getPaywall` retourne le paywall segmenté par Apple Ads sans aucun délai. ::: ## Implémentation \{#implementation\} Au premier lancement, surveillez `.appleAds` dans le profil et appliquez un délai d'expiration strict — si l'attribution Apple Ads n'arrive jamais, ces utilisateurs doivent quand même voir un paywall. 1. **Activez le SDK.** Voir [Installer et configurer le SDK iOS](sdk-installation-ios). 2. **Abonnez-vous aux mises à jour du profil** en vous conformant à `AdaptyDelegate` et en implémentant `didLoadLatestProfile`. Si vous n'avez pas encore configuré le délégué, voir [Écouter les mises à jour d'abonnement](ios-check-subscription-status#listen-to-subscription-updates). 3. **Surveillez `.appleAds` dans `appliedAttributionSources`.** Lorsqu'il apparaît, demandez le paywall — Adapty retournera la variante segmentée par AA : ```swift extension <YourAdaptyDelegateImpl>: AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { if profile.appliedAttributionSources.contains(where: { $0 == .appleAds }) { // load paywall via Adapty.getPaywall(placementId:) } } } ``` 4. **Démarrez un minuteur de 3 à 5 secondes en parallèle de l'abonnement.** Si le minuteur se déclenche avant l'apparition de `.appleAds`, demandez le paywall quand même : La première des deux voies à se déclencher doit charger le paywall ; l'autre doit être ignorée. Utilisez un indicateur d'état unique (par exemple, `hasLoadedPaywall`) pour éviter les doublons afin que le paywall ne soit pas récupéré deux fois. Configurez un [paywall de secours](fallback-paywalls) pour le placement afin que l'utilisateur ne reste jamais bloqué si la requête réseau échoue. ## Exemple complet \{#complete-example\} L'implémentation ci-dessous met en compétition l'attribution contre un délai d'expiration, pré-charge le paywall de l'audience par défaut en parallèle, et retourne le paywall approprié. L'appelant attend une seule fonction async — pas de délégués ni d'indicateurs d'état à gérer côté appelant. `ProfileObserver` est un singleton réutilisable qui publie les mises à jour de profil depuis `AdaptyDelegate`. `PaywallLoader.getPaywallOrDefault` lance la course en utilisant un `TaskGroup` à concurrence structurée : - Si l'attribution arrive avant `timeout`, il retourne le paywall segmenté via `getPaywall(placementId:)`. - Si `timeout` s'écoule en premier, il retourne le paywall de l'audience par défaut pré-chargé via `getPaywallForDefaultAudience(placementId:)`. ```swift title="PaywallLoader.swift" /// Demonstrates how to fetch a paywall that depends on attribution being applied, /// falling back to the default-audience paywall if attribution doesn't arrive in time. /// /// Stateless and self-contained: every call kicks off its own default-audience /// prefetch and races it against attribution + segmented fetch. enum PaywallLoader { static func getPaywallOrDefault( placementId: String, timeout: TimeInterval ) async throws -> AdaptyPaywall { struct TimedOut: Error {} // Kick off the default-audience request immediately so it has the full // `timeout` window to load. We'll either cancel it on success or await // its result on timeout — never a duplicate network call. let defaultPaywallTask = Task { try await Adapty.getPaywallForDefaultAudience(placementId: placementId) } do { // Race two child tasks: whichever finishes first wins. let result = try await withThrowingTaskGroup(of: AdaptyPaywall.self) { group in // 1. Wait for attribution, then ask Adapty for the segmented paywall. group.addTask { await waitForAttribution() return try await Adapty.getPaywall(placementId: placementId) } // 2. Time-bomb: throws `TimedOut` after `timeout` seconds. group.addTask { try await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000)) throw TimedOut() } guard let value = try await group.next() else { throw CancellationError() } group.cancelAll() // stop the loser (sleeper or the attribution wait). return value } // Segmented paywall won — we no longer need the default-audience prefetch. defaultPaywallTask.cancel() return result } catch is TimedOut { // Attribution didn't apply in time — return the prefetched default // (instant if already done, otherwise we await the in-flight request). return try await defaultPaywallTask.value } } /// Suspends until a profile with the desired attribution source is observed. /// `@Published.values` emits the current profile immediately on subscription, /// so this returns on the first iteration if attribution is already applied. @MainActor private static func waitForAttribution() async { for await profile in ProfileObserver.shared.$profile.values { if profile?.appliedAttributionSources.contains(.appleAds) == true { return } } } } @MainActor final class ProfileObserver: AdaptyDelegate { static let shared = ProfileObserver() @Published private(set) var profile: AdaptyProfile? nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { Task { @MainActor [weak self] in self?.profile = profile } } } ``` Reliez `ProfileObserver` à `AdaptyDelegate` une seule fois, après la complétion de `Adapty.activate()` : ```swift Adapty.delegate = ProfileObserver.shared ``` Appelez depuis l'écran de démarrage : ```swift do { let paywall = try await PaywallLoader.getPaywallOrDefault( placementId: "YOUR_PLACEMENT_ID", timeout: 5 ) // present the paywall } catch { // handle the error or show a fallback paywall } ``` Si votre app utilise déjà un `AdaptyDelegate` à d'autres fins (par exemple, [écouter les mises à jour d'abonnement](ios-check-subscription-status#listen-to-subscription-updates)), transmettez `didLoadLatestProfile` à `ProfileObserver.shared` depuis votre délégué existant plutôt que de définir `Adapty.delegate = ProfileObserver.shared`. --- # File: ios-test --- --- title: "Test & release in iOS SDK" description: "Découvrez comment vérifier le statut d'abonnement dans votre application iOS avec Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application iOS, vous souhaitez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu. Cela implique de tester à la fois l'intégration du SDK et les achats réels. ## Tester votre application \{#test-your-app\} Pour des tests complets de vos achats intégrés, notamment les tests en sandbox et la validation via TestFlight, consultez notre [guide de test](test-purchases-in-sandbox). ## Préparer la mise en production \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [checklist de mise en production](release-checklist) pour confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats sont effectués et signalés à Adapty - L'accès est déverrouillé et restauré correctement - Les exigences en matière de confidentialité et de révision sont respectées --- # File: ios-reference --- --- title: "Référence pour le SDK iOS" description: "Documentation de référence pour le SDK iOS Adapty." --- Cette page contient la documentation de référence pour le SDK iOS Adapty. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://swift.adapty.io/)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](ios-sdk-error-handling)** - Gestion des erreurs et résolution des problèmes --- # File: ios-sdk-error-handling --- --- title: "Gérer les erreurs dans le SDK iOS" description: "Gérez efficacement les erreurs du SDK iOS avec le guide de dépannage d'Adapty." --- Le SDK Adapty dispose de son propre wrapper pour tout type d'erreur, appelé `AdaptyError`. En pratique, chaque erreur renvoyée par le SDK est un `AdaptyError`. Il possède deux propriétés utiles : `originalError` et `adaptyErrorCode`, décrites ci-dessous. **originalError** contient l'erreur d'origine si vous en avez besoin. Il peut s'agir d'une [SKError](https://developer.apple.com/documentation/storekit/skerror), d'une [NSError](https://developer.apple.com/documentation/foundation/nserror) ou d'une [Error](https://developer.apple.com/documentation/swift/error) Swift générique. Cette propriété est optionnelle, car certaines erreurs peuvent être générées directement par le SDK — par exemple, des données incohérentes ou manquantes — et ne disposent pas d'erreur d'origine autour de laquelle le wrapper a été initialement construit. **adaptyErrorCode** peut être utilisé pour gérer les problèmes courants, comme : - des identifiants invalides - des erreurs réseau - des paiements annulés - des problèmes de facturation - un reçu invalide - et bien plus encore Il est très simple de vérifier le code d'erreur et d'y réagir en conséquence. ```swift showLineNumbers title="Swift" do { let info = try await Adapty.makePurchase(product: product) } catch { if error.adaptyErrorCode == .paymentCancelled { // purchase was cancelled // you can offer discount to your user or remind them later } } ``` :::tip **Activez les logs détaillés avant de déboguer.** La plupart des `AdaptyError` encapsulent une erreur StoreKit, réseau ou backend sous-jacente. Avec les logs détaillés activés (`Adapty.logLevel = .verbose` — voir [Logging](sdk-installation-ios#logging)), cette erreur encapsulée est affichée dans la console, ce qui révèle généralement la cause réelle. La propriété `originalError` est renseignée quel que soit le niveau de log — les logs détaillés permettent simplement de la faire apparaître dans la console. ::: :::important Si ces solutions ne résolvent pas votre problème, consultez la section [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support, afin de nous aider à vous assister plus efficacement. ::: ## Erreurs StoreKit \{#storekit-errors\} | Erreur | Code | Solution | |--------------------------------------------------------------------------------------------------------------------------------------------|------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [unknown](https://developer.apple.com/documentation/storekit/skerror/code/unknown) | 0 | Code d'erreur indiquant qu'une erreur inconnue ou inattendue s'est produite. <br/> Réessayez ou consultez la section [Autres problèmes](#other-issues). | | [clientInvalid](https://developer.apple.com/documentation/storekit/skerror/code/clientinvalid) | 1 | Ce code d'erreur indique que le client n'est pas autorisé à effectuer l'action tentée. | | [paymentCancelled](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 2 | <p>Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.</p><p>Aucune action n'est requise, mais d'un point de vue métier, vous pouvez proposer une réduction à votre utilisateur ou lui rappeler plus tard.</p> | | [paymentInvalid](https://developer.apple.com/documentation/storekit/skerror/code/paymentinvalid) | 3 | Cette erreur indique qu'un des paramètres de paiement n'a pas été reconnu par l'App Store. | | [paymentNotAllowed](https://developer.apple.com/documentation/storekit/skerror/code/paymentnotallowed) | 4 | Ce code d'erreur indique que l'utilisateur n'est pas autorisé à valider des paiements. | | [storeProductNotAvailable](https://developer.apple.com/documentation/storekit/skerror/code/storeproductnotavailable) | 5 | Ce code d'erreur indique que le produit demandé n'est pas disponible dans le store. <br/> Essayez de réinstaller l'application. | | [cloudServicePermissionDenied](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicepermissiondenied) | 6 | Ce code d'erreur indique que l'utilisateur n'a pas autorisé l'accès aux informations du service Cloud. | | [cloudServiceNetworkConnectionFailed](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicenetworkconnectionfailed) | 7 | Ce code d'erreur indique que l'appareil n'a pas pu se connecter au réseau. | | [cloudServiceRevoked](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicerevoked/) | 8 | Ce code d'erreur indique que l'utilisateur a révoqué l'autorisation d'utiliser ce service Cloud. | | [privacyAcknowledgementRequired](https://developer.apple.com/documentation/storekit/skerror/code/privacyacknowledgementrequired) | 9 | Ce code d'erreur indique que l'utilisateur n'a pas encore accepté la politique de confidentialité d'Apple. | | [unauthorizedRequestData](https://developer.apple.com/documentation/storekit/skerror/code/unauthorizedrequestdata) | 10 | Ce code d'erreur indique que l'application tente d'utiliser une propriété pour laquelle elle ne dispose pas des droits requis. | | [invalidOfferIdentifier](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferidentifier) | 11 | <p>L'[`identifiant`](https://developer.apple.com/documentation/storekit/skpaymentdiscount/identifier) de l'offre n'est pas valide. Par exemple, vous n'avez pas configuré d'offre avec cet identifiant dans l'App Store, ou vous avez révoqué l'offre.</p><p>Assurez-vous de configurer les offres souhaitées dans App Store Connect et de transmettre un identifiant d'offre valide.</p> | | [invalidSignature](https://developer.apple.com/documentation/storekit/skerror/code/invalidsignature) | 12 | Ce code d'erreur indique que la signature dans une remise de paiement n'est pas valide. | | [missingOfferParams](https://developer.apple.com/documentation/storekit/skerror/code/missingofferparams) | 13 | Ce code d'erreur indique que des paramètres sont manquants dans une remise de paiement. | | [invalidOfferPrice](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferprice/) | 14 | Ce code d'erreur indique que le prix que vous avez spécifié dans App Store Connect n'est plus valide. Les offres doivent toujours correspondre à un prix réduit. | | noProductIDsFound | 1000 | <p>Cette erreur indique qu'aucun des produits que vous avez demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le.</p><p>Si vous rencontrez cette erreur, suivez les étapes de la section [Correction de l'erreur Code-1000 `noProductIDsFound`](InvalidProductIdentifiers).</p> | | productRequestFailed | 1002 | Impossible de récupérer les produits disponibles pour le moment. | | cantMakePayments | 1003 | Les achats intégrés ne sont pas autorisés sur cet appareil. Consultez le [guide](cantMakePayments) de dépannage. | | [cantReadReceipt](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 1005 | <p>Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.</p><p>En sandbox, vous n'aurez pas de fichier de reçu valide tant que vous n'aurez pas effectué un achat, assurez-vous donc d'en faire un avant d'y accéder. Lors des tests en sandbox, vérifiez également que vous êtes connecté sur l'appareil avec un compte sandbox Apple valide.</p> | | productPurchaseFailed | 1006 | L'achat du produit a échoué. Cette erreur encapsule une erreur StoreKit sous-jacente — lisez `originalError` (ou activez les logs détaillés pour la voir dans la console) pour connaître la raison réelle. L'erreur encapsulée correspond généralement à l'un des codes StoreKit 0–14 du tableau ci-dessus — le plus souvent `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` ou `invalidOfferPrice`. Si vous ne pouvez pas identifier une raison précise, essayez un nouveau [profil sandbox](test-purchases-in-sandbox) ; si le problème persiste, contactez le support Apple. | | refreshReceiptFailed | 1010 | L'opération de rafraîchissement du reçu a échoué. | | fetchSubscriptionStatusFailed | 1020 | Impossible de récupérer le statut de l'abonnement depuis l'App Store. | | unknownTransactionId | 1030 | L'identifiant de transaction est inconnu. | | paymentPendingError | 1050 | Le paiement est actuellement en attente. | ## Erreurs réseau \{#network-errors\} | Erreur | Code | Solution | | :------------- | :--- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | notActivated | 2002 | Le SDK Adapty n'est pas activé. <br/> Cela se produit généralement lorsqu'un écran de démarrage ou un hook d'interface utilisateur précoce appelle des méthodes Adapty avant que `Adapty.activate` ne retourne. Le symptôme est intermittent et peut ne pas se reproduire sur simulateur, car le timing est différent sur un vrai appareil. Attendez le handler de complétion ou le résultat async d'`activate` avant de planifier tout autre appel SDK. Voir [Ordre des appels dans le SDK iOS](ios-sdk-call-order) pour la séquence complète. | | badRequest | 2003 | Requête incorrecte. <br/> Vérifiez que vous avez bien effectué toutes les étapes nécessaires à l'[intégration avec l'App Store](app-store-connection-configuration). | | serverError | 2004 | Erreur serveur. <br/> Réessayez après un moment. Si le problème persiste, contactez l'équipe support Adapty. | | networkFailed | 2005 | Cette erreur indique des problèmes de connexion réseau sur l'appareil de l'utilisateur. <br/> Essayez de désactiver le VPN ou de basculer entre le Wi-Fi et le réseau cellulaire. | | decodingFailed | 2006 | Cette erreur indique que le décodage de la réponse a échoué. <br/> Vérifiez votre code et assurez-vous que les paramètres que vous envoyez sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. | | encodingFailed | 2009 | Cette erreur indique que l'encodage de la requête a échoué. | ## Erreurs générales \{#general-errors\} | Erreur | Code | Solution | | :------------------- | :--- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | analyticsDisabled | 3000 | Impossible de traiter les événements analytics, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). | | wrongParam | 3001 | Cette erreur indique que certains de vos paramètres sont incorrects. <br/> Si vous utilisez le Paywall Builder d'Adapty et ne pouvez pas afficher un paywall à cause de cette erreur, activez l'option **Show on device** dans le Paywall Builder.<br/> Une autre cause possible est que la version du fichier [fallback](fallback-paywalls) local ne correspond pas à la version du SDK. Téléchargez un nouveau fichier depuis le tableau de bord. | | activateOnceError | 3005 | Il n'est pas possible d'appeler la méthode `.activate` plus d'une fois. | | profileWasChanged | 3006 | Le profil utilisateur a été modifié pendant l'opération. <br/> Cela se produit lorsqu'une méthode est appelée alors qu'`Adapty.identify` est encore en cours d'exécution — l'appel en vol atterrit sur un profil sur le point d'être remplacé, et le SDK le rejette. Utilisez toujours `await` sur `identify` (ou son handler de complétion) avant tout appel déclenché par une action utilisateur. Voir [Ordre des appels dans le SDK iOS](ios-sdk-call-order). | | unsupportedData | 3007 | Cette erreur indique que le format de données n'est pas pris en charge par le SDK. | | unidentifiedUserLogout | 3020 | Il n'est pas possible d'appeler la méthode `logout` pour un utilisateur non identifié. | | fetchTimeoutError | 3101 | Cette erreur indique que l'opération de récupération a expiré. | | operationInterrupted | 9000 | Cette opération a été interrompue par le système. | ## Autres problèmes \{#other-issues\} Si vous n'avez pas encore trouvé de solution, voici les prochaines étapes possibles : - **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de passer à la dernière version du SDK, car elles sont plus stables et incluent des correctifs pour les problèmes connus. - **Contacter l'équipe support ou obtenir de l'aide auprès d'autres développeurs** sur le [forum de support](https://adapty.featurebase.app/). - **Contacter l'équipe support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou si cela n'a pas résolu le problème, contactez notre équipe support. Notez que votre problème sera résolu plus rapidement si vous [activez les logs détaillés](sdk-installation-ios#logging) et les partagez avec l'équipe. Vous pouvez également joindre des extraits de code pertinents. --- # File: InvalidProductIdentifiers --- --- title: "Correction de l'erreur Code-1000 noProductIDsFound" description: "Résolvez les erreurs d'identifiants de produits invalides lors de la gestion des abonnements dans Adapty." --- L'erreur code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont bien référencés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le sans crainte. Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre : ## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\} 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Vérifier les produits 1. Rendez-vous dans **App Store Connect** et accédez à [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. Vos produits s'affichent dans la section **Subscriptions**. 3. Assurez-vous que le produit testé est bien marqué **Ready to Submit**. Si ce n'est pas le cas, suivez les instructions sur la page [Produit dans l'App Store](app-store-products). <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Comparez l'identifiant du produit dans le tableau avec celui de l'onglet [**Products**](https://app.adapty.io/products) dans l'Adapty Dashboard. Si les identifiants ne correspondent pas, copiez l'identifiant depuis le tableau et [créez un produit](create-product) avec cet identifiant dans l'Adapty Dashboard. <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3. Vérifier la disponibilité du produit \{#step-4-check-product-availability\} 1. Retournez dans **App Store Connect** et ouvrez la même section **Subscriptions**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis y figurent. <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. Retournez dans la section **Monetization** → **Subscriptions** dans **App Store Connect**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à **Subscription Pricing** et développez la section **Current Pricing for New Subscribers**. <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Vérifiez que tous les prix requis sont bien listés. <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Vérifier le statut des applications payantes, le compte bancaire et les formulaires fiscaux 1. Sur la page d'accueil d'**[App Store Connect](https://appstoreconnect.apple.com/)**, cliquez sur **Business**. <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez le nom de votre entreprise. <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Faites défiler vers le bas et vérifiez que votre **Paid Apps Agreement**, votre **Bank Account** et vos **Tax forms** affichent tous le statut **Active**. <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En suivant ces étapes, vous devriez pouvoir résoudre l'avertissement `InvalidProductIdentifiers` et rendre vos produits disponibles dans le store. ## Étape 6. Recréer le produit s'il est bloqué Les étapes 1 à 5 peuvent toutes être validées — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK renvoie toujours `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre des produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit. Supprimez le produit dans App Store Connect et recréez-le avec le même identifiant de produit. Comptez jusqu'à 24 heures après la recréation pour la propagation. --- # File: cantMakePayments --- --- title: "Correction de l'erreur Code-1003 cantMakePayment" description: "Résolvez l'erreur de paiement lors de la gestion des abonnements dans Adapty." --- L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil. Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes : - Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous. - Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous. ## Problème : Restrictions de l'appareil \{#issue-device-restrictions\} | Problème | Solution | |--------------------------------|-------------------------------------------------------------------------------------------------------------| | Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) | | Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte | | Restrictions régionales | Utilisez un compte App Store d'une région prise en charge | ## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\} Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat. Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK. --- # File: ios-sdk-migration-guides --- --- title: "Guides de migration iOS SDK" description: "Guides de migration pour les versions du SDK Adapty iOS." --- Cette page regroupe tous les guides de migration pour le SDK Adapty iOS. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées : - [**Migrer vers v4.0**](migration-to-ios-sdk-v4) - [**Migrer vers v3.15**](migration-to-ios-315) - **[Migrer vers v3.4](migration-to-ios-sdk-34)** - **[Migrer vers v3.3](migration-to-ios330)** - **[Migrer vers v3.0](migration-to-ios-sdk-v3)** --- # File: migration-to-ios-sdk-v4 --- --- title: "Migrer le SDK iOS Adapty vers la v4.0" description: "Migrez vers le SDK iOS Adapty v4.0 en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK iOS Adapty 4.0 introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId:locale:)` | `Adapty.getFlow(placementId:)` | | `AdaptyUI.getPaywallConfiguration(forPaywall:)` | `AdaptyUI.getFlowConfiguration(forFlow:locale:)` | | `Adapty.getPaywallProducts(paywall:)` | `Adapty.getPaywallProducts(flow:)` | | `Adapty.logShowPaywall(_:)` | `Adapty.logShowFlow(_:)` | | `AdaptyPaywallController` | `AdaptyFlowController` | | `AdaptyPaywallControllerDelegate` | `AdaptyFlowControllerDelegate` | | `AdaptyUI.paywallController(with:delegate:)` | `AdaptyUI.flowController(with:delegate:)` | | `.paywall()` (modificateur SwiftUI) | `.flow()` | | `AdaptyPaywallView` | `AdaptyFlowView` | | `didFailRenderingWith:` / `didFailRendering:` | `didReceiveError:` | | `didFinishPurchase` (optionnel, fermeture automatique en cas de succès) | `didFinishPurchase` (requis, pas de fermeture automatique) | | Produits de package `Adapty_KidsMode` / `AdaptyUI_KidsMode` | Trait de package `KidsMode` | | `Adapty.updateAttribution(_:source:)` (`source: String`) | `Adapty.updateAttribution(_:source:)` (`source: AdaptyAttributionSource`) | | `Adapty.setIntegrationIdentifier(key:value:)` | `Adapty.setIntegrationIdentifier(_:)` (`AdaptyIntegrationIdentifier`) | ## Version iOS minimale \{#minimum-ios-version\} Adapty iOS SDK 4.0 fait passer la cible de déploiement minimale d'iOS 13.0 à **iOS 15.0**. Définissez la cible de déploiement iOS de votre projet à 15.0 ou une version ultérieure avant de procéder à la mise à niveau. ## Installation : CocoaPods n'est plus pris en charge \{#installation-cocoapods-no-longer-supported\} Adapty iOS SDK 4.0 abandonne le support de CocoaPods. Installez le SDK avec [Swift Package Manager](sdk-installation-ios#install-adapty-sdk). Si votre projet utilise encore CocoaPods, supprimez les pods `Adapty` et `AdaptyUI` de votre `Podfile`, exécutez `pod install` pour les supprimer, puis ajoutez le package dans Xcode via **File → Add Package Dependency** en utilisant `https://github.com/adaptyteam/AdaptySDK-iOS.git`. ## Mode Enfants : produits séparés remplacés par un trait de package \{#kids-mode-separate-products-replaced-by-a-package-trait\} Dans la v3, vous activiez le [Mode Enfants](kids-mode) en sélectionnant les produits de package distincts **Adapty_KidsMode** et **AdaptyUI_KidsMode** et en renommant vos imports. Dans la v4.0, ces produits ont été supprimés. Le Mode Enfants est désormais un trait de package Swift nommé `KidsMode` sur le package Adapty standard — son activation exclut IDFA et AdSupport de l'ensemble du SDK à la compilation. Pour migrer : 1. Dans la fenêtre **Choose Package Products**, sélectionnez les produits standard **Adapty** et **AdaptyUI** au lieu de **Adapty_KidsMode** et **AdaptyUI_KidsMode**. 2. Activez le trait `KidsMode`. Dans Xcode 26.4 ou version ultérieure, activez-le pour la dépendance AdaptySDK-iOS dans la vue **Package Dependencies** de votre projet. Si vous ajoutez Adapty en tant que dépendance dans `Package.swift` (nécessite `swift-tools-version` 6.1 ou version ultérieure), activez-le à cet endroit : ```swift showLineNumbers title="Package.swift" .package( url: "https://github.com/adaptyteam/AdaptySDK-iOS.git", from: "4.0.0", traits: ["KidsMode"] ) ``` 3. Remettez vos imports sur les modules standard : ```diff showLineNumbers - import Adapty_KidsMode - import AdaptyUI_KidsMode + import Adapty + import AdaptyUI ``` :::note Les versions de Xcode antérieures à 26.4 ne permettent pas d'activer les traits pour un projet Xcode depuis l'interface. Dans ce cas, ajoutez un petit package Swift local qui dépend d'Adapty avec le trait `KidsMode` activé, et faites dépendre votre cible d'application de ce package. ::: ## APIs supprimées \{#removed-apis\} - **`Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)`** — supprimée. Tous les produits incluent désormais les informations sur les offres, ce qui rend la vérification séparée d'éligibilité inutile. - **`AdaptyPaywallProductWithoutDeterminingOffer`** — supprimée. Les callbacks qui utilisaient auparavant ce type (comme `didSelectProduct`) transmettent maintenant `AdaptyPaywallProduct`. ## Les achats intégrés promus sur l'App Store temporairement supprimés \{#app-store-promoted-in-app-purchases-temporarily-removed\} Dans le cadre de la migration vers StoreKit 2, le SDK iOS Adapty 4.0 supprime la prise en charge des achats intégrés promus sur l'App Store. La méthode delegate `shouldAddStorePayment(for:)` et le type `AdaptyDeferredProduct` qu'elle reçoit ne sont pas disponibles dans la version 4.0. :::warning Cette suppression est temporaire — la prise en charge des achats intégrés promus sera de retour dans une version ultérieure 4.x. Si votre application repose sur des achats intégrés promus, restez sur le SDK iOS 3.x jusqu'au retour de cette fonctionnalité. ::: ## Récupération des paywalls \{#fetching-paywalls\} ### getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration Les types retournés passent de `AdaptyPaywall` / `AdaptyUI.PaywallConfiguration` à `AdaptyFlow` / `AdaptyUI.FlowConfiguration`. Le paramètre `locale` quitte l'appel de récupération et se déplace vers `getFlowConfiguration` : ```diff showLineNumbers - let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") - let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall) + let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") + let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en") ``` ### getPaywallProducts(paywall:) → getPaywallProducts(flow:) `getPaywallProducts` prend désormais un `AdaptyFlow` retourné par `Adapty.getFlow` : ```diff showLineNumbers - let products = try await Adapty.getPaywallProducts(paywall: paywall) + let products = try await Adapty.getPaywallProducts(flow: flow) ``` ### Fichiers de secours \{#fallback-files\} Le format du fichier de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le à votre application. ## Suivi des vues de paywall \{#tracking-paywall-views\} ### logShowPaywall(_:) → logShowFlow(_:) `logShowPaywall` est renommé en `logShowFlow` et prend désormais un `AdaptyFlow` à la place d'un `AdaptyPaywall`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord. ```diff showLineNumbers - try await Adapty.logShowPaywall(paywall) + try await Adapty.logShowFlow(flow) ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage des flows ou des paywalls générés par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement. ## didFinishPurchase est maintenant obligatoire \{#didfinishpurchase-is-now-required\} Dans la v3, `didFinishPurchase` était facultatif : si vous ne l'implémentiez pas, le paywall se fermait automatiquement après un achat réussi. Dans la v4.0, ce comportement de fermeture automatique par défaut a été supprimé afin qu'un flow puisse continuer après un achat réussi — par exemple, pour afficher les écrans restants de votre flow. Vous décidez désormais ce qui se passe après un achat : fermer l'écran, ou ne rien faire pour laisser le flow continuer. - **UIKit** : les conformeurs à `AdaptyFlowControllerDelegate` doivent implémenter `didFinishPurchase` — cette méthode n'a plus d'implémentation par défaut. - **SwiftUI** : la closure `didFinishPurchase` de `.flow(...)` et `AdaptyFlowView(...)` est désormais non-optionnelle, au même titre que `didFailPurchase` et `didFinishRestore`. Pour conserver le comportement de la v3, fermez l'écran vous-même : ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) } } ``` ## UIKit \{#uikit\} ### AdaptyPaywallController → AdaptyFlowController Renommez le type de contrôleur et la méthode factory : ```diff showLineNumbers - let controller = try AdaptyUI.paywallController( - with: paywallConfiguration, - delegate: self - ) + let controller = try AdaptyUI.flowController( + with: flowConfiguration, + delegate: self + ) ``` ### AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate Renommez le protocole et mettez à jour chaque signature de méthode. Notez que `didSelectProduct` reçoit désormais `AdaptyPaywallProduct` au lieu de l'`AdaptyPaywallProductWithoutDeterminingOffer` supprimé, et `didFinishPurchase` [doit maintenant être implémenté](#didfinishpurchase-is-now-required) — il n'a plus d'implémentation par défaut. ```diff showLineNumbers - class YourClass: AdaptyPaywallControllerDelegate { + class YourClass: AdaptyFlowControllerDelegate { - func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { } + func flowControllerDidAppear(_ controller: AdaptyFlowController) { } - func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { } + func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didPerform action: AdaptyUI.Action) { } + func flowController(_ controller: AdaptyFlowController, + didPerform action: AdaptyUI.Action) { } - func paywallController(_ controller: AdaptyPaywallController, - didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { } + func flowController(_ controller: AdaptyFlowController, + didSelectProduct product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didStartPurchase product: AdaptyPaywallProduct) { } + func flowController(_ controller: AdaptyFlowController, + didStartPurchase product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishPurchase product: AdaptyPaywallProduct, - purchaseResult: AdaptyPurchaseResult) { } + func flowController(_ controller: AdaptyFlowController, + didFinishPurchase product: AdaptyPaywallProduct, + purchaseResult: AdaptyPurchaseResult) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailPurchase product: AdaptyPaywallProduct, - error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailPurchase product: AdaptyPaywallProduct, + error: AdaptyError) { } - func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { } + func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishRestoreWith profile: AdaptyProfile) { } + func flowController(_ controller: AdaptyFlowController, + didFinishRestoreWith profile: AdaptyProfile) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRestoreWith error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailRestoreWith error: AdaptyError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRenderingWith error: AdaptyUIError) { } + func flowController(_ controller: AdaptyFlowController, + didReceiveError error: AdaptyUIError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailLoadingProductsWith error: AdaptyError) -> Bool { } + func flowController(_ controller: AdaptyFlowController, + didFailLoadingProductsWith error: AdaptyError) -> Bool { } - func paywallController(_ controller: AdaptyPaywallController, - didPartiallyLoadProducts failedIds: [String]) { } + func flowController(_ controller: AdaptyFlowController, + didPartiallyLoadProducts failedIds: [String]) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, - error: AdaptyError?) { } + func flowController(_ controller: AdaptyFlowController, + didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, + error: AdaptyError?) { } } ``` ## SwiftUI \{#swiftui\} ### Modificateur `.paywall()` → `.flow()` \{#paywall-modifier--flow\} Renommez le modificateur, mettez à jour le nom du paramètre de configuration, et ajoutez la closure [`didFinishPurchase`](#didfinishpurchase-is-now-required) (désormais obligatoire) : ```diff showLineNumbers @State var flowPresented = false // rename freely — the variable name is your choice var body: some View { Text("Hello, AdaptyUI!") - .paywall( + .flow( isPresented: $flowPresented, - paywallConfiguration: paywallConfiguration, + flowConfiguration: flowConfiguration, + didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in flowPresented = false } + didReceiveError: { error in flowPresented = false } ) } ``` Le callback renommé se déclenche pour les mêmes erreurs de rendu que `didFailRendering`, plus les nouvelles erreurs d'exécution provenant du script de flow (exceptions JavaScript avec le code `AdaptyUIError` `4105` — `.jsException`). Les corps de handler existants ne nécessitent aucune modification — il suffit de renommer le paramètre. ### AdaptyPaywallView → AdaptyFlowView Renommez la vue, mettez à jour le paramètre de configuration, ajoutez la closure [`didFinishPurchase`](#didfinishpurchase-is-now-required) (désormais obligatoire), et mettez à jour toute closure `didSelectProduct` — elle reçoit maintenant `AdaptyPaywallProduct` à la place du type supprimé `AdaptyPaywallProductWithoutDeterminingOffer` : ```diff showLineNumbers - AdaptyPaywallView( - paywallConfiguration: paywallConfiguration, - didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ }, + AdaptyFlowView( + flowConfiguration: flowConfiguration, + didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ }, + didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in /* handle the error */ } + didReceiveError: { error in /* handle the error */ } ) ``` ## Ressources personnalisées AdaptyUI \{#adaptyui-custom-assets\} ### AdaptyUICustomVideoAsset Deux changements affectent tous les appels existants : - `.player` accepte désormais `AVPlayer` au lieu de `AVQueuePlayer`. - Chaque cas a reçu un paramètre supplémentaire `resolution: CGSize?` en fin de signature. Passez `nil` pour conserver le comportement actuel, ou indiquez la taille réelle en pixels afin que le lecteur puisse réserver l'espace de mise en page (ratio = `width / height`) avant le chargement de la vidéo. ```diff showLineNumbers - case file(url: URL, preview: AdaptyUICustomImageAsset?) - case remote(url: URL, preview: AdaptyUICustomImageAsset?) - case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?) + case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) ``` ## Identifiants d'attribution et d'intégration \{#attribution-and-integration-identifiers\} ### updateAttribution(_:source:) Le paramètre `source` passe du type `String` au nouveau type `AdaptyAttributionSource`, et l'ancien `AdaptyProfile.AttributionSource` imbriqué est renommé en `AdaptyAttributionSource` au niveau supérieur. Utilisez l'une des sources prédéfinies, ou passez un littéral de chaîne pour toute autre source — `AdaptyAttributionSource` est conforme à `ExpressibleByStringLiteral`, donc les appels existants avec des littéraux de chaîne continuent de compiler. ```diff showLineNumbers - try await Adapty.updateAttribution(attribution, source: "adjust") + try await Adapty.updateAttribution(attribution, source: .adjust) ``` Sources prédéfinies : `.appleAds`, `.adjust`, `.appsflyer`, `.branch`, `.tenjin`. Si vous conservez la source dans une variable `String`, encapsulez-la : `AdaptyAttributionSource(rawValue: yourSource)`. ### setIntegrationIdentifier(_:) `setIntegrationIdentifier(key:value:)` est remplacé par une méthode variadique qui accepte une ou plusieurs valeurs `AdaptyIntegrationIdentifier`. Utilisez les méthodes factory prédéfinies plutôt que des clés de type chaîne brute : ```diff showLineNumbers - try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + try await Adapty.setIntegrationIdentifier(.appsflyerId(uid)) ``` Vous pouvez définir plusieurs identifiants en un seul appel : ```swift showLineNumbers try await Adapty.setIntegrationIdentifier( .appsflyerId(uid), .adjustDeviceId(adid) ) ``` Remplacez chaque ancienne chaîne de clé par sa méthode factory correspondante : | v3 key | v4 factory | |---|---| | `"adjust_device_id"` | `.adjustDeviceId(_:)` | | `"airbridge_device_id"` | `.airbridgeDeviceId(_:)` | | `"amplitude_user_id"` | `.amplitudeUserId(_:)` | | `"amplitude_device_id"` | `.amplitudeDeviceId(_:)` | | `"appmetrica_device_id"` | `.appmetricaDeviceId(_:)` | | `"appmetrica_profile_id"` | `.appmetricaProfileId(_:)` | | `"appsflyer_id"` | `.appsflyerId(_:)` | | `"branch_id"` | `.branchId(_:)` | | `"facebook_anonymous_id"` | `.facebookAnonymousId(_:)` | | `"firebase_app_instance_id"` | `.firebaseAppInstanceId(_:)` | | `"mixpanel_user_id"` | `.mixpanelUserId(_:)` | | `"one_signal_subscription_id"` | `.oneSignalSubscriptionId(_:)` | | `"one_signal_player_id"` | `.oneSignalPlayerId(_:)` | | `"posthog_distinct_user_id"` | `.posthogDistinctUserId(_:)` | | `"pushwoosh_hwid"` | `.pushwooshHWID(_:)` | | `"tenjin_analytics_installation_id"` | `.tenjinAnalyticsInstallationId(_:)` | --- # File: migration-to-ios-315 --- --- title: "Migrer le SDK iOS Adapty vers la v3.15" description: "Migrez vers le SDK iOS Adapty v3.15 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Si vous utilisez le [Paywall Builder](adapty-paywall-builder) en [mode Observer](observer-vs-full-mode), à partir du SDK iOS 3.15, vous devez implémenter une nouvelle méthode `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)`. Cette méthode offre un meilleur contrôle sur la logique de restauration, vous permettant de gérer les restaurations d'achats dans votre flow personnalisé. Pour tous les détails d'implémentation, consultez [Afficher les paywalls du Paywall Builder en mode Observer](ios-present-paywall-builder-paywalls-in-observer-mode). ```diff showLineNumbers func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } + func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, + onFinishRestore: @escaping () -> Void) { + // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore + } ``` --- # File: migration-to-ios-sdk-34 --- --- title: "Migrer vers le SDK Adapty iOS v3.4" description: "Migrez vers le SDK Adapty iOS v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté. ## Mettre à jour l'activation du SDK Adapty \{#update-adapty-sdk-activation\} <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") - Adapty.activate(with: configurationBuilder) { error in + Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` **Mettre à jour les fichiers de paywall de secours** Mettez à jour vos fichiers de paywall de secours pour garantir la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](ios-use-fallback-paywalls) par les nouveaux fichiers. </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```diff showLineNumbers @main struct SampleApp: App { init() { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") Task { - try await Adapty.activate(with: configurationBuilder) + try await Adapty.activate(with: configurationBuilder.build()) } } var body: some Scene { WindowGroup { ContentView() } } } ``` **Mettre à jour les fichiers de paywall de secours** Mettez à jour vos fichiers de paywall de secours pour garantir la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](ios-use-fallback-paywalls) par les nouveaux fichiers. </TabItem> </Tabs> --- # File: migration-to-ios330 --- --- title: "Migrer le SDK iOS Adapty vers v3.3" description: "Migrez vers le SDK iOS Adapty v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.3.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part. 1. Renommer `Adapty.Configuration` en `AdaptyConfiguration`. 2. Renommer la méthode `getViewConfiguration` en `getPaywallConfiguration`. 3. Supprimer les paramètres `didCancelPurchase` et `paywall` de SwiftUI, et renommer le paramètre `viewConfiguration` en `paywallConfiguration`. 4. Mettre à jour la gestion des achats intégrés promotionnels depuis l'App Store en supprimant le paramètre `defermentCompletion` de la méthode `AdaptyDelegate`. 5. Supprimer la méthode `getProductsIntroductoryOfferEligibility`. 6. Mettre à jour les configurations d'intégration pour Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase et Google Analytics, Mixpanel, OneSignal, Pushwoosh. 7. Mettre à jour l'implémentation du mode Observer. <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/9Xs8d0lt_RY?si=xvWhUO2tlG1tKP5f" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen> </iframe> </div> ## Renommer Adapty.Configuration en AdaptyConfiguration \{#rename-adaptyconfiguration-to-adaptyconfiguration\} Mettez à jour le code d'activation du SDK iOS Adapty de la façon suivante : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } ``` </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```diff showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Task { try await Adapty.activate(with: configurationBuilder) } } var body: some Scene { WindowGroup { ContentView() } } } ``` </TabItem> </Tabs> ## Renommer la méthode getViewConfiguration en getPaywallConfiguration \{#rename-getviewconfiguration-method-to-getpaywallconfiguration\} Mettez à jour le nom de la méthode pour récupérer la `viewConfiguration` du paywall : ```diff showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { - let paywallConfiguration = try await AdaptyUI.getViewConfiguration( + let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall ) // use loaded configuration } catch { // handle the error } ``` Pour plus de détails sur la méthode, consultez [Récupérer la configuration de vue d'un paywall conçu avec le Paywall Builder](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). ## Modifier les paramètres dans SwiftUI \{#change-parameters-in-swiftui\} Les mises à jour suivantes ont été apportées à SwiftUI : 1. Le paramètre `didCancelPurchase` a été supprimé. Utilisez `didFinishPurchase` à la place. 2. La méthode `.paywall()` n'accepte plus d'objet paywall. 3. Le paramètre `paywallConfiguration` remplace le paramètre `viewConfiguration`. Mettez à jour votre code comme ceci : ```diff showLineNumbers @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, - paywall: <paywall object>, - viewConfiguration: <LocalizedViewConfiguration>, + paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, - didFinishPurchase: { product, profile in paywallPresented = false }, + didFinishPurchase: { product, purchaseResult in /* handle the result*/ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } - didCancelPurchase: { product in /* handle the result*/} ) } ``` ## Mettre à jour la gestion des achats intégrés promotionnels depuis l'App Store \{#update-handling-of-promotional-in-app-purchases-from-app-store\} Mettez à jour la façon dont vous gérez les achats intégrés promotionnels depuis l'App Store en supprimant le paramètre `defermentCompletion` de la méthode `AdaptyDelegate`, comme indiqué dans l'exemple ci-dessous : ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from the 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## Supprimer la méthode getProductsIntroductoryOfferEligibility \{#remove-getproductsintroductoryoffereligibility-method\} Avant le SDK iOS Adapty 3.3.0, l'objet produit incluait toujours les offres, peu importe si l'utilisateur y était éligible. Vous deviez vérifier manuellement l'éligibilité avant d'utiliser l'offre. Désormais, l'objet produit n'inclut une offre que si l'utilisateur est éligible. Cela signifie que vous n'avez plus besoin de vérifier l'éligibilité — si une offre est présente, l'utilisateur y est éligible. Si vous souhaitez tout de même consulter les offres pour les utilisateurs non éligibles, référez-vous à `sk1Product` et `sk2Product`. ## Mettre à jour la configuration des SDK d'intégrations tierces \{#update-third-party-integration-sdk-configuration\} À partir du SDK iOS Adapty 3.3.0, nous avons mis à jour l'API publique de la méthode `updateAttribution`. Auparavant, elle acceptait un dictionnaire `[AnyHashable: Any]`, vous permettant de passer directement des objets d'attribution issus de différents services. Désormais, elle requiert un `[String: any Sendable]`, vous devrez donc convertir les objets d'attribution avant de les passer. Pour garantir le bon fonctionnement des intégrations avec le SDK iOS Adapty 3.3.0 et les versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes comme décrit dans les sections ci-dessous. ### Adjust \{#adjust\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust). <Tabs groupId="current-os" queryString> <TabItem value="v5" label="Adjust 5.x+" default> ```diff showLineNumbers class AdjustModuleImplementation { - func updateAdjustAttribution() { - Adjust.attribution { attribution in - guard let attributionDictionary = attribution?.dictionary()?.toSendableDict() else { return } - - Adjust.adid { adid in - guard let adid else { return } - - Adapty.updateAttribution(attributionDictionary, source: .adjust, networkUserId: adid) { error in - // handle the error - } - } - } - } + func updateAdjustAdid() { + Adjust.adid { adid in + guard let adid else { return } + + Adapty.setIntegrationIdentifier(key: "adjust_device_id", value: adid) + } + } + + func updateAdjustAttribution() { + Adjust.attribution { attribution in + guard let attribution = attribution?.dictionary() else { + return + } + + Adapty.updateAttribution(attribution, source: "adjust") + } + } } ``` </TabItem> <TabItem value="v4" label="Adjust 4.x" default> ```diff showLineNumbers class YourAdjustDelegateImplementation { // Find your implementation of AdjustDelegate // and update adjustAttributionChanged method: func adjustAttributionChanged(_ attribution: ADJAttribution?) { - if let attribution = attribution?.dictionary()?.toSendableDict() { - Adapty.updateAttribution(attribution, source: .adjust) + if let attribution = attribution?.dictionary() { + Adapty.updateAttribution(attribution, source: "adjust") } } } ``` </TabItem> </Tabs> ### AirBridge \{#airbridge\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers import AirBridge - let builder = AdaptyProfileParameters.Builder() - .with(airbridgeDeviceId: AirBridge.deviceUUID()) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "airbridge_device_id", + value: AirBridge.deviceUUID() + ) + } catch { + // handle the error + } ``` ### Amplitude \{#amplitude\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers import Amplitude - let builder = AdaptyProfileParameters.Builder() - .with(amplitudeUserId: Amplitude.instance().userId) - .with(amplitudeDeviceId: Amplitude.instance().deviceId) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "amplitude_user_id", + value: Amplitude.instance().userId + ) + try await Adapty.setIntegrationIdentifier( + key: "amplitude_device_id", + value: Amplitude.instance().deviceId + ) + } catch { + // handle the error + } ``` ### AppMetrica \{#appmetrica\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers import AppMetricaCore - if let deviceID = AppMetrica.deviceID { - let builder = AdaptyProfileParameters.Builder() - .with(appmetricaDeviceId: deviceID) - .with(appmetricaProfileId: "YOUR_ADAPTY_CUSTOMER_USER_ID") - - Adapty.updateProfile(params: builder.build()) - } + if let deviceID = AppMetrica.deviceID { + do { + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_device_id", + value: deviceID + ) + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_profile_id", + value: "YOUR_ADAPTY_CUSTOMER_USER_ID" + ) + } catch { + // handle the error + } + } ``` ### AppsFlyer \{#appsflyer\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers class YourAppsFlyerLibDelegateImplementation { // Find your implementation of AppsFlyerLibDelegate // and update onConversionDataSuccess method: func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) { let uid = AppsFlyerLib.shared().getAppsFlyerUID() - Adapty.updateAttribution( - conversionInfo.toSendableDict(), - source: .appsflyer, - networkUserId: uid - ) + Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + Adapty.updateAttribution(conversionInfo, source: "appsflyer") } } ``` ### Branch \{#branch\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers class YourBranchImplementation { func initializeBranch() { // Pass the attribution you receive from the initializing method of Branch iOS SDK to Adapty. Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data = data?.toSendableDict() { - Adapty.updateAttribution(data, source: .branch) - } + if let data { + Adapty.updateAttribution(data, source: "branch") + } } } } ``` ### Facebook Ads \{#facebook-ads\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads). ```diff showLineNumbers import FacebookCore - let builder = AdaptyProfileParameters.Builder() - .with(facebookAnonymousId: AppEvents.shared.anonymousID) - - do { - try Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "facebook_anonymous_id", + value: AppEvents.shared.anonymousID + ) + } catch { + // handle the error + } ``` ### Firebase et Google Analytics \{#firebase-and-google-analytics\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Firebase et Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers import FirebaseCore import FirebaseAnalytics FirebaseApp.configure() - if let appInstanceId = Analytics.appInstanceID() { - let builder = AdaptyProfileParameters.Builder() - .with(firebaseAppInstanceId: appInstanceId) - Adapty.updateProfile(params: builder.build()) { error in - // handle error - } - } + if let appInstanceId = Analytics.appInstanceID() { + do { + try await Adapty.setIntegrationIdentifier( + key: "firebase_app_instance_id", + value: appInstanceId + ) + } catch { + // handle the error + } + } ``` ### Mixpanel \{#mixpanel\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers import Mixpanel - let builder = AdaptyProfileParameters.Builder() - .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) - - do { - try await Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "mixpanel_user_id", + value: Mixpanel.mainInstance().distinctId + ) + } catch { + // handle the error + } ``` ### OneSignal \{#onesignal\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration OneSignal](onesignal#sdk-configuration). ```diff showLineNumbers // PlayerID (pre-v5 OneSignal SDK) // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { - let params = AdaptyProfileParameters.Builder() - .with(oneSignalPlayerId: playerId) - .build() - - Adapty.updateProfile(params:params) { error in - // check error - } + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_player_id", + value: playerId + ) + } } } // SubscriptionID (v5+ OneSignal SDK) OneSignal.Notifications.requestPermission({ accepted in - let id = OneSignal.User.pushSubscription.id - - let builder = AdaptyProfileParameters.Builder() - .with(oneSignalSubscriptionId: id) - - Adapty.updateProfile(params: builder.build()) + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_subscription_id", + value: OneSignal.User.pushSubscription.id + ) + } }, fallbackToSettings: true) ``` ### Pushwoosh \{#pushwoosh\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration du SDK pour l'intégration Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers - let params = AdaptyProfileParameters.Builder() - .with(pushwooshHWID: Pushwoosh.sharedInstance().getHWID()) - .build() - - Adapty.updateProfile(params: params) { error in - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "pushwoosh_hwid", + value: Pushwoosh.sharedInstance().getHWID() + ) + } catch { + // handle the error + } ``` ## Mettre à jour l'implémentation du mode Observer \{#update-observer-mode-implementation\} Mettez à jour la façon dont vous liez les paywalls aux transactions. Auparavant, vous utilisiez la méthode `setVariationId` pour assigner le `variationId`. Désormais, vous pouvez inclure le `variationId` directement lors de l'enregistrement de la transaction via la nouvelle méthode `reportTransaction`. Consultez l'exemple de code final dans [Associer des paywalls à des transactions d'achat en mode Observer](report-transactions-observer-mode). :::warning N'oubliez pas d'enregistrer la transaction via la méthode `reportTransaction`. Si vous omettez cette étape, Adapty ne reconnaîtra pas la transaction, n'accordera pas les niveaux d'accès, ne l'inclura pas dans les analytics et ne l'enverra pas aux intégrations. Cette étape est indispensable ! ::: ```diff showLineNumbers - let variationId = paywall.variationId - - // There are two overloads: for StoreKit 1 and StoreKit 2 - Adapty.setVariationId(variationId, forPurchasedTransaction: transaction) { error in - if error == nil { - // successful binding - } - } + do { + // every time when calling transaction.finish() + try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) + } catch { + // handle the error + } ``` --- # File: migration-to-ios-sdk-v3 --- --- title: "Migrer le SDK Adapty iOS vers v3.0" description: "Migrez vers le SDK Adapty iOS v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Adapty Paywall Builder](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et à ses riches capacités de design, vos paywalls seront plus efficaces et rentables que jamais. :::info Veuillez noter que la bibliothèque AdaptyUI est dépréciée et fait désormais partie intégrante d'AdaptySDK. ::: ## Réinstaller le SDK Adapty v3.x via Swift Package Manager \{#reinstall-adapty-sdk-v3x-via-swift-package-manager\} 1. Supprimez la dépendance au package AdaptyUI de votre projet, vous n'en aurez plus besoin. 2. Même si vous l'avez déjà, vous devrez ré-ajouter la dépendance au SDK Adapty. Pour cela, dans Xcode, ouvrez **File** -> **Add Package Dependency...**. Notez que la façon d'ajouter des dépendances de packages peut varier selon les versions de XCode. Consultez la documentation XCode si nécessaire. 3. Entrez l'URL du dépôt `https://github.com/adaptyteam/AdaptySDK-iOS.git` 4. Choisissez la version, puis cliquez sur le bouton **Add package**. 5. Choisissez les modules dont vous avez besoin : 1. **Adapty** est le module obligatoire 2. **AdaptyUI** est un module optionnel nécessaire si vous prévoyez d'utiliser le [Adapty Paywall Builder](adapty-paywall-builder). 6. Xcode ajoutera la dépendance au package à votre projet, et vous pourrez l'importer. Pour cela, dans la fenêtre **Choose Package Products**, cliquez à nouveau sur le bouton **Add package**. Le package apparaîtra dans la liste **Packages**. ## Réinstaller le SDK Adapty v3.x via CocoaPods \{#reinstall-adapty-sdk-v3x-via-cocoapods\} 1. Ajoutez Adapty à votre `Podfile`. Choisissez les modules dont vous avez besoin : 1. **Adapty** est le module obligatoire. 2. **AdaptyUI** est un module optionnel nécessaire si vous prévoyez d'utiliser le [Adapty Paywall Builder](adapty-paywall-builder). 2. ```shell showLineNumbers title="Podfile" pod 'Adapty', '~> 3.2.0' pod 'AdaptyUI', '~> 3.2.0' # optional module needed only for Paywall Builder ``` 3. Exécutez : ```sh showLineNumbers title="Shell" pod install ``` Cela crée un fichier `.xcworkspace` pour votre application. Utilisez ce fichier pour tout le développement futur de votre application. Activez les modules SDK Adapty et AdaptyUI. Avant la v3.0, vous n'activiez pas AdaptyUI — pensez à **ajouter l'activation d'AdaptyUI**. Les paramètres ne changent pas, conservez-les tels quels. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() ``` </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```swift title="" showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() } var body: some Scene { WindowGroup { ContentView() } } } ``` </TabItem> </Tabs> --- # End of Documentation _Generated on: 2026-08-04T15:08:26.047Z_ _Successfully processed: 53/53 files_ # KMP - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:26.049Z Total files: 48 --- # File: kmp-sdk-overview --- --- title: "Vue d'ensemble du SDK Kotlin Multiplatform" description: "Découvrez le SDK Adapty Kotlin Multiplatform et ses principales fonctionnalités." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-KMP.svg?style=flat&logo=kotlin)](https://github.com/adaptyteam/AdaptySDK-KMP/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le SDK Adapty Kotlin Multiplatform pour vous décharger de la gestion des achats intégrés, afin que vous puissiez vous concentrer sur ce que vous faites de mieux – créer des applications extraordinaires. Voici ce que nous gérons pour vous : - Gestion des achats, validation des reçus et gestion des abonnements clés en main - Création et test de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans configuration – cohortes, LTV, churn et analyse de tunnel inclus - Statut d'abonnement toujours à jour entre les sessions et les appareils - Intégration de votre application avec des services d'attribution marketing et d'analyse en une seule ligne de code :::note Avant de plonger dans le code, vous devrez intégrer Adapty avec Google Play Console et configurer des produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Premiers pas \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous aborderons dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-kotlin-multiplatform) : Ajoutez le SDK comme dépendance à votre projet et activez-le dans le code. 2. [Activer les achats via des flows](kmp-quickstart-paywalls) : Configurez le flux d'achat pour que les utilisateurs puissent acheter des produits. Pour créer votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](kmp-quickstart-manual). 3. [Vérifier le statut de l'abonnement](kmp-check-subscription-status) : Vérifiez automatiquement l'état de l'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (optionnel)](kmp-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir que leurs données sont stockées de manière cohérente sur tous les appareils. ### Le voir en action \{#see-it-in-action\} Vous voulez voir comment tout s'assemble ? Nous avons ce qu'il vous faut : - **Exemple d'application** : Consultez notre [exemple complet](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example) qui illustre la configuration complète - **Tutoriel vidéo** : Suivez notre vidéo d'implémentation étape par étape ci-dessous <iframe width="560" height="315" src="https://www.youtube.com/embed/JfwJvwnloNw?si=HskPxRk4WGkF_u9s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ## Concepts principaux \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts clés qui font fonctionner Adapty. La beauté de l'approche d'Adapty, c'est que seuls les placements sont codés en dur dans votre application. Tout le reste – produits, designs de paywalls, tarifs et offres – peut être géré de manière flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre application – abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Produits regroupés avec une configuration, associés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, créée dans le Flow Builder. Adapty gère l'interface et l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous construisez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](kmp-quickstart-manual). Dans le code SDK, les deux sont récupérés via la même méthode `getFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Pensez aux placements comme au « où » et au « quand » de votre stratégie de monétisation. Les placements courants incluent : - `main` - Votre emplacement de paywall principal - `onboarding` - Affiché pendant le flow d'onboarding de l'utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits de votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque les utilisateurs achètent un produit, leur profil se voit attribuer un **niveau d'accès** que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-kotlin-multiplatform --- --- title: "Installer et configurer le SDK Adapty Kotlin Multiplatform" description: "Installez et configurez le SDK Adapty pour les applications Kotlin Multiplatform." --- Le SDK Adapty comprend deux modules clés pour une intégration fluide dans votre application mobile : - **Core Adapty** : ce SDK essentiel est requis pour qu'Adapty fonctionne correctement dans votre application. - **AdaptyUI** (`io.adapty:adapty-kmp-ui`) : ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder) avec la couche de rendu Compose Multiplatform (`view.present()`). Si votre projet n'utilise pas Compose Multiplatform, vous pouvez utiliser [`createNativePaywallView`](kmp-present-paywalls#without-compose-multiplatform) et [`createNativeOnboardingView`](kmp-present-onboardings#without-compose-multiplatform) depuis le module core. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez notre [exemple d'application](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example), qui illustre la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: Pour un guide d'implémentation complet, vous pouvez également regarder la vidéo : <iframe width="560" height="315" src="https://www.youtube.com/embed/JfwJvwnloNw?si=HskPxRk4WGkF_u9s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ## Prérequis \{#requirements\} Le SDK Adapty Kotlin Multiplatform est compatible avec Xcode 16.2 et versions ultérieures. :::info À partir du SDK v3.17, le SDK Adapty utilise Google Play Billing Library v8.0.0 par défaut. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty via Gradle \{#install-adapty-sdk-via-gradle\} L'installation du SDK Adapty avec Gradle est requise pour les applications Android et iOS. Choisissez votre méthode de configuration des dépendances : - Gradle standard : ajoutez les dépendances dans votre `build.gradle` **au niveau du module** - Si votre projet utilise des fichiers `.gradle.kts`, ajoutez les dépendances dans votre `build.gradle.kts` **au niveau du module** - Si vous utilisez des catalogues de versions, ajoutez les dépendances dans votre fichier `libs.versions.toml`, puis référencez-les dans `build.gradle.kts` :::important Le SDK Adapty Kotlin Multiplatform 4.0 est une version préliminaire. Gradle ne sélectionne pas les versions préliminaires via les plages de versions dynamiques (comme `+` ou `latest.release`), vous devez donc fixer la version exacte — par exemple `io.adapty:adapty-kmp:4.0.0-beta.1`, ou `adapty-kmp = "4.0.0-beta.1"` dans `libs.versions.toml`. Consultez [Migrer le SDK Adapty Kotlin Multiplatform vers v4](migration-to-kmp-sdk-v4). ::: <Tabs> <TabItem value="module-level build.gradle" label="module-level build.gradle" default> ```kotlin showLineNumbers kotlin { sourceSets { commonMain { dependencies { implementation libs.adapty.kmp } } } } ``` </TabItem> <TabItem value="module-level build.gradle.kts" label="module-level build.gradle.kts" default> ```kotlin showLineNumbers kotlin { sourceSets { val commonMain by getting { dependencies { implementation(libs.adapty.kmp) } } } } ``` </TabItem> <TabItem value="version-catalog" label="Versions library" default> ```toml showLineNumbers // libs.versions.toml [versions] .. adapty-kmp = "<the latest SDK version>" [libraries] .. adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" } // build.gradle.kts kotlin { sourceSets { val commonMain by getting { dependencies { implementation(libs.adapty.kmp) } } } } ``` </TabItem> </Tabs> :::note Si vous obtenez une erreur liée à Maven, vérifiez que vous avez bien `mavenCentral()` dans vos scripts Gradle. <details> <summary>Les instructions pour l'ajouter</summary> Si votre projet n'a pas de `dependencyResolutionManagement` dans votre `settings.gradle`, ajoutez ce qui suit dans votre `build.gradle` de niveau supérieur, à la fin de la section repositories : ```groovy showLineNumbers title="top-level build.gradle" allprojects { repositories { ... mavenCentral() } } ``` Sinon, ajoutez ce qui suit dans votre `settings.gradle`, dans la section `repositories` de `dependencyResolutionManagement` : ```groovy showLineNumbers title="settings.gradle" dependencyResolutionManagement { ... repositories { ... google() mavenCentral() } } ``` </details> ::: ## Activer le SDK Adapty \{#activate-adapty-sdk\} ### Configuration de base \{#basic-setup\} Ajoutez l'initialisation le plus tôt possible — généralement dans votre code Kotlin partagé pour les deux plateformes. :::note Le SDK Adapty ne doit être activé qu'une seule fois dans votre application. ::: ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` :::important Attendez que `activate` se termine avant d'appeler toute autre méthode du SDK Adapty. Consultez [Ordre des appels dans le SDK Kotlin Multiplatform](kmp-sdk-call-order) pour la séquence complète. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et rendez-vous dans [App settings → General](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (PAS la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. :::info - Assurez-vous d'utiliser la Public SDK Key pour initialiser Adapty ; la Secret Key doit être utilisée uniquement pour l'[API côté serveur](getting-started-with-server-side-api). - Les clés SDK sont uniques pour chaque application, donc si vous avez plusieurs applications, assurez-vous de choisir la bonne. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), activez d'abord le [module AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) ci-dessous, puis suivez le [démarrage rapide avec Paywall Builder](kmp-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [démarrage rapide pour les paywalls personnalisés](kmp-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'activer le module **AdaptyUI** pour utiliser le [Adapty Paywall Builder](kmp-present-paywalls), veillez à définir `.withActivateUI(true)` dans votre configuration. :::info important Dans votre code, vous devez activer le module core Adapty avant d'activer AdaptyUI. ::: ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withActivateUI(true) // true for activating the AdaptyUI module .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` ## Configurer Proguard (Android) \{#configure-proguard-android\} Avant de lancer votre application en production, vous devrez peut-être ajouter `-keep class com.adapty.** { *; }` à votre configuration Proguard. ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Niveau | Description | | :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | | `AdaptyLogLevel.ERROR` | Seules les erreurs seront journalisées. | | `AdaptyLogLevel.WARN` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais méritent attention, seront journalisés. | | `AdaptyLogLevel.INFO` | Les erreurs, avertissements et divers messages d'information seront journalisés. Valeur par défaut. | | `AdaptyLogLevel.VERBOSE` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera journalisée. | | `AdaptyLogLevel.DEBUG` | Les informations les plus détaillées, y compris les données de débogage internes, seront journalisées. | Vous pouvez définir le niveau de journalisation dans votre application avant de configurer Adapty : ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withLogLevel(AdaptyLogLevel.VERBOSE) // recommended for development .build() ``` ### Politiques de données \{#data-policies\} #### Désactiver la collecte et le partage de l'adresse IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` à `true` pour désactiver la collecte et le partage de l'adresse IP de l'utilisateur. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, respecter les réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'IP ne sont pas requises pour votre application. ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build() ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `appleIdfaCollectionDisabled` (iOS) ou `googleAdvertisingIdCollectionDisabled` (Android) à `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour vous conformer aux politiques de l'App Store/Play Store, éviter de déclencher la demande App Tracking Transparency, ou si votre application ne nécessite pas d'attribution publicitaire ni d'analyses basées sur les identifiants publicitaires. ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withGoogleAdvertisingIdCollectionDisabled(true) // Android only .withAppleIdfaCollectionDisabled(true) // iOS only .build() ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire l'utilisation du réseau. Vous pouvez personnaliser les paramètres du cache en fournissant une configuration personnalisée. Utilisez `mediaCache` pour remplacer les paramètres de cache par défaut : ```kotlin val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withMediaCacheConfiguration( AdaptyConfig.MediaCacheConfiguration( memoryStorageTotalCostLimit = 200 * 1024 * 1024, // 200 MB memoryStorageCountLimit = Int.MAX_VALUE, diskStorageSizeLimit = 200 * 1024 * 1024 // 200 MB ) ) .build() ``` ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont désactivés pour Android. Pour les activer, définissez `withLocalAccessLevelAllowed` à `true` : ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withGoogleLocalAccessLevelAllowed(true) .build() ``` ### Effacer les données lors de la restauration d'une sauvegarde \{#clear-data-on-backup-restore\} Lorsque `withAppleClearDataOnBackup` est défini à `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, y compris les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état vierge. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```swift showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withAppleClearDataOnBackup(true) .build() ``` ## Dépannage \{#troubleshooting\} #### Règles de sauvegarde Android (configuration Auto Backup) \{#android-backup-rules-auto-backup-configuration\} Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules` ou `android:allowBackup`. Symptômes typiques : `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 Ces modifications doivent être effectuées dans votre répertoire de la plateforme Android (généralement situé dans le dossier `android/` de votre projet). ::: Pour résoudre ce problème, vous devez : - Indiquer au gestionnaire de fusion de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Créer des fichiers de règles de sauvegarde qui fusionnent les règles d'Adapty avec celles des autres SDKs. #### 1. Ajoutez l'espace de noms `tools` à votre manifeste \{#1-add-the-tools-namespace-to-your-manifest\} Dans votre fichier `AndroidManifest.xml`, assurez-vous que la balise racine `<manifest>` inclut tools : ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. Remplacez les attributs de sauvegarde dans `<application>` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `<application>` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion de remplacer les valeurs des bibliothèques : ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez les fichiers de règles de sauvegarde fusionnés \{#3-create-merged-backup-rules-files\} Créez des fichiers XML dans le répertoire `res/xml/` de votre projet Android, en combinant les règles d'Adapty avec celles des autres SDKs. Android utilise des formats de règles de sauvegarde différents selon la version de l'OS, donc créer les deux fichiers garantit la compatibilité avec toutes les versions d'Android prises en charge par votre application. :::note Les exemples ci-dessous utilisent AppsFlyer comme exemple de SDK tiers. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::important Dans un projet Kotlin Multiplatform, appliquez ces modifications dans le module d'application Android (celui qui produit l'APK/AAB), par exemple `androidApp` ou `app` : - Manifest : `androidApp/src/main/AndroidManifest.xml` - XML des règles de sauvegarde : `androidApp/src/main/res/xml/` ::: #### Les achats échouent après être revenu d'une autre application sur Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si l'Activity qui démarre le flux d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser de manière incorrecte lorsque l'utilisateur revient de Google Play, d'une application bancaire ou d'un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son traitement comme annulé. Pour garantir le bon fonctionnement des achats, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flux d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui démarre le flux d'achat est définie sur `standard` ou `singleTop` : ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` --- # File: kmp-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK Kotlin Multiplatform" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Ce guide utilise les API du SDK Adapty Kotlin Multiplatform v4 (bêta). Si vous utilisez la v3, consultez le [guide de migration](migration-to-kmp-sdk-v4) pour les noms de méthodes correspondants. Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – des séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez plutôt un paywall — voir [Implémenter les paywalls manuellement](kmp-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez les flows dans votre application (par exemple `main`, `onboarding`, `settings`). Vous associez des flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère tout le flux d'achat, la validation des reçus et la gestion des abonnements en coulisses. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre application, mais récupérez quand même l'objet flow depuis Adapty pour garder de la flexibilité sur les offres produits. Voir le [guide](kmp-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur présente des limitations dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.** Si vous préférez construire l'interface du paywall vous-même, voir [Implémenter les paywalls manuellement](kmp-quickstart-manual). ::: Pour afficher un flow créé dans Adapty Flow Builder, vous n'avez besoin que de : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre application. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans l'Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez-y votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-kotlin-multiplatform) dans le code de votre application. :::tip La façon la plus rapide de réaliser ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des flows et des placements avec la [Developer CLI](developer-cli-quickstart). ::: ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter différents flows pour différentes audiences ou de lancer des [tests A/B](ab-tests). Pour récupérer un flow créé dans Adapty Flow Builder, vous devez : 1. Obtenir l'objet `flow` par l'ID du [placement](placements) en utilisant la méthode `getFlow`. 2. Créer la vue du flow avec la méthode `createFlowView`. La vue contient les éléments d'interface et le style nécessaires pour afficher le flow. Si aucune vue n'est configurée pour le flow, `createFlowView` retourne une erreur — gérez-la dans `onError`. :::important Pour obtenir la vue, vous devez activer le bouton **Show on device** dans le Flow Builder. Sinon, `createFlowView` retournera une erreur et le flow ne sera pas affiché. ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // the flow has no view configured, or view creation failed } } .onError { error -> // handle the error } ``` ## 2. Afficher le flow \{#2-display-the-flow\} Une fois que vous avez le flow, quelques lignes suffisent pour l'afficher. Pour afficher le flow visuel à l'écran de l'appareil, vous devez d'abord créer la vue. Pour ce faire, appelez la méthode `AdaptyUI.createFlowView()` : ```kotlin showLineNumbers AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // handle the error } ``` Une fois la vue créée avec succès, vous pouvez la présenter à l'écran de l'appareil. Chaque vue ne peut être utilisée qu'une seule fois : après avoir appelé `dismiss()`, appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois. :::tip Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](kmp-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Kotlin Multiplatform gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des liens. Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Ou vous souhaitez peut-être remplacer leur comportement par défaut. Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire. Notez que, par défaut, le flow reste ouvert après un achat réussi. Si vous souhaitez le fermer une fois l'achat terminé, ignorez la vue dans le callback `flowViewDidFinishPurchase`. :::tip Consultez nos guides sur la gestion des [actions](kmp-handle-paywall-actions) et des [événements](kmp-handling-events) des boutons. ::: ```kotlin showLineNumbers AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } else -> Unit } } override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) { mainUiScope.launch { view.dismiss() } } } }) ``` ## Prochaines étapes \{#next-steps\} Votre flow est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow. Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](kmp-check-subscription-status) pour vous assurer d'afficher un flow ou d'accorder l'accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment toutes ces étapes peuvent être intégrées ensemble dans votre application. ```kotlin showLineNumbers // Set up the observer for handling flow events AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } else -> Unit } } override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) { mainUiScope.launch { view.dismiss() } } } }) // Get and display the flow Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // the flow has no view configured — use custom logic } } .onError { error -> // handle the error } ``` --- # File: kmp-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK Kotlin Multiplatform" description: "Apprenez à vérifier le statut d'abonnement dans votre application Kotlin Multiplatform avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — afficher un paywall ou leur donner accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Quand vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Vous avez deux options : - Appelez `getProfile` si vous avez besoin des données de profil les plus récentes immédiatement (comme au lancement de l'application) ou si vous souhaitez forcer une mise à jour. - Configurez des **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement à chaque changement de statut d'abonnement. ### Récupérer le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access } .onError { error -> // handle the error } ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour du profil dans votre application : 1. Utilisez `Adapty.setOnProfileUpdatedListener()` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode chaque fois que le statut d'abonnement de l'utilisateur change. 2. Stockez les données du profil mis à jour quand cette méthode est appelée, afin de pouvoir les utiliser partout dans votre application sans effectuer de requêtes réseau supplémentaires. ```kotlin showLineNumbers class SubscriptionManager { private var currentProfile: AdaptyProfile? = null init { // Listen for profile updates Adapty.setOnProfileUpdatedListener { profile -> currentProfile = profile // Update UI, unlock content, etc. } } // Use stored profile instead of calling getProfile() fun hasAccess(): Boolean { return currentProfile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true } } ``` :::note Adapty appelle automatiquement le listener de mise à jour du profil au démarrage de votre application, fournissant ainsi les données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Associer le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates sur l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'accès aux sections premium ou avant l'affichage de contenu spécifique. ```kotlin showLineNumbers private fun checkAccessAndShowPaywall() { // First, check if user has access Adapty.getProfile() .onSuccess { profile -> val hasAccess = profile.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true if (!hasAccess) { // User doesn't have access, show paywall showPaywall() } else { // User has access, show premium content showPremiumContent() } } .onError { error -> // If we can't check access, show paywall as fallback showPaywall() } } private fun showPaywall() { // Get and display paywall using the KMP SDK Adapty.getPaywall("YOUR_PLACEMENT_ID") .onSuccess { paywall -> if (paywall.hasViewConfiguration) { val paywallView = AdaptyUI.createPaywallView(paywall = paywall) paywallView?.present() } else { // Handle remote config paywall or show custom UI handleRemoteConfigPaywall(paywall) } } .onError { error -> // Handle paywall loading error showError("Unable to load paywall") } } private fun showPremiumContent() { // Show your premium content here // This is where you unlock paid features } ``` ## Étapes suivantes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](kmp-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce qu'ils ont payé. --- # File: kmp-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK Kotlin Multiplatform" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans KMP." --- :::important Ce guide vous concerne si vous disposez de votre propre système d'authentification. Vous apprendrez ici comment gérer les profils utilisateurs dans Adapty afin de les aligner avec votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez un **customer user ID** afin de faire le lien entre les profils Adapty et votre système d'authentification interne. Voici les différences entre les utilisateurs anonymes et identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|----------------------------------------------------------------|--------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil entre les sessions et les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'application | Les données des utilisateurs identifiés persistent entre les installations de l'application | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lors de l'activation du SDK au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, celui-ci est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe depuis un **nouvel appareil**, Adapty **crée un nouveau profil anonyme à l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, ses achats sont par défaut automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. Ainsi, avec les utilisateurs anonymes, de nouveaux profils sont créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. :::note Les restaurations à partir d'une sauvegarde se comportent différemment des réinstallations. Par défaut, lorsqu'un utilisateur restaure depuis une sauvegarde, le SDK conserve les données en cache et ne crée pas de nouveau profil. Vous pouvez configurer ce comportement à l'aide du paramètre `withAppleClearDataOnBackup`. [En savoir plus](sdk-installation-kotlin-multiplatform#clear-data-on-backup-restore). ::: ## Utilisateurs identifiés \{#identified-users\} Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils bénéficient d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après qu'ils se sont connectés ou inscrits), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez pas encore utilisé ce customer user ID**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez la valeur du paramètre en dur, tous les utilisateurs seront considérés comme un seul et même utilisateur. ::: Attendez que `identify` se termine (dans son callback `onSuccess`) avant d'appeler d'autres méthodes du SDK. Des appels simultanés peuvent atterrir sur le profil anonyme. Voir [Ordre des appels dans le SDK Kotlin Multiplatform](kmp-sdk-call-order). ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID au moment d'activer le SDK, vous pouvez l'envoyer dans la méthode `activate` au lieu d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`. Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé) ou un nouveau. Si vous en passez un nouveau, le nouveau profil créé lors de l'activation sera automatiquement lié au customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées en fonction des ID d'appareil. Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une énième installation, ni de l'utilisation d'un customer user ID existant. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génèrent pas d'événements d'installation supplémentaires. Si vous souhaitez compter les installations en fonction des utilisateurs uniques plutôt que des appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build() ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si vous avez un bouton pour déconnecter les utilisateurs, utilisez la méthode `logout`. :::important La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur. ::: ```kotlin showLineNumbers Adapty.logout() .onSuccess { // successful logout } .onError { error -> // handle the error } ``` :::info Pour reconnecter des utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur non connecté effectue un achat, Adapty l'associe à son ID de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez obtenir le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](kmp-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](kmp-check-subscription-status) pour que les données se synchronisent automatiquement. ## Étapes suivantes \{#next-steps\} Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons beaucoup de succès dans la monétisation de votre application ! Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code - [**Définir des attributs de profil personnalisés**](kmp-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher des paywalls différents à différents utilisateurs --- # File: adapty-sdk-integration-skill-kmp --- --- title: "Intégrer Adapty dans votre application Kotlin Multiplatform avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Kotlin Multiplatform de bout en bout avec votre outil de codage IA." --- :::important La compétence est en version bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-kmp) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-kmp --- --- title: "Intégrer Adapty dans votre application Kotlin Multiplatform avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre application Kotlin Multiplatform avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Kotlin Multiplatform à l'aide d'un outil IA — vous lui fournissez la bonne documentation Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite une configuration préalable dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire via un skill LLM interactif ou manuellement depuis le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre application, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Vous devez uniquement [connecter vos stores](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris quand ouvrir le Dashboard pour connecter vos stores. ### Approche manuelle \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les fournir vous-même. 1. **Connectez vos stores** : dans l'Adapty Dashboard, rendez-vous dans **App settings → General**. Connectez l'App Store et Google Play si votre application KMP cible les deux plateformes. C'est indispensable pour que les achats fonctionnent. [Connecter les stores](integrate-payments) 2. **Copiez votre clé SDK publique** : dans l'Adapty Dashboard, rendez-vous dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez au builder de configuration Adapty. 3. **Créez au moins un produit** : dans l'Adapty Dashboard, rendez-vous sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les transmet via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis associez-le à un placement sur la page **Placements**. Dans le code, l'ID du placement est la chaîne que vous passez à `Adapty.getPaywall("YOUR_PLACEMENT_ID")`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels["premium"]?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants ont accès à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` vs. un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Dites à votre LLM : « Ma clé SDK publique est X, mon ID de placement est Y » pour qu'il génère le code d'initialisation et de récupération des paywalls correct. ::: ### À configurer quand vous êtes prêt \{#set-up-when-ready\} Ces éléments ne sont pas requis pour commencer à coder, mais vous en aurez besoin au fil de votre intégration : - **Tests A/B** : à configurer sur la page **Placements**. Aucune modification de code nécessaire. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : ajoutez des appels `getPaywall` avec différents IDs de placement. - **Intégrations analytics** : à configurer sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytics](analytics-integration) et [intégrations attribution](attribution-integration). ## Alimenter votre LLM avec la documentation Adapty \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs en fonction de ce que vous demandez — plus besoin de coller des URL manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez : ``` npx ctx7 setup ``` Cette commande détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the Kotlin Multiplatform SDK ``` :::warning Même si Context7 évite de coller des liens de documentation manuellement, l'ordre d'implémentation reste important. Suivez la [procédure d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne. ::: ### Utiliser la documentation en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle page de documentation Adapty en Markdown brut. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-kmp.md](https://adapty.io/docs/fr/adapty-cursor-kmp.md). Chaque étape de la [procédure d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc « À envoyer à votre LLM » avec des liens `.md` à coller. Pour accéder à plus de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Procédure d'implémentation \{#implementation-walkthrough\} La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devriez observer une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode de planification (comme le mode plan de Cursor ou Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire du code. Indiquez à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides à suivre : - [**Adapty Paywall Builder**](adapty-paywall-builder) : vous créez des paywalls dans le builder no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](kmp-making-purchases) : vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats. - [**Mode Observer**](observer-vs-full-mode) : vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour les analytics et les intégrations. Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le guide de démarrage rapide](kmp-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez la dépendance du SDK Adapty via Gradle et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans ça. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-kotlin-multiplatform) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-kotlin-multiplatform.md ``` :::tip[Checkpoint] - **Attendu :** L'application se compile et se lance. Logcat (Android) ou la console Xcode (iOS) affiche le log d'activation Adapty. - **Point d'attention :** « Public API key is missing » → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides nécessaires dépendent de la façon dont vous gérez les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **Guides :** - [Activer les achats avec les paywalls (démarrage rapide)](kmp-quickstart-paywalls) - [Récupérer les paywalls du Paywall Builder et leur configuration](kmp-get-pb-paywalls) - [Afficher les paywalls](kmp-present-paywalls) - [Gérer les événements de paywall](kmp-handling-events) - [Répondre aux actions des boutons](kmp-handle-paywall-actions) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/kmp-quickstart-paywalls.md - https://adapty.io/docs/fr/kmp-get-pb-paywalls.md - https://adapty.io/docs/fr/kmp-present-paywalls.md - https://adapty.io/docs/fr/kmp-handling-events.md - https://adapty.io/docs/fr/kmp-handle-paywall-actions.md ``` :::tip[Checkpoint] - **Attendu :** Le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Point d'attention :** Paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement au tableau de bord et que le placement a bien une audience assignée. ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **Guides :** - [Activer les achats dans votre paywall personnalisé (démarrage rapide)](kmp-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-kmp) - [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-kmp) - [Effectuer des achats](kmp-making-purchases) - [Restaurer des achats](kmp-restore-purchase) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/kmp-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-kmp.md - https://adapty.io/docs/fr/present-remote-config-paywalls-kmp.md - https://adapty.io/docs/fr/kmp-making-purchases.md - https://adapty.io/docs/fr/kmp-restore-purchase.md ``` :::tip[Checkpoint] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Point d'attention :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Observer mode"> **Guides :** - [Vue d'ensemble du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode-kmp) - [Signaler les transactions en mode Observer](report-transactions-observer-mode-kmp) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-kmp.md - https://adapty.io/docs/fr/report-transactions-observer-mode-kmp.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty. - **Point d'attention :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez dans le profil utilisateur la présence d'un niveau d'accès actif pour restreindre l'accès au contenu premium. **Guide :** [Vérifier le statut de l'abonnement](kmp-check-subscription-status) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/kmp-check-subscription-status.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox, `profile.accessLevels["premium"]?.isActive` retourne `true`. - **Point d'attention :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Liez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent d'un appareil à l'autre. :::important Ignorez cette étape si votre application ne dispose pas d'authentification. ::: **Guide :** [Identifier les utilisateurs](kmp-quickstart-identify) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/kmp-quickstart-identify.md ``` :::tip[Checkpoint] - **Attendu :** Après avoir appelé `Adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Point d'attention :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution à un profil anonyme. ::: ### Préparer la mise en production \{#prepare-for-release\} Une fois votre intégration validée en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt pour la production. **Guide :** [Checklist de mise en production](release-checklist) À envoyer à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Checkpoint] - **Attendu :** Tous les éléments de la checklist confirmés : connexions aux stores, notifications serveur, flux d'achat, vérifications des niveaux d'accès et exigences de confidentialité. - **Point d'attention :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**. ::: ## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\} Si vous avez besoin de donner à votre LLM un contexte plus large au-delà des pages individuelles, nous hébergeons des fichiers d'index qui listent ou combinent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par exemple ChatGPT), vous devrez télécharger `llms.txt` et le joindre à la conversation en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : toute la documentation Adapty combinée en un seul fichier. Très volumineux — à utiliser uniquement quand vous avez besoin d'une vue d'ensemble complète. - Sous-ensembles spécifiques à Kotlin Multiplatform [`kmp-llms.txt`](https://adapty.io/docs/fr/kmp-llms.txt) et [`kmp-llms-full.txt`](https://adapty.io/docs/fr/kmp-llms-full.txt) : sous-ensembles par plateforme qui économisent des tokens par rapport au site complet. --- # File: kmp-paywalls --- --- title: "Flows et paywalls - Kotlin Multiplatform" description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre application Kotlin Multiplatform." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['kmp-get-pb-paywalls', 'kmp-present-paywalls', 'kmp-handling-events', 'kmp-handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](kmp-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['kmp-quickstart-manual', 'fetch-paywalls-and-products-kmp', 'present-remote-config-paywalls-kmp', 'kmp-making-purchases']} /> Pour d'autres guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](kmp-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['kmp-use-fallback-paywalls', 'kmp-web-paywalls']} /> --- # File: kmp-get-pb-paywalls --- --- title: "Récupérer les flows et paywalls - Kotlin Multiplatform" description: "Récupérez les flows et paywalls depuis Adapty dans votre application Kotlin Multiplatform." --- <SDKv4> <MethodPromo method="getFlow" /> Après [avoir conçu votre flow ou paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration de vue, comme décrit ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des flows dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-kotlin-multiplatform) dans votre application mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration de vue, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le flow ou le paywall et sa [configuration de vue](kmp-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour récupérer un flow ou un paywall, utilisez la méthode `getFlow` : ```kotlin showLineNumbers Adapty.getFlow( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { flow -> // the requested flow/paywall }.onError { error -> // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront pas forcément les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour les récupérer plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système est conçu pour vous garantir toujours la dernière version tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 s | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en coulisses.</p><p>Pour Kotlin Multiplatform : vous pouvez créer une `Duration` avec des fonctions d'extension comme `5.seconds`, où `.seconds` provient de `kotlin.time.Duration.Companion.seconds`.</p> | Paramètres de réponse : | Paramètre | Description | | :-------- | :---------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`instanceIdentity`, `variationId`), le nom, les variantes de paywall (`paywalls` — une liste d'`AdaptyFlowPaywall`) et les Remote Configs (`remoteConfigs` — une liste avec une entrée par locale). Pour récupérer les produits réels en vue d'un préchargement, d'une interface personnalisée ou de vérifications programmatiques, appelez `getPaywallProducts(flow)`. | ## Récupérer la configuration de vue \{#fetch-the-view-configuration\} Après avoir récupéré le flow ou le paywall, chargez sa configuration de vue et créez la vue en une seule étape avec la méthode `createFlowView`. Il n'y a pas d'indicateur séparé à vérifier : si le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall), `createFlowView` renvoie la vue prête à être présentée. Si le placement est un paywall personnalisé sans interface Builder, `createFlowView` renvoie une `AdaptyResult.Error` — [traitez-le comme un paywall Remote Config](present-remote-config-paywalls-kmp). :::important Assurez-vous d'activer le bouton **Show on device** dans le Flow Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible pour la récupération. ::: ```kotlin showLineNumbers AdaptyUI.createFlowView( flow = flow, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { view -> // use view }.onError { error -> // the flow has no view configured, or view creation failed } ``` | Paramètre | Présence | Description | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **flow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | | **loadTimeout** | optionnel | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés. Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en coulisses. Vous pouvez utiliser des fonctions d'extension comme `5.seconds` de `kotlin.time.Duration.Companion`. | | **preloadProducts** | optionnel | Définissez sur `true` pour précharger les produits et améliorer les performances. Lorsqu'activé, les produits sont chargés à l'avance, réduisant le temps nécessaire pour afficher le flow ou le paywall. | | **productPurchaseParams** | optionnel | Une map d'[`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) vers [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Utilisez-la pour configurer des paramètres d'achat spécifiques, comme les offres personnalisées ou les paramètres de mise à jour d'abonnement pour des produits individuels dans le flow ou le paywall. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Builder](add-paywall-locale-in-adapty-paywall-builder). ::: Une fois chargé, [présentez le flow ou le paywall](kmp-present-paywalls). ## Récupérer un flow ou paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs ont une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois crucial de comprendre que l'approche recommandée consiste à récupérer le flow ou le paywall avec la méthode `getFlow`, comme décrit dans la section [Récupérer un flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients notables : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des flows différents selon les versions de l'application (actuelle et future), vous pourriez rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs avec la version actuelle (legacy) puissent rencontrer des problèmes avec des flows non rendus. - **Perte de ciblage** : tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des flows ou paywalls, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront pas forcément les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre flow ou paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente pour certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. Voici un exemple illustrant comment fournir des ressources personnalisées via une map : :::info Le SDK Kotlin Multiplatform ne prend en charge que les ressources locales. Pour le contenu distant, vous devez télécharger et mettre en cache les ressources localement avant de les utiliser dans les ressources personnalisées. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map<String, AdaptyCustomAsset> = mapOf( // Load image from app resources (bundled with the app) // Files should be placed in commonMain/composeResources/files/ "hero_image" to AdaptyCustomAsset.localImageResource( path = heroImagePath ), // Or use image byte data "avatar" to AdaptyCustomAsset.localImageData( data = imageByteData ), // Load video from app resources "demo_video" to AdaptyCustomAsset.localVideoResource( path = demoVideoPath ), // Or use a video file from device storage "intro_video" to AdaptyCustomAsset.localVideoFile( path = "/path/to/local/video.mp4" ), // Apply custom brand colors "brand_primary" to AdaptyCustomAsset.color( colorHex = "#FF6B35" ), // Create gradient background "card_gradient" to AdaptyCustomAsset.linearGradient( colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"), stops = listOf(0.0f, 0.5f, 1.0f) ) ) // Use custom assets when creating the flow view AdaptyUI.createFlowView( flow = flow, customAssets = customAssets ).onSuccess { view -> // Present the flow with custom assets view.present() }.onError { error -> // Handle the error - the flow will fall back to default appearance } } ``` :::note Si une ressource est introuvable ou ne se charge pas, le flow ou le paywall reviendra à son apparence par défaut configurée dans le Builder. ::: </SDKv4> <SDKv3> Après [avoir conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape de ce processus consiste à récupérer le paywall associé au placement et sa configuration de vue, comme décrit ci-dessous. Notez que ce sujet concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, reportez-vous à la rubrique [Récupérer les paywalls et produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-kmp). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-kotlin-multiplatform) dans votre application mobile. </details> ## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration de vue, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour récupérer un paywall, utilisez la méthode `getPaywall` : ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre est attendu sous la forme d'un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de locale](localizations-and-locale-codes) pour plus d'informations sur les codes de locale et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront pas forcément les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 s | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en coulisses.</p><p>Pour Kotlin Multiplatform : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.</p> | Paramètres de réponse : | Paramètre | Description | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objet [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) contenant une liste d'identifiants de produits, l'identifiant du paywall, la Remote Config et plusieurs autres propriétés. | ## Récupérer la configuration de vue d'un paywall conçu avec le Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible pour la récupération. ::: Après avoir récupéré le paywall, vérifiez s'il inclut une `ViewConfiguration`, ce qui indique qu'il a été créé avec le Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si la `ViewConfiguration` est présente, traitez-le comme un paywall Paywall Builder ; sinon, [traitez-le comme un paywall Remote Config](present-remote-config-paywalls-kmp). Utilisez la méthode `createPaywallView` pour charger la configuration de vue. ```kotlin showLineNumbers if (paywall.hasViewConfiguration) { AdaptyUI.createPaywallView( paywall = paywall, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { paywallView -> // use paywallView }.onError { error -> // handle the error } } else { // use your custom logic } ``` | Paramètre | Présence | Description | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | requis | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. | | **loadTimeout** | optionnel | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés. Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en coulisses. Vous pouvez utiliser des fonctions d'extension comme `5.seconds` de `kotlin.time.Duration.Companion`. | | **preloadProducts** | optionnel | Définissez sur `true` pour précharger les produits et améliorer les performances. Lorsqu'activé, les produits sont chargés à l'avance, réduisant le temps nécessaire pour afficher le paywall. | | **productPurchaseParams** | optionnel | Une map d'[`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) vers [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Utilisez-la pour configurer des paramètres d'achat spécifiques, comme les offres personnalisées ou les paramètres de mise à jour d'abonnement pour des produits individuels dans le paywall. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Paywall Builder](add-paywall-locale-in-adapty-paywall-builder). ::: Une fois chargé, [présentez le paywall](kmp-present-paywalls). ## Récupérer un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls, et que vos utilisateurs ont une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois crucial de comprendre que l'approche recommandée consiste à récupérer le paywall avec la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients notables : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous pourriez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs avec la version actuelle (legacy) puissent rencontrer des problèmes avec des paywalls non rendus. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre est attendu sous la forme d'un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de locale](localizations-and-locale-codes) pour plus d'informations sur les codes de locale et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront pas forcément les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou une vidéo différente pour certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK Adapty vers la version 3.7.0 ou supérieure. ::: Voici un exemple illustrant comment fournir des ressources personnalisées via une map : :::info Le SDK Kotlin Multiplatform ne prend en charge que les ressources locales. Pour le contenu distant, vous devez télécharger et mettre en cache les ressources localement avant de les utiliser dans les ressources personnalisées. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map<String, AdaptyCustomAsset> = mapOf( // Load image from app resources (bundled with the app) // Files should be placed in commonMain/composeResources/files/ "hero_image" to AdaptyCustomAsset.localImageResource( path = heroImagePath ), // Or use image byte data "avatar" to AdaptyCustomAsset.localImageData( data = imageByteData ), // Load video from app resources "demo_video" to AdaptyCustomAsset.localVideoResource( path = demoVideoPath ), // Or use a video file from device storage "intro_video" to AdaptyCustomAsset.localVideoFile( path = "/path/to/local/video.mp4" ), // Apply custom brand colors "brand_primary" to AdaptyCustomAsset.color( colorHex = "#FF6B35" ), // Create gradient background "card_gradient" to AdaptyCustomAsset.linearGradient( colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"), stops = listOf(0.0f, 0.5f, 1.0f) ) ) // Use custom assets when creating paywall view AdaptyUI.createPaywallView( paywall = paywall, customAssets = customAssets ).onSuccess { paywallView -> // Present the paywall with custom assets paywallView.present() }.onError { error -> // Handle the error - paywall will fall back to default appearance } } ``` :::note Si une ressource est introuvable ou ne se charge pas, le paywall reviendra à son apparence par défaut configurée dans le Paywall Builder. ::: </SDKv3> --- # File: kmp-present-paywalls --- --- title: "Afficher les flows et paywalls - Kotlin Multiplatform" description: "Présentez les flows et paywalls aux utilisateurs dans votre application Kotlin Multiplatform." --- <SDKv4> <MethodPromo method="getFlow" label="Afficher les flows et paywalls" /> Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Ce guide couvre les flows et les **paywalls du nouveau Paywall Builder** rendus par Adapty. Le processus diffère pour les paywalls en Remote Config et le [mode Observateur](observer-vs-full-mode). - Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-kmp). - Pour présenter des flows en **mode Observateur**, consultez [Présenter des flows en mode Observateur](kmp-present-flows-in-observer-mode). ::: Pour obtenir l'objet `flow` utilisé ci-dessous, consultez [Récupérer les flows et paywalls](kmp-get-pb-paywalls). Le SDK Kotlin Multiplatform d'Adapty offre deux façons de présenter les flows et les paywalls : - **Avec Compose Multiplatform** - **Sans Compose Multiplatform** ## Avec Compose Multiplatform \{#with-compose-multiplatform\} Pour afficher un flow ou un paywall, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createFlowView`](kmp-get-pb-paywalls#fetch-the-view-configuration). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut entraîner une erreur. ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createFlowView(flow = flow).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode plutôt que les boîtes de dialogue natives lorsqu'un flow ou un paywall est présenté sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du flow, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du flow sur toutes les plateformes. ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { view.showDialog( title = "Close this screen?", content = "You will lose access to exclusive offers.", primaryActionTitle = "Stay", secondaryActionTitle = "Close" ).onSuccess { action -> if (action == AdaptyUIDialogActionType.SECONDARY) { // User confirmed - close the flow view.dismiss() } // If primary - do nothing, user stays }.onError { error -> // handle the error } } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le flow ou le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`. ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createFlowView(flow = flow).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ## Sans Compose Multiplatform \{#without-compose-multiplatform\} :::note `createNativeFlowView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`. ::: Pour intégrer un flow ou un paywall sans Compose Multiplatform, appelez `createNativeFlowView`. La méthode retourne un `AdaptyNativeFlowView` que vous ajoutez à votre mise en page : <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` Par défaut, une vue intégrée n'applique pas les marges de zone de sécurité — votre mise en page est censée gérer les insets elle-même. Si vous souhaitez que la vue les applique elle-même, passez `androidEnableSafeArea = true` à `createNativeFlowView`. Ce paramètre est spécifique à Android. </TabItem> <TabItem value="ios" label="iOS"> Comme les méthodes par défaut des interfaces KMP deviennent `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIFlowsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` : ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BaseFlowObserver : AdaptyUIFlowsEventsObserver ``` Créez ensuite une sous-classe en Swift, en ne redéfinissant que ce dont vous avez besoin : ```swift showLineNumbers title="Swift" class MyFlowObserver: BaseFlowObserver { override func flowViewDidPerformAction(view: AdaptyUIFlowView, action: any AdaptyUIAction) { if action is AdaptyUIActionCloseAction { // remove nativeView from your view hierarchy } } } let nativeView = AdaptyUI.shared.createNativeFlowView( flow: flow, observer: MyFlowObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### Libérer la vue \{#dispose-the-view\} Appelez `dispose()` lorsque vous retirez la vue de votre mise en page. Cela désenregistre l'écouteur d'événements et libère les ressources internes. ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` ## Tags personnalisés \{#custom-tags\} Les tags personnalisés vous permettent d'éviter de créer des flows ou des paywalls distincts pour différents scénarios. Imaginez un seul flow qui s'adapte dynamiquement selon les données de l'utilisateur. Par exemple, au lieu d'un générique « Bonjour ! », vous pourriez accueillir les utilisateurs personnellement avec « Bonjour, John ! » ou « Bonjour, Ann ! » Voici quelques façons d'utiliser les tags personnalisés : - Afficher le nom ou l'e-mail de l'utilisateur sur le flow ou le paywall. - Afficher le jour de la semaine actuel pour stimuler les ventes (par ex., « Bonne journée de jeudi »). - Ajouter des détails personnalisés sur les produits que vous vendez (comme le nom d'un programme fitness ou un numéro de téléphone dans une application VoIP). Les tags personnalisés vous aident à créer un flow flexible qui s'adapte à diverses situations, rendant l'interface de votre application plus personnalisée et engageante. :::warning Dans certains cas, votre application peut ne pas savoir par quoi remplacer un tag personnalisé — notamment si les utilisateurs utilisent une ancienne version du SDK AdaptyUI. Pour éviter ce problème, ajoutez toujours un texte de repli qui remplacera les lignes contenant des tags inconnus. Sans cela, les utilisateurs pourraient voir les tags affichés sous forme de code (`<USERNAME/>`). ::: Pour utiliser des tags personnalisés dans votre flow ou paywall, passez-les lors de la création de la vue de flow : <Tabs> <TabItem value="standalone" label="Avec Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) AdaptyUI.createFlowView( flow = flow, customTags = customTags ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Sans Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, customTags = customTags, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativeFlowView( flow = flow, observer = myFlowObserver, customTags = customTags, ) ``` </TabItem> </Tabs> ## Minuteries personnalisées \{#custom-timers\} La minuterie est un excellent outil pour promouvoir des offres spéciales et saisonnières avec une limite de temps. Notez cependant que cette minuterie n'est pas liée à la validité de l'offre ni à la durée de la campagne. Il s'agit simplement d'un compte à rebours autonome qui démarre à partir de la valeur que vous définissez et diminue jusqu'à zéro. Lorsque la minuterie atteint zéro, rien ne se passe — elle reste simplement à zéro. Vous pouvez personnaliser le texte avant et après la minuterie pour créer le message souhaité, par exemple : « Offre se termine dans : 10:00 sec. » Pour utiliser des minuteries personnalisées dans votre flow ou paywall, passez-les lors de la création de la vue de flow : <Tabs> <TabItem value="standalone" label="Avec Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) AdaptyUI.createFlowView( flow = flow, customTimers = customTimers ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Sans Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, customTimers = customTimers, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativeFlowView( flow = flow, observer = myFlowObserver, customTimers = customTimers, ) ``` </TabItem> </Tabs> </SDKv4> <SDKv3> Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Ce guide concerne uniquement les **paywalls du nouveau Paywall Builder**. Le processus de présentation diffère pour les paywalls conçus avec Remote Config et le [mode Observateur](observer-vs-full-mode). Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-kmp). ::: Le SDK Kotlin Multiplatform d'Adapty offre deux façons de présenter les paywalls : - **Avec Compose Multiplatform** - **Sans Compose Multiplatform** ## Avec Compose Multiplatform \{#with-compose-multiplatform\} Pour afficher un paywall, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createPaywallView`](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `createPaywallView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut entraîner une erreur. ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createPaywallView(paywall = paywall).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode plutôt que les boîtes de dialogue natives lorsqu'une vue de paywall est présentée sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes. ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { view.showDialog( title = "Close paywall?", content = "You will lose access to exclusive offers.", primaryActionTitle = "Stay", secondaryActionTitle = "Close" ).onSuccess { action -> if (action == AdaptyUIDialogActionType.SECONDARY) { // User confirmed - close the paywall view.dismiss() } // If primary - do nothing, user stays }.onError { error -> // handle the error } } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`. ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createPaywallView(paywall = paywall).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ## Sans Compose Multiplatform \{#without-compose-multiplatform\} :::note `createNativePaywallView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`. ::: Pour intégrer un paywall sans Compose Multiplatform, appelez `createNativePaywallView`. La méthode retourne un `AdaptyNativePaywallView` que vous ajoutez à votre mise en page : <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` </TabItem> <TabItem value="ios" label="iOS"> Comme les méthodes par défaut des interfaces KMP deviennent `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIPaywallsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` : ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BasePaywallObserver : AdaptyUIPaywallsEventsObserver ``` Créez ensuite une sous-classe en Swift, en ne redéfinissant que ce dont vous avez besoin : ```swift showLineNumbers title="Swift" class MyPaywallObserver: BasePaywallObserver { override func paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: any AdaptyUIAction) { if action is AdaptyUIActionCloseAction { // remove nativeView from your view hierarchy } } } let nativeView = AdaptyUI.shared.createNativePaywallView( paywall: paywall, observer: MyPaywallObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### Libérer la vue \{#dispose-the-view\} Appelez `dispose()` lorsque vous retirez la vue de votre mise en page. Cela désenregistre l'écouteur d'événements et libère les ressources internes. ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` ## Tags personnalisés \{#custom-tags\} Les tags personnalisés vous permettent d'éviter de créer des paywalls distincts pour différents scénarios. Imaginez un seul paywall qui s'adapte dynamiquement selon les données de l'utilisateur. Par exemple, au lieu d'un générique « Bonjour ! », vous pourriez accueillir les utilisateurs personnellement avec « Bonjour, John ! » ou « Bonjour, Ann ! » Voici quelques façons d'utiliser les tags personnalisés : - Afficher le nom ou l'e-mail de l'utilisateur sur le paywall. - Afficher le jour de la semaine actuel pour stimuler les ventes (par ex., « Bonne journée de jeudi »). - Ajouter des détails personnalisés sur les produits que vous vendez (comme le nom d'un programme fitness ou un numéro de téléphone dans une application VoIP). Les tags personnalisés vous aident à créer un paywall flexible qui s'adapte à diverses situations, rendant l'interface de votre application plus personnalisée et engageante. :::warning Dans certains cas, votre application peut ne pas savoir par quoi remplacer un tag personnalisé — notamment si les utilisateurs utilisent une ancienne version du SDK AdaptyUI. Pour éviter ce problème, ajoutez toujours un texte de repli qui remplacera les lignes contenant des tags inconnus. Sans cela, les utilisateurs pourraient voir les tags affichés sous forme de code (`<USERNAME/>`). ::: Pour utiliser des tags personnalisés dans votre paywall, passez-les lors de la création de la vue de paywall : <Tabs> <TabItem value="standalone" label="Avec Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) AdaptyUI.createPaywallView( paywall = paywall, customTags = customTags ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Sans Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, customTags = customTags, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativePaywallView( paywall = paywall, observer = myPaywallObserver, customTags = customTags, ) ``` </TabItem> </Tabs> ## Minuteries personnalisées \{#custom-timers\} La minuterie de paywall est un excellent outil pour promouvoir des offres spéciales et saisonnières avec une limite de temps. Notez cependant que cette minuterie n'est pas liée à la validité de l'offre ni à la durée de la campagne. Il s'agit simplement d'un compte à rebours autonome qui démarre à partir de la valeur que vous définissez et diminue jusqu'à zéro. Lorsque la minuterie atteint zéro, rien ne se passe — elle reste simplement à zéro. Vous pouvez personnaliser le texte avant et après la minuterie pour créer le message souhaité, par exemple : « Offre se termine dans : 10:00 sec. » Pour utiliser des minuteries personnalisées dans votre paywall, passez-les lors de la création de la vue de paywall : <Tabs> <TabItem value="standalone" label="Avec Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) AdaptyUI.createPaywallView( paywall = paywall, customTimers = customTimers ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Sans Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, customTimers = customTimers, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativePaywallView( paywall = paywall, observer = myPaywallObserver, customTimers = customTimers, ) ``` </TabItem> </Tabs> </SDKv3> --- # File: kmp-handle-paywall-actions --- --- title: "Répondre aux actions des flows - Kotlin Multiplatform" description: "Gérez les actions des boutons des flows et paywalls dans votre app Kotlin Multiplatform." --- <SDKv4> Si vous créez des flows ou des paywalls avec l'Adapty Flow Builder ou le Paywall Builder, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code. :::warning **Seuls les achats, les restaurations, la fermeture des flows/paywalls et l'ouverture de liens sont gérés automatiquement.** Toutes les autres actions de boutons, comme les actions personnalisées, nécessitent une implémentation adaptée dans le code de l'app. ::: ## Configurer l'AdaptyUIFlowsEventsObserver \{#set-up-the-adaptyuiflowseventsobserver\} Pour gérer les actions des flows, vous devez implémenter l'interface `AdaptyUIFlowsEventsObserver` et la configurer avec `AdaptyUI.setFlowsEventsObserver()`. Cette étape doit être effectuée tôt dans le cycle de vie de votre app, généralement dans votre activité principale ou lors de l'initialisation de l'app. ```kotlin // In your app initialization AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` Toutes les actions de boutons arrivent dans le callback `flowViewDidPerformAction(view, action)` sous forme de classe scellée `AdaptyUIAction` : `CloseAction`, `AndroidSystemBackAction`, `OpenUrlAction` ou `CustomAction`. :::warning Surcharger `flowViewDidPerformAction` remplace la gestion par défaut de **toutes** les actions, pas uniquement celle qui vous intéresse. Conservez les branches par défaut pour `CloseAction` (fermer le flow) et `OpenUrlAction` (ouvrir l'URL) sauf si vous souhaitez les modifier, comme illustré dans les exemples ci-dessous. ::: ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui fermera votre flow ou votre paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le flow. :::info Dans le SDK Kotlin Multiplatform, `CloseAction` déclenche la fermeture du flow ou du paywall par défaut. Vous pouvez toutefois surcharger ce comportement dans votre code si nécessaire. Par exemple, fermer un flow pourrait déclencher l'ouverture d'un autre. ::: ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } } // Set up the observer AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` Si vous utilisez [`createNativeFlowView`](kmp-present-paywalls#without-compose-multiplatform), appeler `view.dismiss()` n'a aucun effet — la vue est intégrée dans votre layout et non présentée via la pile KMP. Retirez la vue de votre layout et appelez `dispose()` dessus à la place. ## Gérer le bouton retour système Android \{#handle-the-android-system-back-button\} Appuyer sur le bouton retour système Android (ou utiliser le geste retour) émet `AdaptyUIAction.AndroidSystemBackAction`. Par défaut, cette action est ignorée — le flow reste ouvert et l'utilisateur en sort par le chemin que vous définissez, comme un bouton **Close** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même : ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.AndroidSystemBackAction -> mainUiScope.launch { view.dismiss() } // not handled by default is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } } ``` ## Ouvrir des URLs depuis des flows et des paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Conditions d'utilisation** ou **Politique de confidentialité**), dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. Par défaut, le SDK ouvre l'URL reçue de façon native — dans un navigateur externe ou intégré à l'app, selon `action.openIn` — aucun code n'est donc nécessaire. Ne surchargez le gestionnaire que si vous souhaitez une logique personnalisée, par exemple afficher une boîte de dialogue de confirmation au préalable : ```kotlin class MyAdaptyUIFlowsEventsObserver( private val uriHandler: UriHandler ) : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.OpenUrlAction -> { // Show confirmation dialog before opening URL mainUiScope.launch { val selectedAction = view.showDialog( title = "Open URL?", content = action.url, primaryActionTitle = "Cancel", secondaryActionTitle = "Open" ).getOrNull() when (selectedAction) { AdaptyUIDialogActionType.PRIMARY -> { // User cancelled } AdaptyUIDialogActionType.SECONDARY -> { // User confirmed - open URL uriHandler.openUri(action.url) } else -> Unit } } } else -> Unit } } } // Set up the observer with UriHandler AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver(uriHandler)) ``` ## Se connecter à l'app \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre app : 1. Dans le builder, ajoutez un bouton et assignez-lui une action **Custom** avec l'ID "login". 2. Dans le code de votre app, implémentez un gestionnaire pour l'action personnalisée qui identifie votre utilisateur. ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { if (action.action == "login") { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } else -> Unit } } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé. Par exemple, si vous disposez d'un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall : ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { when (action.action) { "openNewFlow" -> { // Display another flow or paywall } } } else -> Unit } } } // Set up the observer AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` </SDKv4> <SDKv3> :::warning **Seuls les achats et les restaurations sont gérés automatiquement.** Toutes les autres actions de boutons, comme la fermeture des paywalls ou l'ouverture de liens, nécessitent une implémentation adaptée dans le code de l'app. ::: Si vous créez des paywalls avec le Adapty paywall builder, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le paywall builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code. ## Configurer l'AdaptyUIPaywallsEventsObserver \{#set-up-the-adaptyuipaywallseventsobserver\} Pour gérer les actions des paywalls, vous devez implémenter l'interface `AdaptyUIPaywallsEventsObserver` et la configurer avec `AdaptyUI.setPaywallsEventsObserver()`. Cette étape doit être effectuée tôt dans le cycle de vie de votre app, généralement dans votre activité principale ou lors de l'initialisation de l'app. ```kotlin // In your app initialization AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui fermera votre paywall : 1. Dans le paywall builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le paywall. :::info Dans le SDK Kotlin Multiplatform, `CloseAction` et `AndroidSystemBackAction` déclenchent la fermeture du paywall par défaut. Vous pouvez toutefois surcharger ce comportement dans votre code si nécessaire. Par exemple, fermer un paywall pourrait déclencher l'ouverture d'un autre. ::: ```kotlin class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { AdaptyUIAction.CloseAction, AdaptyUIAction.AndroidSystemBackAction -> view.dismiss() } } } // Set up the observer AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` Si vous utilisez [`createNativePaywallView`](kmp-present-paywalls#without-compose-multiplatform), appeler `view.dismiss()` n'a aucun effet — la vue est intégrée dans votre layout et non présentée via la pile KMP. Retirez la vue de votre layout et appelez `dispose()` dessus à la place. ## Ouvrir des URLs depuis des paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le paywall builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Conditions d'utilisation** ou **Politique de confidentialité**) : 1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK Kotlin Multiplatform, `OpenUrlAction` fournit l'URL à ouvrir. Vous pouvez implémenter une logique personnalisée pour gérer l'ouverture des URLs, par exemple en affichant une boîte de dialogue de confirmation ou en utilisant la méthode de gestion des URLs préférée de votre app. ::: ```kotlin class MyAdaptyUIPaywallsEventsObserver( private val uriHandler: UriHandler ) : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.OpenUrlAction -> { // Show confirmation dialog before opening URL mainUiScope.launch { val selectedAction = view.showDialog( title = "Open URL?", content = action.url, primaryActionTitle = "Cancel", secondaryActionTitle = "Open" ).getOrNull() when (selectedAction) { AdaptyUIDialogActionType.PRIMARY -> { // User cancelled } AdaptyUIDialogActionType.SECONDARY -> { // User confirmed - open URL uriHandler.openUri(action.url) } else -> Unit } } } } } } // Set up the observer with UriHandler AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver(uriHandler)) ``` ## Se connecter à l'app \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre app : 1. Dans le paywall builder, ajoutez un bouton et assignez-lui une action **Custom** avec l'ID "login". 2. Dans le code de votre app, implémentez un gestionnaire pour l'action personnalisée qui identifie votre utilisateur. ```kotlin class MyAdaptyUIObserver : AdaptyUIObserver { override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { if (action.action == "login") { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } } } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID. 2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé. Par exemple, si vous disposez d'un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre paywall : ```kotlin class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { when (action.action) { "login" -> { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } } } } } // Set up the observer AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` </SDKv3> --- # File: kmp-handling-events --- --- title: "Gérer les événements de flow et de paywall - Kotlin Multiplatform" description: "Gérez les événements de flow et de paywall dans votre application Kotlin Multiplatform." --- <SDKv4> :::important Ce guide couvre la gestion des événements liés aux achats, aux restaurations, à la sélection de produits et au rendu des flows. Vous devez également implémenter la gestion des boutons (fermeture du flow, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de flow](kmp-handle-paywall-actions) pour plus de détails. ::: Les flows et paywalls configurés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-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 pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez comment répondre à ces événements ci-dessous. Pour contrôler ou surveiller les processus qui se déroulent sur l'écran de flow dans votre application mobile, implémentez les méthodes de l'interface `AdaptyUIFlowsEventsObserver` et enregistrez votre observateur avec `AdaptyUI.setFlowsEventsObserver()`. Certaines méthodes ont des implémentations par défaut qui gèrent automatiquement les scénarios courants, donc ne surchargez que les méthodes que vous souhaitez modifier : ```kotlin showLineNumbers title="Kotlin" AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { // override only the methods you want to change }) ``` :::note Ces méthodes sont l'endroit où vous ajoutez votre logique personnalisée pour répondre aux événements de flow. Vous pouvez utiliser `view.dismiss()` pour fermer le flow, ou implémenter tout autre comportement personnalisé dont vous avez besoin. Notez que `dismiss()` est une fonction suspend — à l'intérieur d'un callback, lancez-la sur le `mainUiScope` de l'observateur : `mainUiScope.launch { view.dismiss() }`. ::: ### Événements générés par l'utilisateur \{#user-generated-events\} #### Apparition et disparition du flow \{#flow-appearance-and-disappearance\} Lorsqu'un flow apparaît ou disparaît, ces méthodes seront invoquées : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidAppear(view: AdaptyUIFlowView) { // Handle flow appearance // You can track analytics or update UI here } override fun flowViewDidDisappear(view: AdaptyUIFlowView) { // Handle flow disappearance // You can track analytics or update UI here } ``` :::note - Sur iOS, `flowViewDidAppear` est également invoqué quand un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un flow, et qu'un paywall web s'ouvre dans un navigateur intégré. - Sur iOS, `flowViewDidDisappear` est également invoqué quand un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un flow dans un navigateur intégré disparaît de l'écran. ::: <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```javascript // Flow appeared { // No additional data } // Flow disappeared { // No additional data } ``` </Details> #### Sélection de produit \{#product-selection\} Si un utilisateur sélectionne un produit à acheter, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidSelectProduct(view: AdaptyUIFlowView, productId: String) { // Handle product selection // You can update UI or track analytics here } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> #### Achat démarré \{#started-purchase\} Si un utilisateur initie le processus d'achat, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidStartPurchase(view: AdaptyUIFlowView, product: AdaptyPaywallProduct) { // Handle purchase start // You can show loading indicators or track analytics here } ``` :::note En [mode Observateur](kmp-present-flows-in-observer-mode), les achats démarrés depuis un flow sont transmis à votre `AdaptyUIObserverModeResolver` à la place. ::: <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si un achat se termine, cette méthode sera invoquée. Par défaut, elle ne fait rien — le flow reste ouvert après l'achat jusqu'à ce que vous le fermiez, alors appelez `view.dismiss()` vous-même dès que l'utilisateur obtient l'accès : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { when (purchaseResult) { is AdaptyPurchaseResult.Success -> { // Check if user has access to premium features if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) { mainUiScope.launch { view.dismiss() } } } AdaptyPurchaseResult.Pending -> { // Handle pending purchase (e.g., user will pay offline with cash) } AdaptyPurchaseResult.UserCanceled -> { // Handle user cancellation } } } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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" } } } } } // 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" } } // User canceled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCanceled" } } ``` </Details> Nous recommandons de fermer l'écran du flow en cas d'achat réussi. #### Achat échoué \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `flowViewDidFinishPurchase` avec un résultat annulé à la place, et les paiements en attente ne déclenchent pas cette méthode. ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, error: AdaptyError ) { // Add your purchase failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```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" } } } ``` </Details> #### Restauration démarrée \{#started-restore\} Si un utilisateur initie le processus de restauration, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidStartRestore(view: AdaptyUIFlowView) { // Handle restore start // You can show loading indicators or track analytics here } ``` #### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée. Par défaut, elle ne fait rien — le flow reste ouvert après la restauration jusqu'à ce que vous le fermiez : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishRestore(view: AdaptyUIFlowView, profile: AdaptyProfile) { // Add your successful restore handling logic here // For example: show success message, update UI, or dismiss the flow // Check if user has access to premium features if (profile.accessLevels["premium"]?.isActive == true) { mainUiScope.launch { view.dismiss() } } } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```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" } ] } } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur dispose du `accessLevel` requis. Consultez la rubrique [Statut d'abonnement](subscription-status) pour savoir comment le vérifier. #### Restauration échouée \{#failed-restore\} Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailRestore(view: AdaptyUIFlowView, error: AdaptyError) { // Add your restore failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> #### Fin de la navigation de paiement web \{#web-payment-navigation-completion\} Si un utilisateur initie le processus d'achat via un [paywall web](web-paywall), cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishWebPaymentNavigation( view: AdaptyUIFlowView, product: AdaptyPaywallProduct?, error: AdaptyError? ) { if (error != null) { // Handle web payment navigation error } else { // Handle successful web payment navigation } } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```javascript // Successful web payment 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 web payment navigation { "product": null, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> ### Chargement des données et rendu \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur. Si cette opération échoue, AdaptyUI signalera l'erreur en appelant cette méthode : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailLoadingProducts(view: AdaptyUIFlowView, error: AdaptyError) { // Add your product loading failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> #### Erreurs de rendu et d'exécution \{#rendering-and-runtime-errors\} Si une erreur survient pendant le rendu de l'interface, ou si une autre erreur d'exécution non liée à un achat se produit, elle sera signalée par cette méthode. Par défaut, le flow est fermé en cas d'erreur — surchargez la méthode pour le maintenir ouvert ou ajouter votre propre gestion : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) { // Handle the error // The default implementation dismisses the flow; // once you override this method, dismissal is up to you } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } ``` </Details> Dans une situation normale, de telles erreurs ne devraient pas se produire. Si vous en rencontrez une, merci de nous en informer. #### Événements d'analyse \{#analytics-events\} Le callback `flowViewDidReceiveAnalyticEvent` est réservé aux événements d'analyse personnalisés 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 : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidReceiveAnalyticEvent( view: AdaptyUIFlowView, name: String, paramsJsonString: String ) { // Reserved for custom analytic events from a flow } ``` ### Navigation \{#navigation\} #### Bouton retour système Android \{#android-system-back-button\} Par défaut, un flow ne peut pas être fermé avec le bouton retour système Android ou le geste de retour — l'implémentation par défaut de `flowViewDidPerformAction` ferme le flow uniquement sur `CloseAction` et ignore `AndroidSystemBackAction`, de sorte que l'utilisateur quitte le flow via un chemin que vous définissez, comme un bouton **Fermer** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même : ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.AndroidSystemBackAction -> mainUiScope.launch { view.dismiss() } // not handled by default is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } ``` Consultez le [guide sur la gestion des actions de flow](kmp-handle-paywall-actions) pour la liste complète des actions. </SDKv4> <SDKv3> Les paywalls configurés avec le [Paywall Builder](adapty-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 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 sur le paywall. Découvrez comment répondre à ces événements ci-dessous. :::warning Ce guide est réservé aux paywalls **du nouveau Paywall Builder** uniquement. ::: Pour contrôler ou surveiller les processus qui se déroulent sur l'écran de paywall dans votre application mobile, implémentez les méthodes de l'interface `AdaptyUIPaywallsEventsObserver`. Certaines méthodes ont des implémentations par défaut qui gèrent automatiquement les scénarios courants. :::note Ces méthodes sont l'endroit où vous ajoutez votre logique personnalisée pour répondre aux événements de paywall. Vous pouvez utiliser `view.dismiss()` pour fermer le paywall, ou implémenter tout autre comportement personnalisé dont vous avez besoin. ::: ## Événements générés par l'utilisateur \{#user-generated-events\} ### Apparition et disparition du paywall \{#paywall-appearance-and-disappearance\} Lorsqu'un paywall apparaît ou disparaît, ces méthodes seront invoquées : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidAppear(view: AdaptyUIPaywallView) { // Handle paywall appearance // You can track analytics or update UI here } override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) { // Handle paywall disappearance // You can track analytics or update UI here } ``` :::note - Sur iOS, `paywallViewDidAppear` est également invoqué quand un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré. - Sur iOS, `paywallViewDidDisappear` est également invoqué quand un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. ::: <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```javascript // Paywall appeared { // No additional data } // Paywall disappeared { // No additional data } ``` </Details> ### Sélection de produit \{#product-selection\} Si un utilisateur sélectionne un produit à acheter, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) { // Handle product selection // You can update UI or track analytics here } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> ### Achat démarré \{#started-purchase\} Si un utilisateur initie le processus d'achat, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) { // Handle purchase start // You can show loading indicators or track analytics here } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> ### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si un achat réussit, cette méthode sera invoquée. Par défaut, elle ferme automatiquement le paywall sauf si l'achat a été annulé par l'utilisateur : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishPurchase( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { when (purchaseResult) { is AdaptyPurchaseResult.Success -> { // Check if user has access to premium features if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) { view.dismiss() } } AdaptyPurchaseResult.Pending -> { // Handle pending purchase (e.g., user will pay offline with cash) } AdaptyPurchaseResult.UserCanceled -> { // Handle user cancellation } } } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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" } } } } } // 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" } } // User canceled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCanceled" } } ``` </Details> Nous recommandons de fermer l'écran du paywall en cas d'achat réussi. ### Achat échoué \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `paywallViewDidFinishPurchase` avec un résultat annulé à la place, et les paiements en attente ne déclenchent pas cette méthode. ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailPurchase( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, error: AdaptyError ) { // Add your purchase failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```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" } } } ``` </Details> ### Restauration démarrée \{#started-restore\} Si un utilisateur initie le processus de restauration, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidStartRestore(view: AdaptyUIPaywallView) { // Handle restore start // You can show loading indicators or track analytics here } ``` ### Restauration réussie \{#successful-restore\} Si la restauration d'un achat réussit, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) { // Add your successful restore handling logic here // For example: show success message, update UI, or dismiss paywall // Check if user has access to premium features if (profile.accessLevels["premium"]?.isActive == true) { view.dismiss() } } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```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" } ] } } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur dispose du `accessLevel` requis. Consultez la rubrique [Statut d'abonnement](subscription-status) pour savoir comment le vérifier. ### Restauration échouée \{#failed-restore\} Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your restore failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> ### Fin de la navigation de paiement web \{#web-payment-navigation-completion\} Si un utilisateur initie le processus d'achat via un [paywall web](web-paywall), cette méthode sera invoquée : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishWebPaymentNavigation( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct?, error: AdaptyError? ) { if (error != null) { // Handle web payment navigation error } else { // Handle successful web payment navigation } } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```javascript // Successful web payment 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 web payment navigation { "product": null, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> ## Chargement des données et rendu \{#data-fetching-and-rendering\} ### Erreurs de chargement des produits \{#product-loading-errors\} Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur. Si cette opération échoue, AdaptyUI signalera l'erreur en appelant cette méthode : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your product loading failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> ### Erreurs de rendu \{#rendering-errors\} Si une erreur survient pendant le rendu de l'interface, elle sera signalée par cette méthode : ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) { // Handle rendering error // In a normal situation, such errors should not occur // If you come across one, please let us know } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> Dans une situation normale, de telles erreurs ne devraient pas se produire. Si vous en rencontrez une, merci de nous en informer. </SDKv3> --- # File: kmp-use-fallback-paywalls --- --- title: "Kotlin Multiplatform - Use fallback paywalls" description: "Gérer les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles" --- To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} 1. Ajoutez le fichier de configuration de secours à votre application. * Si votre plateforme cible est Android, déplacez le fichier de configuration de secours dans le dossier `android/app/src/main/assets/`. * Si votre plateforme cible est iOS, ajoutez le fichier JSON de secours au bundle de votre projet. (**File** -> **Add Files to YourProjectName**) 2. Appelez la méthode `.setFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible. 3. Définissez le paramètre `assetId` en fonction de votre plateforme cible. * Android : utilisez le chemin du fichier relatif au répertoire `assets`. * iOS : utilisez le nom de fichier complet. ```kotlin showLineNumbers Adapty.setFallback(assetId = "fallback.json") .onSuccess { // Fallback paywalls loaded successfully } .onError { error -> // Handle the error } ``` :::important `setFallback` doit être exécuté avant que le SDK ne récupère le flow, le paywall ou l'onboarding cible. ::: Paramètres : | Paramètre | Description | | :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **assetId** | Nom du fichier de configuration de secours (iOS). <br /> Chemin du fichier de configuration de secours, relatif au répertoire `assets` (Android). | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: kmp-localizations-and-locale-codes --- --- title: "Utiliser les localisations et les codes de langue dans le SDK Kotlin Multiplatform" description: "Gérez les localisations et les codes de langue de votre application pour toucher un public mondial dans votre app Kotlin Multiplatform." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu lorsqu'Adapty choisit la localisation pour un flow, et lorsque vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet d'anticiper quelle localisation reçoit un utilisateur. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-étiquettes en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de locale \{#locale-code-matching\} Lorsqu'Adapty recherche la localisation correspondant à la locale d'un utilisateur, voici ce qui se passe : 1. La chaîne de locale est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des traits d'union (`-`) 2. Adapty recherche la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier trait d'union (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, Adapty renvoie le contenu dans la locale par défaut du flow Cette approche permet à `'pt_BR'`, `pt-BR` et `pt-br` de tous pointer vers la même localisation. ## Implémentation des localisations \{#implementing-localizations\} Dans le SDK v4, vous ne passez pas de code de langue lors de la récupération d'un flow — `getFlow` renvoie le flow avec l'ensemble de ses localisations. - **Flows créés dans le builder** : `createFlowView` ne prend pas de paramètre de langue, et le SDK ne lit pas la langue de l'appareil. Le flow s'affiche dans sa [langue par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) — sur iOS, en `en` quand le flow a une localisation en anglais. - **Paywalls personnalisés (Remote Config)** : `getFlow` renvoie toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée est un `AdaptyRemoteConfig` avec un code `locale` et un `dataMap`. Sélectionnez l'entrée qui correspond à l'utilisateur, avec votre propre logique de secours : ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() // read your values from config?.dataMap } .onError { error -> // handle the error } ``` Les règles de correspondance des codes de langue décrites ci-dessus expliquent comment Adapty normalise les codes `locale` stockés dans chaque Remote Config. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de locale entrent en jeu dans plusieurs situations — par exemple, lorsque vous souhaitez récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de locale sont complexes et peuvent varier d'une plateforme à l'autre. C'est pourquoi nous nous appuyons sur un standard interne pour toutes les plateformes que nous supportons. Mais justement parce que ces codes sont complexes, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin de toujours recevoir ce que vous attendez. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty reçoit un appel du SDK avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de langue reçue est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`) 2. On recherche ensuite la localisation dont le code de langue correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, on renvoie le contenu dans la langue par défaut du paywall De cette façon, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Mise en œuvre des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous posez des questions sur les localisations, il y a de bonnes chances que vous gériez déjà des ressources de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de ressources. Vous n'aurez alors qu'à extraire la valeur de cette clé lors de l'appel au SDK, comme ceci : ```kotlin showLineNumbers // 1. Add the Adapty locale code to your Compose Multiplatform resources /* composeResources/values/strings.xml (default — English) */ <string name="adapty_paywalls_locale">en</string> /* composeResources/values-es/strings.xml (Spanish) */ <string name="adapty_paywalls_locale">es</string> /* composeResources/values-pt-rBR/strings.xml (Portuguese — Brazil) */ <string name="adapty_paywalls_locale">pt-br</string> // 2. Extract and use the locale code suspend fun fetchPaywall() { val locale = getString(Res.string.adapty_paywalls_locale) Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = locale ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } } ``` De cette façon, vous gardez un contrôle total sur la localisation récupérée pour chaque utilisateur de votre application. Si vous n'utilisez pas les ressources Compose Multiplatform, la même idée s'applique à toute bibliothèque de localisation que vous utilisez (par exemple, [moko-resources](https://github.com/icerockdev/moko-resources)) — stockez le code de locale Adapty sous forme de chaîne dans le bundle de ressources de chaque locale et lisez-le avant d'appeler le SDK. ## Implémenter les localisations : l'autre approche \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de langue pour chaque localisation. Cela revient à extraire un code de langue directement depuis l'appareil — ce qui nécessite des déclarations `expect`/`actual`, puisqu'il n'existe pas d'API de locale partagée dans `commonMain` : ```kotlin showLineNumbers // commonMain expect fun currentLocaleTag(): String // androidMain actual fun currentLocaleTag(): String = Locale.getDefault().toLanguageTag() // iosMain actual fun currentLocaleTag(): String = NSLocale.currentLocale.localeIdentifier // commonMain — pass the locale code to Adapty suspend fun fetchPaywall() { Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = currentLocaleTag() ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } } ``` Notez que nous ne recommandons pas cette approche pour plusieurs raisons : 1. Sur iOS, la langue préférée de l'utilisateur et la langue régionale de l'appareil ne sont pas identiques. `NSLocale.currentLocale.localeIdentifier` renvoie la langue régionale, qui peut différer de la langue dans laquelle les utilisateurs lisent réellement votre application. Les apps iOS qui utilisent des fichiers de chaînes localisées s'appuient sur la logique de résolution d'Apple pour combiner les deux — ce qui fonctionne directement avec l'approche recommandée ci-dessus. 2. Il est difficile de prédire exactement ce que renverra l'appareil et si cela correspond à une localisation Adapty. La langue régionale de l'appareil peut inclure des extensions ou des codes régionaux que vous n'avez pas configurés dans Adapty, auquel cas le SDK revient à la correspondance sur le premier sous-tag ou, en dernier recours, à `en`. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: kmp-web-paywalls --- --- title: "Implémenter des web paywalls dans le SDK Kotlin Multiplatform" description: "Configurez un web paywall pour être payé sans les frais et les audits du store." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre web paywall dans le tableau de bord](web-paywall) et d'avoir installé la version 3.15 ou ultérieure du SDK Adapty. ::: ## Ouvrir des web paywalls \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les web paywalls via la méthode SDK. La méthode `openWebPaywall` : 1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `getProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a été effectué avec succès et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. :::note Après que les utilisateurs reviennent dans l'application, actualisez l'interface pour refléter les mises à jour du profil. Adapty recevra et traitera les événements de mise à jour du profil. ::: ```kotlin showLineNumbers viewModelScope.launch { Adapty.openWebPaywall(product = product).onSuccess { // the web paywall was opened successfully }.onError { error -> // handle the error } } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall(product = product)` qui génère des URL par paywall et ajoute également les données du produit aux URL. 2. `openWebPaywall(paywall = paywall)` qui génère des URL par paywall sans ajouter les données du produit aux URL. Utilisez-la lorsque vos produits dans le paywall Adapty diffèrent de ceux du web paywall. Dans le SDK v4, le paramètre `paywall` est remplacé par un paramètre `flowPaywall` qui prend un `AdaptyFlowPaywall` — l'une des variantes de paywall dans `flow.paywalls`. Consultez le [guide de migration](migration-to-kmp-sdk-v4). ::: ## Ouvrir des web paywalls dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} Par défaut, les web paywalls s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les web paywalls dans un navigateur intégré à l'application. Cela affiche la page d'achat web au sein de votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application. Pour activer cela, définissez le paramètre `openIn` sur `AdaptyWebPresentation.IN_APP_BROWSER` : ```kotlin showLineNumbers viewModelScope.launch { Adapty.openWebPaywall( product = product, openIn = AdaptyWebPresentation.IN_APP_BROWSER // default – EXTERNAL_BROWSER ).onSuccess { // the web paywall was opened successfully }.onError { error -> // handle the error } } ``` --- # File: kmp-present-flows-in-observer-mode --- --- title: "Présenter les flows en mode Observer - Kotlin Multiplatform" description: "Présentez des flows et des paywalls Paywall Builder en mode Observer dans votre application Kotlin Multiplatform tout en gérant les achats avec votre propre code." --- Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez la rubrique [Afficher les flows et paywalls](kmp-present-paywalls). ::: :::info Cette fonctionnalité nécessite le SDK Adapty Kotlin Multiplatform 4.0 (beta) ou une version ultérieure — elle n'était auparavant disponible que dans les SDK natifs iOS et Android. Consultez le [guide de migration](migration-to-kmp-sdk-v4) pour effectuer la mise à niveau. ::: <details> <summary>Avant de commencer à présenter des flows (Cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios) et [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous d'appeler `withObserverMode(true)` dans le builder de configuration. Consultez le [guide d'installation du SDK Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et associez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](kmp-get-pb-paywalls) dans le code de votre application. </details> En mode Observer, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou paywall rendu par Adapty, le SDK appelle votre `AdaptyUIObserverModeResolver` à la place — effectuez l'achat ou la restauration avec votre propre code à cet endroit. 1. Implémentez l'interface `AdaptyUIObserverModeResolver` : ```kotlin showLineNumbers import com.adapty.kmp.AdaptyUIObserverModeResolver import com.adapty.kmp.models.AdaptyPaywallProduct import com.adapty.kmp.models.AdaptyUIFlowView class MyObserverModeResolver : AdaptyUIObserverModeResolver { override fun observerModeDidInitiatePurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, onStartPurchase: () -> Unit, onFinishPurchase: () -> Unit ) { onStartPurchase() // the view shows its loading indicator // make the purchase with your own code, // then report the transaction to Adapty and call: onFinishPurchase() // the view hides the loading indicator } override fun observerModeDidInitiateRestore( view: AdaptyUIFlowView, onStartRestore: () -> Unit, onFinishRestore: () -> Unit ) { onStartRestore() // restore purchases with your own code, then: onFinishRestore() } } ``` La méthode `observerModeDidInitiatePurchase` vous informe que l'utilisateur a initié un achat, et `observerModeDidInitiateRestore` — que l'utilisateur a initié une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse. N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. Cela est nécessaire pour le bon fonctionnement du flow, notamment l'affichage du chargement : | Callback | Description | | :----------------- | :--------------------------------------------------------------------------------------------- | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | Le flow reste ouvert pendant l'exécution de votre code — fermez-le vous-même après un achat ou une restauration réussi. 2. Enregistrez le resolver avant d'afficher un écran : ```kotlin showLineNumbers import com.adapty.kmp.AdaptyUI AdaptyUI.setObserverModeResolver(MyObserverModeResolver()) ``` Sans resolver enregistré, la vue du flow n'a aucun moyen de transmettre l'achat à votre code, et rien ne se passe lorsque l'utilisateur appuie sur le bouton d'achat. 3. Créez et présentez la vue du flow comme d'habitude : [récupérez le flow et créez sa vue](kmp-get-pb-paywalls), puis [présentez-la](kmp-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — une fois le resolver enregistré, chaque flow ou paywall rendu par Adapty achemine les achats et les restaurations à travers lui. :::warning N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-kmp). Sinon, Adapty ne reconnaîtra pas la transaction et ne pourra pas déterminer le paywall source de l'achat. ::: --- # File: kmp-troubleshoot-paywall-builder --- --- title: "Résoudre les problèmes du Paywall Builder dans le SDK Kotlin Multiplatform" description: "Résoudre les problèmes du Paywall Builder dans le SDK Kotlin Multiplatform" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK Kotlin Multiplatform. ## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La méthode `createPaywallView` ne parvient pas à créer une vue de paywall, ou le paywall n'a pas de configuration de vue. **Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. Vous pouvez également vérifier si un paywall possède une configuration de vue en utilisant la propriété `hasViewConfiguration` sur l'objet `AdaptyPaywall`. <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le nombre de vues du paywall affiche le double du nombre attendu. **Cause** : Vous appelez peut-être `logShowFlow` (SDK v4+) / `logShowPaywall` dans votre code, ce qui duplique le nombre de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls créés avec ces outils, les statistiques sont suivies automatiquement, vous n'avez donc pas besoin d'utiliser cette méthode. **Solution** : Assurez-vous de ne pas appeler `logShowFlow` (SDK v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. --- # File: kmp-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement dans le SDK Kotlin Multiplatform" description: "Découvrez comment implémenter les paywalls manuellement dans votre application Kotlin Multiplatform avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty via la méthode `makePurchase`. Ainsi, nous gérons tous les scénarios utilisateur et vous n'avez qu'à traiter les résultats des achats. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Veillez à configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['kmp-quickstart-manual', 'fetch-paywalls-and-products-kmp', 'present-remote-config-paywalls-kmp', 'kmp-making-purchases', 'kmp-restore-purchase', 'kmp-troubleshoot-purchases']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, tout en profitant de l'analytique avancée d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode-kmp', 'report-transactions-observer-mode-kmp', 'kmp-troubleshoot-purchases']} /> --- # File: kmp-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec le SDK Kotlin Multiplatform" description: "Intégrez le SDK Adapty dans vos paywalls Kotlin Multiplatform personnalisés pour activer les achats intégrés." --- Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les précédents. Ce guide utilise les APIs du SDK Adapty Kotlin Multiplatform v4 (bêta) — si vous utilisez la v3, consultez le [guide de migration](migration-to-kmp-sdk-v4) pour les noms de méthodes correspondants. :::important **Ce guide est destiné aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la méthode la plus simple pour activer les achats, utilisez l'[Adapty Flow Builder](kmp-quickstart-paywalls). Avec le Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différentes conceptions sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. Dans le SDK v4, les variations de paywall pour un placement sont portées par un objet **flow** — vous récupérez un flow et interrogez ses produits. - [**Placements**](placements) – où et quand vous affichez des paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez des paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de paywalls différents à différents utilisateurs. Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En résumé, ce sont simplement votre façon de gérer les produits que vous vendez dans votre application. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](kmp-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs. ## Étape 1. Obtenir les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau de produits pour ce flow à l'aide de la méthode `getPaywallProducts`. ```kotlin showLineNumbers fun loadPaywall() { Adapty.getFlow(placementId = "YOUR_PLACEMENT_ID") .onSuccess { flow -> Adapty.getPaywallProducts(flow = flow) .onSuccess { products -> // Use products to build your custom paywall UI } .onError { error -> // Handle the error } } .onError { error -> // Handle the error } } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour. ```kotlin showLineNumbers fun purchaseProduct(product: AdaptyPaywallProduct) { Adapty.makePurchase(product = product) .onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // Purchase successful, profile updated } is AdaptyPurchaseResult.UserCanceled -> { // User canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Purchase is pending (e.g., user will pay offline with cash) } } } .onError { error -> // Handle the error } } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Les stores d'applications exigent que toutes les applications avec des abonnements fournissent un moyen aux utilisateurs de restaurer leurs achats. Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera leur historique d'achats avec Adapty et retournera le profil mis à jour. ```kotlin showLineNumbers fun restorePurchases() { Adapty.restorePurchases() .onSuccess { profile -> // Restore successful, profile updated } .onError { error -> // Handle the error } } ``` ## Étape 4. Vérifier le statut de l'abonnement \{#step-4-check-the-subscription-status\} Après un achat ou une restauration, vérifiez le [niveau d'accès](access-level) de l'utilisateur pour décider d'afficher le paywall ou de débloquer les fonctionnalités payantes. Les méthodes `makePurchase` et `restorePurchases` retournent déjà le profil mis à jour ; lorsque vous avez besoin du statut actuel ailleurs dans l'application, utilisez la méthode `getProfile` : ```kotlin showLineNumbers fun checkPremiumAccess() { Adapty.getProfile() .onSuccess { profile -> val hasPremiumAccess = profile.accessLevels["premium"]?.isActive == true // Grant access to paid features if hasPremiumAccess is true } .onError { error -> // Handle the error } } ``` Pour d'autres façons de vérifier et surveiller le statut de l'abonnement, notamment en écoutant les mises à jour en temps réel, consultez [Vérifier le statut de l'abonnement](kmp-check-subscription-status). ## Prochaines étapes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans le [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez [AppViewModel.kt](https://github.com/adaptyteam/AdaptySDK-KMP/blob/main/example/composeMultiplatformApp/composeApp/src/commonMain/kotlin/com/adapty/exampleapp/AppViewModel.kt) dans notre exemple d'application, qui illustre la gestion des achats avec une gestion des erreurs et une gestion d'état appropriées. --- # File: fetch-paywalls-and-products-kmp --- --- title: "Récupérer les paywalls et produits pour les paywalls Remote Config dans le SDK Kotlin Multiplatform" description: "Récupérez les paywalls et produits dans le SDK Adapty Kotlin Multiplatform pour améliorer la monétisation des utilisateurs." --- <SDKv4> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique porte sur le Remote Config et les paywalls personnalisés. Pour savoir comment récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow ou paywall](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-kotlin-multiplatform) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits cross-platform sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter à des emplacements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) avec la méthode `getFlow`. :::important **Ne codez pas les IDs de produits en dur.** Le seul ID à coder en dur est l'ID de placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un flow renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```kotlin showLineNumbers Adapty.getFlow( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](kmp-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant au cas où le CDN serait inaccessible. Ce système est conçu pour garantir que vous disposez toujours de la dernière version de vos flows et paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en arrière-plan.</p> | Ne codez pas en dur les identifiants de produits ! Étant donné que les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modifications du code. La seule chose que vous devez coder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant : l'identifiant du flow, les variantes de paywall (`paywalls` — chacune avec ses propres identifiants de produits), une liste `remoteConfigs` (une entrée par locale configurée), ainsi que plusieurs autres propriétés. Pour récupérer les produits du flow, appelez `getPaywallProducts(flow)`. | :::note Dans la v4, `getFlow` n'a pas de paramètre `locale`. Lorsque vous affichez un flow avec `createFlowView`, la localisation est résolue automatiquement. Pour les paywalls personnalisés, toutes les localisations disponibles sont retournées ensemble dans `flow.remoteConfigs` — choisissez celle qui correspond à la langue de l'appareil ou aux paramètres de votre application. Consultez [Localisations et codes de langue](kmp-localizations-and-locale-codes) pour plus de détails. ::: ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond : ```kotlin showLineNumbers Adapty.getPaywallProducts(flow).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) contenant : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lorsque vous implémentez votre propre design de flow, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher le prix dans un format localisé, utilisez `product.price.localizedString`. Cette localisation est basée sur la locale de l'appareil. Vous pouvez également accéder au prix sous forme numérique via `product.price.amount`. La valeur est fournie dans la devise locale. Pour obtenir le symbole de devise correspondant, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement de manière programmatique, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, la valeur sera `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre avec cette propriété. Son fonctionnement est identique à celui décrit dans la section précédente pour les abonnements.<br/>• `localizedSubscriptionPeriod` : la période d'abonnement de la remise formatée pour la locale de l'utilisateur. | ## Accélérer la récupération du flow avec un flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous inquiéter de cette étape. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-kmp#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (version actuelle et futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version rencontrent des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon le pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur la méthode `getFlow` décrite [ci-dessus](fetch-paywalls-and-products-kmp#fetch-flow-information). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne bénéficieront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc tout à fait sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau inutiles.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant de présenter les Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que ce sujet concerne les Remote Config et les paywalls personnalisés. Pour obtenir des instructions sur la récupération des paywalls créés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](kmp-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-kotlin-multiplatform) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits cross-platform sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **N'inscrivez pas les IDs de produits en dur dans le code.** Le seul ID à coder en dur est l'ID de placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne bénéficieront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](kmp-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour garantir que vous recevez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan.</p> | Ne codez pas les identifiants de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à coder en dur est l'identifiant de placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) contenant : une liste d'identifiants de produit, l'identifiant du paywall, le Remote Config, et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le paywall, vous pouvez interroger le tableau de produits qui lui correspond : ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) contenant : l'identifiant du produit, son nom, son prix, la devise, la durée de l'abonnement et plusieurs autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil lui-même. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. Cette localisation est basée sur les informations de locale de l'appareil. Vous pouvez aussi accéder au prix sous forme numérique via `product.price.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de la devise associée, utilisez `product.price.currencySymbol`. | | **Subscription Period** | Pour afficher la période (par exemple : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement de manière programmatique, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits sont du type `FREE_TRIAL`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, la valeur sera `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre grâce à cette propriété. Elle fonctionne de la même façon pour les offres que ce qui est décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la locale de l'utilisateur. | ## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls sont récupérés presque instantanément, donc vous n'avez pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de n'afficher aucun paywall. Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme expliqué dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-kmp#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : si vous avez besoin d'afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur la méthode `getPaywall` décrite [plus haut](fetch-paywalls-and-products-kmp#fetch-paywall-information). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` correspond à l'anglais, `pt-br` représente le portugais brésilien.</p><p></p> | | **fetchPolicy** | défaut : `AdaptyPaywallFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser sans risque durant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv3> --- # File: present-remote-config-paywalls-kmp --- --- title: "Afficher un paywall conçu via Remote Config dans le SDK Kotlin Multiplatform" description: "Découvrez comment présenter les paywalls Remote Config dans le SDK Adapty Kotlin Multiplatform pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé. ## Récupérer le Remote Config d'un flow et l'afficher \{#get-flow-remote-config-and-present-it\} Dans la v4, un flow contient une entrée `AdaptyRemoteConfig` par locale configurée dans la liste `remoteConfigs`. Sélectionnez la locale correspondant à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin. ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() val headerText = config?.dataMap?.get("header_text") as? String // use the remote config values } .onError { error -> // handle the error } ``` À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler pour créer une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-kmp#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](kmp-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](kmp-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion Internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos flows et paywalls. Si nous collectons automatiquement les données sur les achats, l'enregistrement des vues nécessite votre intervention, car vous seul savez quand un utilisateur voit un flow. Pour enregistrer un événement de vue, appelez simplement `.logShowFlow(flow)` : il apparaîtra dans vos métriques dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les vues automatiquement dans ces cas. ::: ```kotlin showLineNumbers Adapty.logShowFlow(flow) .onSuccess { // flow view logged successfully } .onError { error -> // handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :-------- |:-----------------------------------------------------------------| | **flow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer le Remote Config d'un paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir le Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires. ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String // use the remote config values }.onError { error -> // handle the error } ``` À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler pour créer une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-kmp#track-paywall-view-events-1) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](kmp-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](kmp-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion Internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events-1\} Adapty vous aide à mesurer les performances de vos paywalls. Si nous collectons automatiquement les données sur les achats, l'enregistrement des vues de paywall nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement de vue de paywall, appelez simplement `.logShowPaywall(paywall)` : il apparaîtra dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```kotlin showLineNumbers Adapty.logShowPaywall(paywall = paywall) .onSuccess { // paywall view logged successfully } .onError { error -> // handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :-------- |:-------------------------------------------------------------------------------------------------------| | **paywall** | requis | Un objet [`AdaptyPaywall`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). | </SDKv3> --- # File: kmp-making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK Kotlin Multiplatform" description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour proposer aux utilisateurs l'accès à des contenus ou services premium. Cependant, les présenter suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour personnaliser vos paywalls. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode distincte appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode constitue le point d'entrée pour que les utilisateurs interagissent avec les paywalls et procèdent à leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de la publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans cela, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez des instructions pas à pas ?** Consultez le [guide de démarrage rapide](kmp-implement-paywalls-manually) pour une implémentation complète avec tout le contexte nécessaire. ::: ```kotlin showLineNumbers Adapty.makePurchase(product = product).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // Grant access to the paid features } } is AdaptyPurchaseResult.UserCanceled -> { // Handle the case where the user canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Handle deferred purchases (e.g., the user will pay offline with cash) } } }.onError { error -> // Handle the error } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------| | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Si la requête a abouti, la réponse contient cet objet. Un objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur au sein de l'application.</p><p>Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose des droits d'accès requis.</p> | :::warning **Remarque :** si vous utilisez encore la version StoreKit d'Apple inférieure à la v2.0 et une version du SDK Adapty inférieure à la v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple. ::: ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur opte pour un nouvel abonnement plutôt que de renouveler son abonnement actuel, le comportement dépend du store. Sur Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer l'abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire : ```kotlin showLineNumbers val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( oldSubVendorProductId = "old_subscription_product_id", replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE ) val purchaseParams = AdaptyPurchaseParameters.Builder() .setSubscriptionUpdateParams(subscriptionUpdateParams) .build() Adapty.makePurchase( product = product, parameters = purchaseParams ).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } }.onError { error -> // Handle the error } ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | |:---------------|:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **parameters** | optionnel | un objet [`AdaptyAndroidSubscriptionUpdateParameters`](https://kmp.adapty.io/////adapty/com.adapty.kmp.models/-adapty-android-subscription-update-parameters/) transmis via [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). | Vous pouvez en savoir plus sur les abonnements et les modes de remplacement dans la documentation Google Developer : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation de l'abonnement actuel. ## Utiliser des codes promotionnels sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie de code dans votre application : ```kotlin showLineNumbers Adapty.presentCodeRedemptionSheet() .onSuccess { // code redemption sheet presented successfully } .onError { error -> // handle the error } ``` :::danger D'après nos observations, la feuille de saisie de code promotionnel peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, vous devez ouvrir une URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ## Gérer les forfaits prépayés (Android) \{#manage-prepaid-plans-android\} Si les utilisateurs de votre application peuvent acheter des [forfaits prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, acheter un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour ces forfaits. ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withGoogleEnablePendingPrepaidPlans(true) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } ``` --- # File: kmp-restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec le SDK Kotlin Multiplatform" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés, comme des abonnements ou des achats intégrés, sans être facturés à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent accéder à leurs achats antérieurs sans payer à nouveau. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.restorePurchases()` : ```kotlin showLineNumbers Adapty.restorePurchases().onSuccess { profile -> if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // successful access restore } }.onError { error -> // handle the error } ``` Paramètres de réponse : | Paramètre | Description | |---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Un objet [`AdaptyProfile`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-profile/). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.</p><p>Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.</p> | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: implement-observer-mode-kmp --- --- title: "Implémenter le mode Observateur dans le SDK Kotlin Multiplatform" description: "Implémentez le mode Observateur dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Kotlin Multiplatform." --- Si vous disposez déjà de votre propre infrastructure d'achats et que vous n'êtes pas prêt à basculer complètement vers Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration fluide avec les systèmes d'attribution et d'analytique. Si cela répond à vos besoins, il vous suffit de : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` à `true`. Suivez les instructions de configuration pour [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform). 2. [Signaler les transactions](report-transactions-observer-mode-kmp) depuis votre infrastructure d'achats existante à Adapty. :::tip Dans la version 4 du SDK, vous pouvez également présenter des flows et des paywalls rendus par Adapty en mode Observateur : lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration, le SDK transmet l'action à votre code afin que vous puissiez effectuer l'achat ou la restauration vous-même. Consultez [Présenter des flows en mode Observateur](kmp-present-flows-in-observer-mode). ::: ## Configuration du mode Observateur \{#observer-mode-setup\} Activez le mode Observateur si vous gérez vous-même les achats et le statut des abonnements, et que vous utilisez Adapty pour envoyer les événements d'abonnement et les données analytiques. :::important En mode Observateur, le SDK Adapty ne fermera aucune transaction — assurez-vous de les gérer de votre côté. ::: ```kotlin showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withObserverMode(true) // default false .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised in observer mode") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | observerMode | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observateur \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observateur. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls avec Remote Config](present-remote-config-paywalls-kmp). 3. [Associez les paywalls](report-transactions-observer-mode-kmp) aux transactions d'achat. --- # File: report-transactions-observer-mode-kmp --- --- title: "Déclarer les transactions en mode Observateur dans le SDK Kotlin Multiplatform" description: "Déclarez les transactions d'achat en mode Observateur d'Adapty pour les insights utilisateurs et le suivi des revenus dans le SDK Kotlin Multiplatform." --- En mode Observateur, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez déclarer les transactions depuis votre store. Il est essentiel de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour déclarer explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas la déclaration des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez les paywalls Adapty, incluez le `variationId` lors de la déclaration d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```kotlin showLineNumbers Adapty.reportTransaction( transactionId = "your_transaction_id", variationId = paywall.variationId ).onSuccess { profile -> // Transaction reported successfully // profile contains updated user data }.onError { error -> // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | --------------- | ---------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | obligatoire | L'identifiant de transaction de votre achat dans le store. Il s'agit généralement du token d'achat ou de l'identifiant de transaction renvoyé par le store. | | variationId | optionnel | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). | --- # File: kmp-troubleshoot-purchases --- --- title: "Résoudre les problèmes d'achats dans le SDK Kotlin Multiplatform" description: "Résoudre les problèmes d'achats dans le SDK Kotlin Multiplatform" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Kotlin Multiplatform. ## makePurchase s'exécute avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et le statut d'abonnement ne sont pas mis à jour dans Adapty. **Cause** : Cela indique généralement une configuration incomplète du Google Play Store ou des problèmes de configuration. **Solution** : Assurez-vous d'avoir complété toutes les [étapes de configuration Google Play](initial-android). ## makePurchase est appelée deux fois \{#makepurchase-is-invoked-twice\} **Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat. **Cause** : Cela se produit généralement lorsque le flow d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur. **Solution** : Assurez-vous d'avoir complété toutes les [étapes de configuration Google Play](initial-android). ## AdaptyError.cantMakePayments en mode observateur \{#adaptyerror-cantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` lors de l'utilisation de `makePurchase` en mode observateur. **Cause** : En mode observateur, vous devez gérer les achats de votre côté, et non utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observateur. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observateur. Consultez [Implémenter le mode observateur](implement-observer-mode-kmp) pour plus de détails. ## Erreur 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\} **Problème** : Vous recevez une erreur de facturation indisponible depuis le Google Play Store. **Cause** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil. **Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui ne peut pas être trouvé. **Cause** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de fin d'achat liés au sandbox. --- # File: kmp-user --- --- title: "Utilisateurs & accès dans le SDK Kotlin Multiplatform" description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application Kotlin Multiplatform avec le SDK Adapty." --- Cette page regroupe tous les guides pour travailler avec les utilisateurs et les niveaux d'accès dans votre application Kotlin Multiplatform. Choisissez le sujet dont vous avez besoin : - **[Identifier les utilisateurs](kmp-identifying-users)** - Apprenez à identifier les utilisateurs dans votre application - **[Mettre à jour les données utilisateur](kmp-setting-user-attributes)** - Définir les attributs utilisateur et les données de profil - **[Écouter les changements de statut d'abonnement](kmp-listen-subscription-changes)** - Surveiller les changements d'abonnement en temps réel - **[Mode Enfants](kids-mode-kmp)** - Implémenter le mode Enfants pour votre application --- # File: kmp-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK Kotlin Multiplatform" description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyé à toutes les intégrations. ### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur au moment de la configuration, passez-le simplement comme paramètre `customerUserId` à la méthode `.activate()` : ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("YOUR_USER_ID") .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } } ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous n'avez pas d'identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'usage les plus courants sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié. ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID").onSuccess { // successful identify }.onError { error -> // handle the error } ``` Paramètres de la requête : - **Customer User ID** (obligatoire) : un identifiant utilisateur sous forme de chaîne de caractères. :::warning Nouvelle soumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces situations, le SDK Adapty bascule automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, comme des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez soumettre à nouveau ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```kotlin showLineNumbers Adapty.logout().onSuccess { // successful logout }.onError { error -> // handle the error } ``` Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`. ## Associer un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`iosAppAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de relier les transactions App Store à l'identité interne de vos utilisateurs. StoreKit associe ce token à chaque transaction, ce qui permet à votre backend de faire correspondre les données App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications App Store restent correctement associés. Vous pouvez définir le token de deux façons : lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `iosAppAccountToken` avec `customerUserId`. Si vous ne passez que le token, il ne sera pas inclus dans la transaction. ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## Définir des identifiants de compte obscurcis (Android) \{#set-obfuscated-account-ids-android\} Google Play exige des identifiants de compte obscurcis dans certains cas d'usage pour renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants aident Google Play à identifier les achats tout en préservant l'anonymat des informations utilisateur, ce qui est particulièrement important pour la prévention des fraudes et l'analyse. Vous aurez peut-être besoin de définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations spécifiques en matière de confidentialité. Les identifiants obscurcis permettent à Google Play de suivre les achats sans exposer les identifiants réels des utilisateurs. :::important Vous devez toujours passer `androidObfuscatedAccountId` avec `customerUserId`. Si vous ne passez que l'identifiant de compte obscurcis, il ne sera pas inclus dans la transaction. ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: kmp-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK Kotlin Multiplatform" description: "Découvrez comment définir les attributs utilisateur dans Adapty pour améliorer la segmentation des audiences." --- Vous pouvez définir des attributs optionnels tels que l'adresse e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` : ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.FEMALE) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) .onSuccess { // profile updated successfully } .onError { error -> // handle the error } ``` Notez que les attributs précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés `<Key>` autorisées de `AdaptyProfileParameters.Builder` et les valeurs `<Value>` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum, les valeurs autorisées sont : `AdaptyProfile.Gender.FEMALE`, `AdaptyProfile.Gender.MALE`, `AdaptyProfile.Gender.OTHER` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés. Ils sont généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblés, et les exploiter dans vos analyses pour identifier quelles métriques produit influencent le plus les revenus. ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withCustomAttribute("key1", "value1") ``` Pour supprimer une clé existante, utilisez la méthode `.withRemovedCustomAttribute()` : ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withRemovedCustomAttribute("key2") ``` Il peut parfois être utile de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut ne pas être à jour, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment. Les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clés peuvent contenir jusqu'à 30 caractères. Ils peuvent inclure des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre à virgule flottante, sans dépasser 50 caractères. --- # File: kmp-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK Kotlin Multiplatform" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Kotlin Multiplatform." --- Avec Adapty, suivre le statut d'abonnement est simple. Vous n'avez pas besoin d'insérer manuellement des identifiants de produits dans votre code. Vous pouvez vérifier le statut d'abonnement d'un utilisateur en contrôlant l'existence d'un [niveau d'accès](access-level) actif. Avant de commencer à vérifier le statut d'abonnement, configurez les [notifications développeur en temps réel (RTDN)](enable-real-time-developer-notifications-rtdn). ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). Nous vous recommandons de récupérer le profil au démarrage de votre application, par exemple lorsque vous [identifiez un utilisateur](android-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour dès qu'une modification survient. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander à chaque fois. Pour être notifié des mises à jour du profil, écoutez les changements de profil comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](android-listen-subscription-changes) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> // check the access }.onError { error -> // handle the error } ``` Paramètres de la réponse : | Paramètre | Description | | --------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile | <p>Un objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.</p><p></p><p>La méthode `.getProfile` fournit le résultat le plus récent car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont renvoyées. Il est également important de noter que le SDK Adapty met à jour le cache `AdaptyProfile` régulièrement, afin de maintenir ces informations aussi à jour que possible.</p> | La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de presse et vendez des abonnements à différents sujets indépendamment, vous pouvez créer des niveaux d'accès « sports » et « science ». Mais la plupart du temps, vous n'aurez besoin que d'un seul niveau d'accès ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès « premium » par défaut. Voici un exemple de vérification du niveau d'accès « premium » par défaut : ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } }.onError { error -> // handle the error } ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir les messages d'Adapty, vous devez effectuer quelques configurations supplémentaires : ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil. Il est toutefois important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier les mises à jour ou modifications liées au profil. Si des modifications sont détectées, comme de nouvelles transactions ou d'autres mises à jour, elles sont transmises aux données en cache afin de les maintenir synchronisées avec le serveur. --- # File: kmp-deal-with-att --- --- title: "Gérer l'ATT dans le SDK Kotlin Multiplatform" description: "Démarrez avec Adapty sur Kotlin Multiplatform pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. ```kotlin showLineNumbers val profileParameters = AdaptyProfileParameters.Builder() .withAttStatus(3) // 3 = ATTrackingManagerAuthorizationStatusAuthorized .build() Adapty.updateProfile(profileParameters) .onSuccess { // ATT status updated successfully } .onError { error -> // handle AdaptyError } ``` :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de transmettre les données en temps voulu aux intégrations que vous avez configurées. ::: --- # File: kids-mode-kmp --- --- title: "Mode Enfants dans le SDK Kotlin Multiplatform" description: "Activez facilement le Mode Enfants pour respecter les politiques Google. Aucune collecte de GAID ou de données publicitaires dans le SDK Kotlin Multiplatform." --- Si votre application Kotlin Multiplatform est destinée aux enfants, vous devez respecter les politiques de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour satisfaire ces politiques et passer les revues des stores. ## Ce qui est requis \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte 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) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `<Prénom.Nom>` sera très probablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'une adresse e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activation du Mode Enfants \{#enabling-kids-mode\} ### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, accédez aux [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, vous devez désactiver la collecte de l'Android Advertising ID (AAID/GAID) et de l'adresse IP lors de l'initialisation du SDK Adapty : ```kotlin showLineNumbers override fun onCreate() { super.onCreate() val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") // highlight-start .withGoogleAdvertisingIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised with privacy settings") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } } ``` --- # File: kmp-onboardings --- --- title: "Onboardings dans le SDK Kotlin Multiplatform" description: "Découvrez comment travailler avec les onboardings dans votre application Kotlin Multiplatform avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une version future.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui offre des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls) et [Afficher des flows et des paywalls](kmp-present-paywalls) pour commencer. ::: <CustomDocCardList /> --- # File: kmp-get-onboardings --- --- title: "Récupérer les onboardings dans le SDK Kotlin Multiplatform" description: "Découvrez comment récupérer les onboardings dans Adapty pour Kotlin Multiplatform." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance à un environnement WebView. Consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls) et [Afficher des flows et des paywalls](kmp-present-paywalls) pour commencer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Kotlin Multiplatform. La première étape consiste à récupérer l'onboarding associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) en version 3.15.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'expérience complète — quel contenu apparaît, comment il est présenté et comment les interactions utilisateur (comme les réponses à des quiz ou les saisies de formulaires) sont traitées. Le conteneur assure également le suivi automatique des événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi des vues séparément. Pour de meilleures performances, récupérez la configuration de l'onboarding suffisamment tôt pour que les images aient le temps de se télécharger avant d'être affichées aux utilisateurs. Pour obtenir un onboarding, utilisez la méthode `getOnboarding` : ```kotlin showLineNumbers Adapty.getOnboarding( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.<p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tentera de charger les données depuis le serveur et retournera les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser durant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé qu'à la réinstallation de l'application ou lors d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en interne.</p> | Paramètres de la réponse : | Paramètre | Description | |:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-onboarding/) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. | ## Accélérer la récupération des onboardings avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un onboarding par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer l'onboarding via la méthode `getOnboarding`, comme détaillé dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des problèmes lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions puissent s'afficher incorrectement. - **Pas de personnalisation** : affiche uniquement le contenu pour l'audience « All Users », sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si une récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```kotlin showLineNumbers Adapty.getOnboardingForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.<br/>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tentera de charger les données depuis le serveur et retournera les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser durant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé qu'à la réinstallation de l'application ou lors d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | --- # File: kmp-present-onboardings --- --- title: "Présenter les onboardings dans le SDK Kotlin Multiplatform" description: "Découvrez comment présenter efficacement les onboardings pour augmenter vos conversions." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows & paywalls](kmp-get-pb-paywalls) et [Afficher des flows & paywalls](kmp-present-paywalls) pour commencer. ::: Si vous avez personnalisé un onboarding via le builder, vous n'avez pas besoin de vous soucier de son rendu dans le code de votre application Kotlin Multiplatform pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et comment cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) 3.16.1 ou une version ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Le SDK Adapty Kotlin Multiplatform offre deux façons de présenter les onboardings : - **Avec Compose Multiplatform** - **Sans Compose Multiplatform** ## Avec Compose Multiplatform \{#with-compose-multiplatform\} Pour afficher un onboarding, utilisez la méthode `view.present()` sur la `view` créée par la méthode `createOnboardingView`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher l'onboarding à nouveau, appelez `createOnboardingView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut entraîner une erreur. ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createOnboardingView(onboarding = onboarding).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`. ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createOnboardingView(onboarding = onboarding).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ### Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web directement dans votre application, permettant aux utilisateurs de les consulter sans changer d'app. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `AdaptyWebPresentation.EXTERNAL_BROWSER` : ```kotlin showLineNumbers viewModelScope.launch { AdaptyUI.createOnboardingView( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.EXTERNAL_BROWSER // default – IN_APP_BROWSER ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ## Sans Compose Multiplatform \{#without-compose-multiplatform\} :::note `createNativeOnboardingView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`. ::: Pour intégrer un onboarding sans Compose Multiplatform, appelez `createNativeOnboardingView`. Cette méthode retourne un `AdaptyNativeOnboardingView` que vous ajoutez à votre layout : <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativeOnboardingView( context = context, viewModelStoreOwner = activity, onboarding = onboarding, observer = myOnboardingObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` </TabItem> <TabItem value="ios" label="iOS"> Les méthodes par défaut de l'interface KMP devenant `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIOnboardingsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` : ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BaseOnboardingObserver : AdaptyUIOnboardingsEventsObserver ``` Puis sous-classez-la en Swift, en ne redéfinissant que ce dont vous avez besoin : ```swift showLineNumbers title="Swift" class MyOnboardingObserver: BaseOnboardingObserver { override func onboardingViewOnCloseAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // remove nativeView from your view hierarchy } } let nativeView = AdaptyUI.shared.createNativeOnboardingView( onboarding: onboarding, observer: MyOnboardingObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### Supprimer la vue \{#dispose-the-view\} Appelez `dispose()` lors de la suppression de la vue de votre layout. Cela désenregistre le listener d'événements et libère les ressources internes. ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` --- # File: kmp-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK Kotlin Multiplatform" description: "Gérez les événements liés à l'onboarding dans Kotlin Multiplatform avec Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une future version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Récupérer les flows et paywalls](kmp-get-pb-paywalls) et [Afficher les flows et paywalls](kmp-present-paywalls) pour commencer. ::: Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) 3.15.0 ou une version ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Découvrez comment y répondre ci-dessous. ## Configurer l'observateur d'événements d'onboarding \{#set-up-the-onboarding-event-observer\} Pour gérer les événements d'onboarding, vous devez implémenter l'interface `AdaptyUIOnboardingsEventsObserver` et la configurer via `AdaptyUI.setOnboardingsEventsObserver()`. Cette opération doit être effectuée tôt dans le cycle de vie de votre application, généralement dans votre activité principale ou lors de l'initialisation de l'application. ```kotlin // In your app initialization AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` ## Actions personnalisées \{#custom-actions\} Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un identifiant. Vous pouvez ensuite utiliser cet identifiant dans votre code et le traiter comme une action personnalisée. <img src={require('./img/ios-events-1.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Par exemple, si un utilisateur appuie sur un bouton personnalisé comme **Login** ou **Allow notifications**, la méthode déléguée `onCustomAction` sera déclenchée avec l'identifiant d'action défini dans le builder. Vous pouvez créer vos propres identifiants, par exemple « allowNotifications ». ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnCustomAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { when (actionId) { "openPaywall" -> { // Display paywall from onboarding // You would typically fetch and present a new paywall here mainUiScope.launch { // Example: Get paywall by placement ID // val paywallResult = Adapty.getPaywall("your_placement_id") // paywallResult.onSuccess { paywall -> // val paywallViewResult = AdaptyUI.createPaywallView(paywall) // paywallViewResult.onSuccess { paywallView -> // paywallView.present() // } // } } } "allowNotifications" -> { // Handle notification permissions } else -> { // Handle other custom actions } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton avec l'action **Close** assignée. Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple : :::important Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter l'affichage de l'onboarding lui-même. ::: Si vous utilisez [`createNativeOnboardingView`](kmp-present-onboardings#without-compose-multiplatform), `view.isStandaloneView` est `false` — l'implémentation par défaut n'appelle pas `view.dismiss()`. Retirez la vue de votre layout et appelez `dispose()` sur elle dans ce callback à la place. ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnCloseAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // Dismiss the onboarding screen mainUiScope.launch { view.dismiss() } // Additional cleanup or navigation logic can be added here // For example, navigate back or show main app content } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall à l'intérieur de l'onboarding. Si vous souhaitez ouvrir un paywall après la fermeture de l'onboarding, il existe une approche plus directe — gérez [`onboardingViewOnCloseAction`](#closing-onboarding) et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La façon la plus simple de travailler avec les paywalls dans les onboardings est de définir l'identifiant d'action égal à l'identifiant de placement du paywall. Ainsi, vous pouvez utiliser l'identifiant de placement pour récupérer et ouvrir le paywall directement : ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnPaywallAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // Get the paywall using the placement ID from the action mainUiScope.launch { val paywallResult = Adapty.getPaywall(placementId = actionId) paywallResult.onSuccess { paywall -> val paywallViewResult = AdaptyUI.createPaywallView(paywall) paywallViewResult.onSuccess { paywallView -> paywallView.present() }.onError { error -> // handle the error } }.onError { error -> // handle the error } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Lorsqu'un onboarding finit de se charger, cette méthode est invoquée : ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewDidFinishLoading( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta ) { // Handle loading completion // You can add any initialization logic here } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## Événements de navigation \{#navigation-events\} La méthode `onboardingViewOnAnalyticsEvent` est appelée lors de divers événements analytiques survenant pendant le flow d'onboarding. L'objet `event` peut être de l'un des types suivants : |Type | Description | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | Lorsque l'onboarding a été chargé | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | Lorsqu'un écran est affiché | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque l'utilisateur effectue une action pour quitter l'écran. | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | Lorsque le deuxième écran est affiché | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | Déclenché lorsque l'adresse e-mail de l'utilisateur est collectée via le champ de saisie | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'identifiant `final`. Si vous avez besoin de cet événement, attribuez l'identifiant `final` au dernier écran. | | `AdaptyOnboardingsAnalyticsEventUnknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `screensTotal` | Nombre total d'écrans dans le flow | Voici un exemple d'utilisation des événements analytiques pour le suivi : ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnAnalyticsEvent( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, event: AdaptyOnboardingsAnalyticsEvent ) { when (event) { is AdaptyOnboardingsAnalyticsEventOnboardingStarted -> { // Track onboarding start trackEvent("onboarding_started", event.meta) } is AdaptyOnboardingsAnalyticsEventScreenPresented -> { // Track screen presentation trackEvent("screen_presented", event.meta) } is AdaptyOnboardingsAnalyticsEventScreenCompleted -> { // Track screen completion with user response trackEvent("screen_completed", event.meta, event.elementId, event.reply) } is AdaptyOnboardingsAnalyticsEventOnboardingCompleted -> { // Track successful onboarding completion trackEvent("onboarding_completed", event.meta) } is AdaptyOnboardingsAnalyticsEventUnknown -> { // Handle unknown events trackEvent(event.name, event.meta) } // Handle other cases as needed } } private fun trackEvent(eventName: String, meta: AdaptyUIOnboardingMeta, elementId: String? = null, reply: String? = null) { // Implement your analytics tracking here // For example, send to your analytics service } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemples d'événements (cliquer pour développer)</summary> ```javascript // OnboardingStarted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "welcome_screen", "screenIndex": 0, "screensTotal": 4 } } // ScreenPresented { "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 4 } } // ScreenCompleted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 }, "elementId": "profile_form", "reply": "success" } // SecondScreenPresented { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 } } // UserEmailCollected { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 } } // OnboardingCompleted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "final_screen", "screenIndex": 3, "screensTotal": 4 } } ``` </Details> --- # File: kmp-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK Kotlin Multiplatform" description: "Enregistrez et utilisez les données des onboardings dans votre application Kotlin Multiplatform avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Obtenir des flows & paywalls](kmp-get-pb-paywalls) et [Afficher des flows & paywalls](kmp-present-paywalls) pour commencer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onboardingViewOnStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Store user preferences or responses when (params) { is AdaptyOnboardingsSelectParams -> { // Handle single selection val id = params.id val value = params.value val label = params.label AppLogger.d("Selected option: $label (id: $id, value: $value)") } is AdaptyOnboardingsMultiSelectParams -> { // Handle multiple selections } is AdaptyOnboardingsInputParams -> { // Handle text input } is AdaptyOnboardingsDatePickerParams -> { // Handle date selection } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>Exemples de données enregistrées (le format peut différer dans votre implémentation)</summary> ```javascript // Example of a saved select action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "preferences_screen", "screen_index": 1, "total_screens": 3 }, "action": { "element_id": "preference_selector", "element_type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 3 }, "action": { "element_id": "interests_selector", "element_type": "multi_select", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 0, "total_screens": 3 }, "action": { "element_id": "name_input", "element_type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 0, "total_screens": 3 }, "action": { "element_id": "birthday_picker", "element_type": "date_picker", "value": { "day": 15, "month": 6, "year": 1990 } } } ``` </Details> ## Cas d'utilisation \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois la même information, vous devez [mettre à jour le profil utilisateur](kmp-setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci : ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Store user preferences or responses when (params) { is AdaptyOnboardingsInputParams -> { // Handle text input val builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field when (elementId) { "name" -> { when (val input = params.input) { is AdaptyOnboardingsTextInput -> { builder.withFirstName(input.value) } } } "email" -> { when (val input = params.input) { is AdaptyOnboardingsEmailInput -> { builder.withEmail(input.value) } } } } // Update profile asynchronously mainUiScope.launch { val profileParams = builder.build() val result = Adapty.updateProfile(profileParams) result.onSuccess { profile -> // Profile updated successfully AppLogger.d("Profile updated: ${profile.email}") }.onError { error -> // Handle the error AppLogger.e("Failed to update profile: ${error.message}") } } } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` ### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\} En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls que vous affichez aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le générateur d'onboarding et attribuez des IDs significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](kmp-setting-user-attributes) pour les utilisateurs. ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Handle quiz responses and set custom attributes when (params) { is AdaptyOnboardingsSelectParams -> { // Handle quiz selection val builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes when (elementId) { "experience" -> { // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.withCustomAttribute("experience", params.value) } } // Update profile asynchronously mainUiScope.launch { val profileParams = builder.build() val result = Adapty.updateProfile(profileParams) result.onSuccess { profile -> // Profile updated successfully AppLogger.d("Custom attribute 'experience' set to: ${params.value}") }.onError { error -> // Handle the error AppLogger.e("Failed to update profile: ${error.message}") } } } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](kmp-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](kmp-handling-onboarding-events#opening-a-paywall). --- # File: kmp-best-practices --- --- title: "Meilleures pratiques avec le SDK Kotlin Multiplatform" description: "Modèles de référence pour intégrer le SDK Adapty sur Kotlin Multiplatform — ordre d'appel, gestion des erreurs et autres règles pour une utilisation en production." --- <CustomDocCardList /> --- # File: kmp-sdk-call-order --- --- title: "Ordre d'appel dans le SDK Kotlin Multiplatform" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs d'activation intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre." --- `Adapty.activate()` doit se terminer avant tout autre appel de méthode du SDK Adapty. Tant qu'il n'est pas terminé, le SDK n'a aucun état. Tout appel émis avant ou en parallèle d'`activate()` échoue avec une erreur d'activation. Voir [Gestion des erreurs dans le SDK Kotlin Multiplatform](kmp-handle-errors). Si votre application authentifie les utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty.identify()` à ce moment-là. N'appelez pas les méthodes liées aux actions utilisateur tant qu'`identify` n'est pas terminé. Les appels qui entrent en concurrence avec lui renvoient soit une erreur, soit atterrissent sur le profil anonyme créé lors de l'activation. Dans ce cas, l'attribution, les identifiants MMP comme `appsflyer_id` et la propriété d'installation ne sont pas toujours transférés au profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré au profil identifié. Pour les spécificités d'AppsFlyer, voir [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre chemin dépend de deux choses : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou analytics. - **Étapes 2 et 5** : Obligatoires pour toutes les applications. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou analytics (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et récupère l'identifiant utilisateur client après le lancement. Si vous avez l'identifiant utilisateur client au lancement de l'application, passez-le dans `AdaptyConfig.Builder` avant d'appeler `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, l'étape 4 est donc inutile. | Étape | Appel | Quand | Remarques | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou analytics (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'application, en premier | Attendez le callback d'UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | Lancement de l'application, après l'étape 1, si vous avez l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").build())` sans `withCustomerUserId` | Lancement de l'application, après l'étape 1, si vous n'avez pas l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` pour chaque MMP | Après l'étape 2, avant tout appel d'action utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. | | 4 | `Adapty.identify("YOUR_USER_ID").onSuccess { ... }.onError { ... }` | Après l'étape 3 (ou l'étape 2 sans MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Attendez `onSuccess` avant tout appel d'action utilisateur. Les appels concurrents pendant `identify` peuvent atterrir sur le profil anonyme. | | 5 | `getPaywall` (`getFlow` dans SDK v4), `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 sans MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne la perte d'accès premium pour les utilisateurs existants, l'absence d'`appsflyer_id` sur les profils, et des paywalls renvoyés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent via un paiement web (Stripe, Paddle) puis installent l'application native, le premier `activate()` sur l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flux d'authentification ou le referrer d'installation), passez-le directement dans `AdaptyConfig.Builder`. Sinon, l'achat web est invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque paiement web, voir : - [Stripe](stripe) - [Paddle](paddle) --- # File: kmp-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK Kotlin Multiplatform" description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour Kotlin Multiplatform." --- Une récupération fiable de paywall sur Kotlin Multiplatform repose sur trois points : un affichage rapide, le retour du paywall ciblé par audience, et un repli gracieux en cas de réseau lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir. :::tip Ces règles supposent que `Adapty.activate()` et `Adapty.identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK Kotlin Multiplatform](kmp-sdk-call-order). ::: Les conseils ci-dessous utilisent les noms de méthodes de la v3. Dans le SDK v4, `getPaywall` est renommé en `getFlow` (voir le [guide de migration](migration-to-kmp-sdk-v4)) — chaque règle s'applique sans changement. ## Règles et pièges \{#rules-and-pitfalls\} | À faire | À éviter | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements simultanément au démarrage. | Le pré-chargement en masse bloque le thread principal et provoque un écran noir pendant la rafale. | | Appelez `getPaywall` une fois que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `setOnProfileUpdatedListener`. | Appeler `getPaywall` au démarrage de l'application. | L'attribution n'est pas encore arrivée. Le paywall se résout sur l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment sur `getPaywall`. | Sans délai d'expiration, les utilisateurs avec une mauvaise connectivité voient un écran blanc jusqu'à ce que le réseau réponde — ou ferment l'application. | Voir [Récupérer les paywalls et les produits](fetch-paywalls-and-products-kmp) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour une mauvaise connectivité \{#tune-for-poor-connectivity\} Pour les marchés avec une connectivité constamment faible (zones rurales, transports, régions affectées par le routage) : - Définissez `fetchPolicy = AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` sur chaque récupération sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le délai expire. - Ne conditionnez pas l'affichage du paywall à `Adapty.getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: kmp-test --- --- title: "Test & release in Kotlin Multiplatform SDK" description: "Apprenez à vérifier le statut d'abonnement dans votre application Kotlin Multiplatform avec Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application Kotlin Multiplatform, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox. ## Tester votre application \{#test-your-app\} Pour tester en profondeur vos achats intégrés, consultez nos guides de test spécifiques à chaque plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android). ## Se préparer pour la mise en production \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [liste de contrôle de mise en production](release-checklist) pour confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats sont effectués et remontés à Adapty - L'accès se déverrouille et se restaure correctement - Les exigences en matière de confidentialité et de révision sont respectées --- # File: kmp-reference --- --- title: "Référence pour le SDK Kotlin Multiplatform" description: "Documentation de référence pour le SDK Adapty Kotlin Multiplatform." --- Cette page contient la documentation de référence pour le SDK Adapty Kotlin Multiplatform. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://kmp.adapty.io/adapty/)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](kmp-handle-errors)** - Gestion des erreurs et résolution des problèmes --- # File: kmp-handle-errors --- --- title: "Gérer les erreurs dans le SDK Kotlin Multiplatform" description: "Découvrez comment gérer les erreurs dans votre application Kotlin Multiplatform avec Adapty." --- Cette page couvre la gestion des erreurs dans le SDK Adapty Kotlin Multiplatform. ## Bases de la gestion des erreurs \{#error-handling-basics\} Toutes les méthodes du SDK Adapty renvoient des résultats qui peuvent être soit un succès, soit une erreur. Gérez toujours les deux cas : <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // Handle success } is AdaptyResult.Error -> { val error = result.error // Handle error Log.e("Adapty", "Error: ${error.message}") } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // Handle success } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle error Log.e("Adapty", "Error: " + error.getMessage()); } }); ``` </TabItem> </Tabs> ## Codes d'erreur courants \{#common-error-codes\} | Code d'erreur | Description | Solution | |---------------|-------------|----------| | 1000 | Aucun identifiant de produit trouvé | Vérifiez la configuration des produits dans le tableau de bord | | 1001 | Erreur réseau | Vérifiez la connexion internet | | 1002 | Clé SDK invalide | Vérifiez votre clé SDK | | 1003 | Impossible d'effectuer des paiements | L'appareil ne prend pas en charge les paiements | | 1004 | Produit non disponible | Produit non configuré dans le store | ## Gérer des erreurs spécifiques \{#handle-specific-errors\} ### Erreurs réseau \{#network-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.getPaywall("main") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Use paywall } is AdaptyResult.Error -> { val error = result.error when (error.code) { 1001 -> { // Network error - show offline message showOfflineMessage() } else -> { // Other errors showErrorMessage(error.message) } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.getPaywall("main", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); // Use paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); switch (error.getCode()) { case 1001: // Network error - show offline message showOfflineMessage(); break; default: // Other errors showErrorMessage(error.getMessage()); break; } } }); ``` </TabItem> </Tabs> ### Erreurs d'achat \{#purchase-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers product.makePurchase { result -> when (result) { is AdaptyResult.Success -> { val purchase = result.value // Purchase successful showSuccessMessage() } is AdaptyResult.Error -> { val error = result.error when (error.code) { 1003 -> { // Can't make payments showPaymentNotAvailableMessage() } 1004 -> { // Product not available showProductNotAvailableMessage() } else -> { // Other purchase errors showPurchaseErrorMessage(error.message) } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers product.makePurchase(result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchase purchase = ((AdaptyResult.Success<AdaptyPurchase>) result).getValue(); // Purchase successful showSuccessMessage(); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); switch (error.getCode()) { case 1003: // Can't make payments showPaymentNotAvailableMessage(); break; case 1004: // Product not available showProductNotAvailableMessage(); break; default: // Other purchase errors showPurchaseErrorMessage(error.getMessage()); break; } } }); ``` </TabItem> </Tabs> ## Stratégies de récupération après erreur \{#error-recovery-strategies\} ### Réessayer en cas d'erreur réseau \{#retry-on-network-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers fun getPaywallWithRetry(placementId: String, maxRetries: Int = 3) { var retryCount = 0 fun attemptGetPaywall() { Adapty.getPaywall(placementId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Use paywall } is AdaptyResult.Error -> { val error = result.error if (error.code == 1001 && retryCount < maxRetries) { // Network error - retry retryCount++ Handler(Looper.getMainLooper()).postDelayed({ attemptGetPaywall() }, 1000 * retryCount) // Exponential backoff } else { // Max retries reached or other error showErrorMessage(error.message) } } } } } attemptGetPaywall() } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers public void getPaywallWithRetry(String placementId, int maxRetries) { AtomicInteger retryCount = new AtomicInteger(0); Runnable attemptGetPaywall = new Runnable() { @Override public void run() { Adapty.getPaywall(placementId, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); // Use paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); if (error.getCode() == 1001 && retryCount.get() < maxRetries) { // Network error - retry retryCount.incrementAndGet(); new Handler(Looper.getMainLooper()).postDelayed(this, 1000 * retryCount.get()); } else { // Max retries reached or other error showErrorMessage(error.getMessage()); } } }); } }; attemptGetPaywall.run(); } ``` </TabItem> </Tabs> ### Utiliser les données en cache en secours \{#fallback-to-cached-data\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers class PaywallManager { private var cachedPaywall: AdaptyPaywall? = null fun getPaywall(placementId: String) { Adapty.getPaywall(placementId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value cachedPaywall = paywall showPaywall(paywall) } is AdaptyResult.Error -> { val error = result.error if (error.code == 1001 && cachedPaywall != null) { // Network error - use cached paywall showPaywall(cachedPaywall!!) showOfflineIndicator() } else { // No cache available or other error showErrorMessage(error.message) } } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers public class PaywallManager { private AdaptyPaywall cachedPaywall; public void getPaywall(String placementId) { Adapty.getPaywall(placementId, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); cachedPaywall = paywall; showPaywall(paywall); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); if (error.getCode() == 1001 && cachedPaywall != null) { // Network error - use cached paywall showPaywall(cachedPaywall); showOfflineIndicator(); } else { // No cache available or other error showErrorMessage(error.getMessage()); } } }); } } ``` </TabItem> </Tabs> ## Étapes suivantes \{#next-steps\} - [Correction de l'erreur Code-1000 noProductIDsFound](InvalidProductIdentifiers-kmp) - [Correction de l'erreur Code-1003 cantMakePayments](cantMakePayments-kmp) - [Référence complète de l'API](https://android.adapty.io) - Documentation complète du SDK --- # File: InvalidProductIdentifiers-kmp --- --- title: "Correction de l'erreur Code-1000 noProductIDsFound dans le SDK Kotlin Multiplatform" description: "Résolvez les erreurs d'identifiants de produit invalides lors de la gestion des abonnements dans Adapty." --- L'erreur avec le code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont bien répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, vous pouvez l'ignorer. Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre : ## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\} 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Vérifier les produits \{#step-3-check-products\} 1. Rendez-vous dans **App Store Connect** et accédez à [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. Vos produits s'affichent dans la section **Subscriptions**. 3. Assurez-vous que le produit que vous testez est marqué **Ready to Submit**. Si ce n'est pas le cas, suivez les instructions de la page [Produit dans l'App Store](app-store-products). <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Comparez l'identifiant du produit dans le tableau avec celui de l'onglet [**Products**](https://app.adapty.io/products) dans l'Adapty Dashboard. Si les identifiants ne correspondent pas, copiez l'identifiant du produit depuis le tableau et [créez un produit](create-product) avec cet identifiant dans l'Adapty Dashboard. <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3. Vérifier la disponibilité du produit \{#step-4-check-product-availability\} 1. Retournez dans **App Store Connect** et ouvrez la même section **Subscriptions**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis y figurent. <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. Retournez dans la section **Monetization** → **Subscriptions** d'**App Store Connect**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à **Subscription Pricing** et développez la section **Current Pricing for New Subscribers**. <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Vérifiez que tous les prix requis sont bien listés. <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Vérifier le statut de paiement de l'app, le compte bancaire et les formulaires fiscaux \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. Sur la page d'accueil d'[**App Store Connect**](https://appstoreconnect.apple.com/), cliquez sur **Business**. <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez le nom de votre entreprise. <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Faites défiler vers le bas et vérifiez que votre **Paid Apps Agreement**, votre **Bank Account** et vos **Tax forms** affichent tous le statut **Active**. <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En suivant ces étapes, vous devriez pouvoir résoudre l'avertissement `InvalidProductIdentifiers` et mettre vos produits en ligne dans le store. ## Étape 6. Recréer le produit s'il est bloqué \{#step-6-recreate-the-product-if-its-stuck\} Les étapes 1 à 5 peuvent toutes être validées — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK continue de renvoyer `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre de produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit. Supprimez le produit dans App Store Connect et recréez-le avec le même identifiant de produit. Attendez jusqu'à 24 heures après la recréation pour que la propagation s'effectue. --- # File: cantMakePayments-kmp --- --- title: "Correction de l'erreur Code-1003 cantMakePayment dans le SDK Kotlin Multiplatform" description: "Résolvez l'erreur de paiement lors de la gestion des abonnements dans Adapty." --- L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil. Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes : - Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous. - Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous. ## Problème : Restrictions de l'appareil \{#issue-device-restrictions\} | Problème | Solution | |--------------------------------|-------------------------------------------------------------------------------------------------------------| | Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) | | Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte | | Restrictions régionales | Utilisez un compte App Store d'une région prise en charge | ## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\} Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat. Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK. --- # File: kmp-sdk-migration-guides --- --- title: "Guides de migration du SDK Kotlin Multiplatform" description: "Guides de migration pour les versions du SDK Adapty Kotlin Multiplatform." --- Cette page contient tous les guides de migration pour le SDK Adapty Kotlin Multiplatform. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées : - **[Migrer vers la v4.0 (beta)](migration-to-kmp-sdk-v4)** - **[Migrer vers la v3.15](migration-to-kmp-315)** --- # File: migration-to-kmp-sdk-v4 --- --- title: "Migrer le SDK Adapty Kotlin Multiplatform vers la v. 4.0" description: "Migrez vers le SDK Adapty Kotlin Multiplatform v4.0 (beta) en remplaçant les API de paywall par des API de flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK Adapty Kotlin Multiplatform 4.0 (beta) introduit les flows et renomme les API de paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` | | `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` | | `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` | | `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` | | `AdaptyPaywall` | `AdaptyFlow` | | `AdaptyUI.createPaywallView(paywall, ...)` | `AdaptyUI.createFlowView(flow, ...)` | | `AdaptyUI.createNativePaywallView(...)` → `AdaptyNativePaywallView` | `AdaptyUI.createNativeFlowView(...)` → `AdaptyNativeFlowView` | | `AdaptyUIPaywallView` | `AdaptyUIFlowView` | | `AdaptyUI.presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI.presentFlowView(view)` / `dismissFlowView(view)` | | `AdaptyUI.setPaywallsEventsObserver(observer)` | `AdaptyUI.setFlowsEventsObserver(observer)` | | `AdaptyUI.registerPaywallEventsListener` / `unregisterPaywallEventsListener` | `AdaptyUI.registerFlowEventsListener` / `unregisterFlowEventsListener` | | `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` | | `AdaptyUIPaywallPlatformView(paywall, ...)` | `AdaptyUIFlowPlatformView(flow, ...)` | | `paywallViewDidPerformAction`, `paywallViewDidAppear` et autres callbacks `paywallView...` | `flowViewDidPerformAction`, `flowViewDidAppear` et autres callbacks `flowView...` | | `paywallViewDidFailRendering` | `flowViewDidReceiveError` | `AdaptyPaywallProduct` conserve son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` conserve également son nom, en prenant désormais un `AdaptyFlow`. Les méthodes `getFlow` et `getFlowForDefaultAudience` ne prennent plus de paramètre `locale`. Les API d'achat et de profil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) ainsi que `setFallback` conservent les mêmes signatures, mais le fichier de secours lui-même doit être retéléchargé — voir [Fichiers de secours](#fallback-files). Les méthodes d'onboarding fonctionnent toujours mais sont dépréciées — voir [Dépréciation de l'API d'onboarding](#onboarding-api-deprecation). Certains comportements par défaut ont changé — voir [Changements de comportement par défaut](#default-behavior-changes). ## Installation \{#installation\} La v4.0 est une version préliminaire, donc épinglez la version exacte — Gradle ne sélectionne pas les versions préliminaires via les plages dynamiques : ```toml showLineNumbers title="libs.versions.toml" [versions] adapty-kmp = "4.0.0-beta.1" [libraries] adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" } adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" } ``` Le module `adapty-kmp-ui` n'est nécessaire que si vous affichez des flows et des paywalls avec la couche Compose Multiplatform (`view.present()`). Consultez [Installer le SDK Adapty](sdk-installation-kotlin-multiplatform) pour la configuration complète. Les SDK natifs Adapty sous-jacents sont mis à jour vers leurs versions 4.x sur les deux plateformes et sont résolus automatiquement — aucune modification de build n'est nécessaire. La cible de déploiement iOS reste **15.0**, inchangée dans cette version. ## Récupération des flows \{#fetching-flows\} ### getPaywall → getFlow Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et le paramètre `locale` est supprimé — lorsque vous affichez un flow, la locale est résolue automatiquement ; pour les paywalls personnalisés, toutes les locales sont retournées dans `flow.remoteConfigs` : ```diff showLineNumbers - Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") - .onSuccess { paywall -> - // use the paywall + Adapty.getFlow("YOUR_PLACEMENT_ID") + .onSuccess { flow -> + // use the flow } .onError { error -> // handle the error } ``` `getPaywallForDefaultAudience` est renommé de la même façon : ```diff showLineNumbers - Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") + Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` conserve son nom mais prend désormais un `AdaptyFlow` : ```diff showLineNumbers - Adapty.getPaywallProducts(paywall) + Adapty.getPaywallProducts(flow) .onSuccess { products -> // use the products } ``` ### Fichiers de secours \{#fallback-files\} Le format du fichier de secours [a changé dans le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le à votre application. ## Modèle de données \{#data-model\} `getFlow` renvoie un `AdaptyFlow` à la place d'un `AdaptyPaywall`, et la structure de l'objet a changé : | Propriété v3 `AdaptyPaywall` | Propriété v4 `AdaptyFlow` | Action | |---|---|---| | `remoteConfig: AdaptyRemoteConfig?` (unique) | `remoteConfigs: List<AdaptyRemoteConfig>` | Un flow contient une Remote Config par langue configurée. Lisez celle qui correspond à l'utilisateur : `flow.remoteConfigs.firstOrNull { it.locale == "en" }`. | | _(nouveau)_ | `paywalls: List<AdaptyFlowPaywall>` | Chaque entrée est une variante de paywall dans le flow, avec son propre `name`, `variationId` et `productIdentifiers`. Les méthodes de paywall web prennent un `AdaptyFlowPaywall` — voir [Méthodes de paywall web](#web-paywall-methods). | | `productIdentifiers` | déplacé | Les identifiants de produit se trouvent désormais sur chaque variante : `flow.paywalls[i].productIdentifiers`. Pour récupérer les produits, continuez d'appeler `getPaywallProducts(flow)`. | | `hasViewConfiguration` | supprimé | Supprimez tout contrôle `hasViewConfiguration` de votre code — `createFlowView` renvoie une erreur à la place (voir [Affichage des flows](#displaying-flows)). | `hasViewConfiguration` reste sur `AdaptyOnboarding` — seul le modèle de flow le supprime. ## Méthodes de paywall web \{#web-paywall-methods\} `openWebPaywall` et `createWebPaywallUrl` conservent leurs noms, mais le paramètre `paywall` est remplacé par un paramètre `flowPaywall` qui prend un `AdaptyFlowPaywall` — l'une des variantes dans `flow.paywalls`. Vous pouvez toujours passer un `AdaptyPaywallProduct` à la place : ```diff showLineNumbers - Adapty.openWebPaywall(paywall = paywall) + flow.paywalls.firstOrNull()?.let { flowPaywall -> + Adapty.openWebPaywall(flowPaywall = flowPaywall) + } ``` ## Suivi des vues de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` est renommé en `logShowFlow` et prend désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, de sorte que les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord. ```diff showLineNumbers - Adapty.logShowPaywall(paywall) + Adapty.logShowFlow(flow) ``` Comme en v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage de flows ou de paywalls générés par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement. ## Affichage des flows \{#displaying-flows\} ### createPaywallView → createFlowView Renommez la méthode factory et passez l'`AdaptyFlow`. Le type de vue retourné est renommé de `AdaptyUIPaywallView` en `AdaptyUIFlowView`, mais ses méthodes (`present`, `dismiss`) et les paramètres optionnels (`loadTimeout`, `preloadProducts`, `customTags`, `customTimers`, `customAssets`, `productPurchaseParams`) restent inchangés : ```diff showLineNumbers - AdaptyUI.createPaywallView(paywall) + AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // handle the error } ``` Si vous n'utilisez pas Compose Multiplatform, la méthode factory native est renommée de la même façon : ```diff showLineNumbers - AdaptyUI.createNativePaywallView(paywall) + AdaptyUI.createNativeFlowView(flow) ``` `createFlowView` retourne une `AdaptyResult.Error` si le flow n'a pas de vue configurée — ceci remplace la vérification v3 `hasViewConfiguration` : ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - AdaptyUI.createPaywallView(paywall) - .onSuccess { view -> view.present() } - } + AdaptyUI.createFlowView(flow) + .onSuccess { view -> view.present() } + .onError { error -> + // the flow has no view configured, or view creation failed + } ``` :::note Une vue de flow est à usage unique : après avoir appelé `dismiss()`, la vue est détruite. Appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois. ::: ## Gestion des événements \{#handling-events\} L'observateur d'événements est renommé de `AdaptyUIPaywallsEventsObserver` en `AdaptyUIFlowsEventsObserver`, et ses callbacks remplacent le préfixe `paywallView` par `flowView`. Le contenu des handlers existants n'a pas besoin d'être modifié — il suffit de renommer le type et les overrides : ```diff showLineNumbers - AdaptyUI.setPaywallsEventsObserver(object : AdaptyUIPaywallsEventsObserver { - override fun paywallViewDidFinishPurchase( - view: AdaptyUIPaywallView, + AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { + override fun flowViewDidFinishPurchase( + view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { // custom logic after purchase } }) ``` Un callback est également renommé : `paywallViewDidFailRendering` devient `flowViewDidReceiveError`. Il se déclenche pour les mêmes erreurs de rendu qu'auparavant, ainsi que pour d'autres erreurs d'exécution non liées aux achats : ```diff showLineNumbers - override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {} + override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {} ``` Consultez [Gérer les événements flow et paywall](kmp-handling-events) pour la liste complète des callbacks. ### Vue de la plateforme Compose \{#compose-platform-view\} Si vous intégrez des vues avec le composable Compose Multiplatform, `AdaptyUIPaywallPlatformView(paywall, ...)` est renommé en `AdaptyUIFlowPlatformView(flow, ...)`. Les callbacks d'événements conservent leurs noms `onDid...`, sauf `onDidFailRendering`, qui devient `onDidReceiveError` : ```diff showLineNumbers - AdaptyUIPaywallPlatformView( - paywall = paywall, + AdaptyUIFlowPlatformView( + flow = flow, onDidFinishPurchase = { view, product, result -> /* ... */ }, ) ``` Comme dans la v3, les callbacks que vous passez ici (et tout observateur enregistré via `registerFlowEventsListener`) s'exécutent **en plus** de l'observateur global, et non à sa place — votre callback observe un événement ; il ne remplace pas le comportement global par défaut. Gardez les [valeurs par défaut modifiées](#default-behavior-changes) à l'esprit : par exemple, le comportement global par défaut ne ferme plus la vue après un achat. ### Nouvelles API \{#new-apis\} - `AdaptyUI.setObserverModeResolver(...)` avec un `AdaptyUIObserverModeResolver` — gérez les achats et restaurations initiés depuis les flows lorsque le SDK fonctionne en [mode Observer](implement-observer-mode-kmp). Auparavant, cela n'était disponible que dans les SDK natifs iOS et Android. Voir [Présenter des flows en mode Observer](kmp-present-flows-in-observer-mode). - `AdaptyUI.setSystemRequestsHandler(...)` avec un `AdaptyUISystemRequestsHandler` — réservé aux requêtes système issues d'un flow (invites de permission OS et demandes d'avis d'application). Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler. - Le nouveau callback optionnel `flowViewDidReceiveAnalyticEvent` est réservé aux événements analytiques personnalisés émis par un flow. Les flows ne les transmettent pas encore à votre code, vous n'avez donc pas besoin de l'implémenter. - `AdaptyUI.openWebUrl(url, openIn)` et `AdaptyUI.requestAppReview()` — ces méthodes alimentent la gestion par défaut de `OpenUrlAction` et le `handleAppReviewRequest` par défaut, de sorte que les URL et les demandes d'avis d'application sont traitées nativement prêtes à l'emploi. Appelez-les directement uniquement si vous remplacez ces comportements par défaut. - `AdaptyConfig.ServerCluster.CN` — une nouvelle option de cluster de serveurs aux côtés de `DEFAULT` et `EU`, pour connecter votre application aux [serveurs Adapty en Chine](china-cluster). ## Changements de comportement par défaut \{#default-behavior-changes\} Ces changements ne génèrent pas d'erreurs de compilation, testez-les donc à l'exécution : - **Finalisation d'achat** : En v3, le comportement par défaut de `paywallViewDidFinishPurchase` fermait la vue après tout résultat d'achat autre que `AdaptyPurchaseResult.UserCanceled`. En v4, le comportement par défaut de `flowViewDidFinishPurchase` ne fait rien, donc **un flow reste ouvert après un achat jusqu'à ce que vous le fermiez vous-même** — comme sur iOS. Si vous vous appuyiez sur cette fermeture automatique, appelez `view.dismiss()` une fois l'achat terminé. - **Bouton retour Android** : En v3, le comportement par défaut de `paywallViewDidPerformAction` fermait la vue pour `CloseAction` et `AndroidSystemBackAction`. En v4, le comportement par défaut ne gère que `CloseAction` — **le bouton retour système ne ferme plus un flow automatiquement**, comme sur iOS où un flow ne peut pas être fermé par un geste système. Donnez aux utilisateurs un moyen explicite de sortir (un bouton **Close** ou une action `on_device_back`), ou fermez la vue vous-même dans `flowViewDidPerformAction`. - **Erreurs de vue** : En v3, le comportement par défaut de `paywallViewDidFailRendering` ne faisait rien. En v4, le comportement par défaut de `flowViewDidReceiveError` **ferme la vue** — surchargez-le si vous souhaitez garder la vue ouverte ou gérer l'erreur différemment. - **Les vues sont à usage unique** : Après `dismiss()`, la vue est détruite. Appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois. ## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\} L'ancienne API onboarding est dépréciée dans la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, mais sera supprimée dans une prochaine version — prévoyez donc la migration de vos onboardings vers le Flow Builder. Symboles dépréciés : `getOnboarding`, `getOnboardingForDefaultAudience`, `AdaptyUI.createOnboardingView`, `AdaptyUI.createNativeOnboardingView` et `AdaptyUIOnboardingsEventsObserver`. --- # File: migration-to-kmp-315 --- --- title: "Guide de migration vers Adapty Kotlin Multiplatform SDK 3.15.0" description: "Étapes de migration pour Adapty Kotlin Multiplatform SDK 3.15.0" --- Adapty Kotlin Multiplatform SDK 3.15.0 est une version majeure qui apporte de nouvelles fonctionnalités et améliorations, lesquelles peuvent néanmoins nécessiter quelques étapes de migration de votre côté. 1. Mettez à jour les noms de la classe et des méthodes de l'observer. 2. Mettez à jour le nom de la méthode des paywalls de secours. 3. Mettez à jour le nom de la classe de vue dans les méthodes de gestion des événements. ## Mettre à jour les noms de la classe et des méthodes de l'observer \{#update-observer-class-and-method-names\} La classe observer et sa méthode d'enregistrement ont été renommées : ```diff - import com.adapty.kmp.AdaptyUIObserver + import com.adapty.kmp.AdaptyUIPaywallsEventsObserver - import com.adapty.kmp.models.AdaptyUIView + import com.adapty.kmp.models.AdaptyUIPaywallView - class MyAdaptyUIObserver : AdaptyUIObserver { - override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) { + class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { + override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { // handle actions } } // Set up the observer - AdaptyUI.setObserver(MyAdaptyUIObserver()) + AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` ## Mettre à jour le nom de la méthode des paywalls de secours \{#update-fallback-paywalls-method-name\} Le nom de la méthode permettant de définir les paywalls de secours a été modifié : ```diff showLineNumbers - Adapty.setFallbackPaywalls(assetId = "fallback.json") + Adapty.setFallback(assetId = "fallback.json") .onSuccess { // Fallback paywalls loaded successfully } .onError { error -> // Handle the error } ``` ## Mettre à jour le nom de la classe de vue dans les méthodes de gestion des événements \{#update-view-class-name-in-event-handling-methods\} Toutes les méthodes de gestion des événements utilisent désormais la nouvelle classe `AdaptyUIPaywallView` à la place de `AdaptyUIView` : ```diff - override fun paywallViewDidAppear(view: AdaptyUIView) { + override fun paywallViewDidAppear(view: AdaptyUIPaywallView) { // Handle paywall appearance } - override fun paywallViewDidDisappear(view: AdaptyUIView) { + override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) { // Handle paywall disappearance } - override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) { + override fun paywallViewDidSelectProduct(view: AdaptyUIView, productId: String) { // Handle product selection } - override fun paywallViewDidStartPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct) { + override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) { // Handle purchase start } - override fun paywallViewDidFinishPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { + override fun paywallViewDidFinishPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { // Handle purchase result } - override fun paywallViewDidFailPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, error: AdaptyError) { + override fun paywallViewDidFailPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, error: AdaptyError) { // Add your purchase failure handling logic here } - override fun paywallViewDidFinishRestore(view: AdaptyUIView, profile: AdaptyProfile) { + override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) { // Add your successful restore handling logic here } - override fun paywallViewDidFailRestore(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your restore failure handling logic here } - override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIView, product: AdaptyPaywallProduct?, error: AdaptyError?) { + override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct?, error: AdaptyError?) { // Handle web payment navigation result } - override fun paywallViewDidFailLoadingProducts(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your product loading failure handling logic here } - override fun paywallViewDidFailRendering(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) { // Handle rendering error } ``` --- # End of Documentation _Generated on: 2026-08-04T15:08:26.079Z_ _Successfully processed: 48/48 files_ # REACT-NATIVE - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:26.081Z Total files: 57 --- # File: react-native-sdk-overview --- --- title: "React Native SDK overview" description: "Découvrez le SDK React Native Adapty et ses fonctionnalités clés." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le SDK React Native Adapty pour vous libérer des contraintes des achats intégrés et vous permettre de vous concentrer sur ce que vous faites le mieux – créer des applications extraordinaires. Voici ce dont nous nous occupons pour vous : - Gestion des achats, validation des reçus et gestion des abonnements prêts à l'emploi - Création et test de flows et de paywalls sans mise à jour de l'application - Analyses d'achats détaillées sans aucune configuration – cohortes, LTV, churn et analyse de funnel inclus - Statut d'abonnement utilisateur toujours à jour entre les sessions et les appareils - Intégration avec des services d'attribution marketing et d'analyse en une seule ligne de code Que votre application soit développée avec **Expo** ou en **React Native pur**, le SDK Adapty prend en charge les deux environnements. :::note Avant de plonger dans le code, vous devrez intégrer Adapty avec App Store Connect et Google Play Console, puis configurer vos produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer en premier. ::: ## Premiers pas \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons aborder dans le guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-reactnative) : Ajoutez le SDK comme dépendance à votre projet et activez-le dans le code. Adapty fonctionne aussi bien avec **Expo** que dans des projets **React Native purs**. 2. [Activer les achats via les flows](react-native-quickstart-paywalls) : Configurez le flow d'achat pour que les utilisateurs puissent acheter des produits. Pour créer votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](react-native-quickstart-manual). 3. [Vérifier le statut d'abonnement](react-native-check-subscription-status) : Vérifiez automatiquement l'état de l'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (optionnel)](react-native-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir la cohérence de leurs données sur tous les appareils. ### En action \{#see-it-in-action\} Envie de voir comment tout s'assemble ? Nous avons ce qu'il vous faut : - **Exemples d'applications** : Consultez nos [exemples complets](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples) qui illustrent la configuration complète - **Tutoriel vidéo** : Suivez notre vidéo d'implémentation étape par étape ci-dessous <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/TtCJswpt2ms?si=FlFJGvpj-U33yoNK" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> ## Concepts clés \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts essentiels qui font fonctionner Adapty. La force de l'approche Adapty, c'est que seuls les placements sont codés en dur dans votre application. Tout le reste – produits, designs de paywalls, tarifs et offres – peut être géré de façon flexible depuis l'Adapty Dashboard sans mise à jour de l'application : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre application – abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Des produits regroupés avec une configuration, rattachés à un placement. Deux variantes : - **[Flow](adapty-flow-builder)** - Interface visuelle sans code, construite dans le Flow Builder. Adapty affiche l'interface et gère l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous construisez l'interface dans votre propre code et appelez `makePurchase` vous-même. Voir [Implémenter les paywalls manuellement](react-native-quickstart-manual). Dans le code SDK, les deux sont récupérés via la même méthode `getFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Les placements représentent le « où » et le « quand » de votre stratégie de monétisation. Les placements courants incluent : - `main` - L'emplacement principal de votre paywall - `onboarding` - Affiché pendant le flow d'onboarding de l'utilisateur - `settings` - Accessible depuis les paramètres de votre application Commencez par les bases comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits de votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque des utilisateurs achètent un produit, un **niveau d'accès** est attribué à leur profil, que vous utilisez pour définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-reactnative --- --- title: "Installer et configurer le SDK React Native" description: "Guide étape par étape pour installer le SDK Adapty sur React Native pour les applications basées sur les abonnements." --- Adapty fournit un SDK React Native entièrement natif qui fonctionne aussi bien dans les projets **Expo** qu'en **React Native pur**. Ces environnements utilisant des systèmes de build différents, les étapes d'installation diffèrent également. Choisissez le guide d'installation correspondant à votre projet : <CustomDocCardList /> --- # File: sdk-installation-react-native-expo --- --- title: "Installer et configurer le SDK Adapty React Native dans un projet Expo" description: "Guide étape par étape pour installer le SDK Adapty React Native dans un projet Expo pour les applications basées sur des abonnements." --- :::important Ce guide couvre l'installation et la configuration du SDK React Native d'Adapty **dans un projet Expo**. Si vous utilisez **React Native pur (sans Expo)**, suivez le [guide d'installation React Native](sdk-installation-react-native-pure) à la place. ::: Adapty SDK comprend deux modules clés pour une intégration fluide dans votre application React Native : - **Core Adapty** : ce module est indispensable au bon fonctionnement d'Adapty dans votre application. - **AdaptyUI** : ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. AdaptyUI est automatiquement activé avec le module principal. Si vous souhaitez un tutoriel complet sur l'implémentation des achats intégrés dans votre application React Native, consultez [celui-ci](https://adapty.io/blog/react-native-in-app-purchases-tutorial/). :::tip Vous voulez voir un exemple concret de l'intégration du SDK Adapty dans une application Expo ? Consultez nos exemples d'applications : - [Exemple de build Expo dev](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) pour toutes les fonctionnalités, y compris les achats réels et le Paywall Builder - [Exemple Expo Go & Web](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) pour les tests en mode simulation ::: Pour une présentation complète de l'implémentation, vous pouvez également regarder la vidéo : <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/TtCJswpt2ms?si=FlFJGvpj-U33yoNK" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> ## Prérequis \{#requirements\} Le SDK React Native d'Adapty requiert iOS 15.0+. La compilation pour iOS nécessite **Swift 6.0** ou une version ultérieure. Le [mode enfants](kids-mode-react-native) requiert **Swift 6.1** ou une version ultérieure. :::info À partir du SDK v3.17, le SDK Adapty utilise Google Play Billing Library v8.0.0 par défaut. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} :::important À partir de la v4, le SDK Adapty React Native ne prend plus en charge l'installation CocoaPods de ses dépendances natives. Si vous avez besoin de la v4 ou d'une version ultérieure (pour le [Flow Builder](adapty-flow-builder)), suivez plutôt [SDK Adapty 4.0 : activer Swift Package Manager](#adapty-sdk-40-enable-swift-package-manager) ci-dessous. ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) :::important [Expo Dev Client](https://docs.expo.dev/versions/latest/sdk/dev-client/) (un build de développement personnalisé) est requis pour utiliser Adapty dans un projet Expo. Expo Go ne prend pas en charge les modules natifs personnalisés, vous pouvez donc l'utiliser uniquement avec le [**mode mock**](#set-up-mock-mode-for-expo-go--expo-web) pour le développement UI/logique (pas d'achats réels ni de rendu AdaptyUI/Paywall Builder). ::: 1. Installez le SDK Adapty (cela installe également `@adapty/core` automatiquement) : ```sh npx expo install react-native-adapty npx expo prebuild ``` 2. Compilez votre application pour le développement avec EAS ou un build local : <Tabs> <TabItem value="eas" label="EAS build" default> ```sh # For iOS eas build --profile development --platform ios # For Android eas build --profile development --platform android ``` </TabItem> <TabItem value="local" label="Local build"> ```sh # For iOS npx expo run:ios # For Android npx expo run:android ``` </TabItem> </Tabs> 3. Démarrez le serveur de développement : ```sh npx expo start --dev-client ``` ### Adapty SDK 4.0 : activer Swift Package Manager \{#adapty-sdk-40-enable-swift-package-manager\} Le SDK React Native 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — nécessite **React Native 0.75 ou une version ultérieure**. Installez le SDK : ```sh npx expo install react-native-adapty@^4.0.0 ``` v4 récupère les SDK iOS natifs (`Adapty`, `AdaptyUI`, `AdaptyPlugin`) via Swift Package Manager plutôt que les sous-dépendances CocoaPods ([le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). SPM requiert des frameworks dynamiques, que vous activez dans Expo avec le plugin [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/). Ajoutez-le dans `app.json` (ou `app.config.js`) : ```json showLineNumbers title="app.json" { "expo": { "plugins": [ [ "expo-build-properties", { "ios": { "useFrameworks": "dynamic", "buildReactNativeFromSource": true } } ] ] } } ``` `buildReactNativeFromSource` est requis à partir d'**Expo SDK 57 et versions ultérieures**. Expo SDK 57 embarque un framework React Native prébuild dont les headers ne sont pas accessibles aux autres packages lorsque les frameworks sont dynamiques, ce qui entraîne des erreurs de build iOS du type `'React/RCTBridge.h' file not found` dans `expo-updates` ou `@expo/ui`. Compiler React Native depuis les sources permet d'éviter ce conflit, au prix de builds iOS plus longs. Avec Expo SDK 56 ou antérieur, cette option peut être omise. Installez ensuite le plugin et regénérez le projet natif : ```sh npx expo install expo-build-properties npx expo prebuild --clean ``` Consultez [Migrer le SDK Adapty React Native vers la v4](migration-to-react-native-sdk-v4) pour la migration complète. ## Activer le module Adapty du SDK \{#activate-adapty-module-of-adapty-sdk\} Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. Copiez le code suivant dans `App.tsx` pour activer Adapty : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important Attendez que `activate` soit résolu avant d'appeler toute autre méthode du SDK Adapty. Consultez [Ordre d'appel dans le SDK React Native](react-native-sdk-call-order) pour la séquence complète. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), suivez le [guide de démarrage du Paywall Builder](react-native-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [guide de démarrage pour les paywalls personnalisés](react-native-quickstart-manual). :::tip Pour éviter les erreurs d'activation dans l'environnement de développement, consultez les [conseils](#development-environment-tips). ::: ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder), vous avez besoin du module AdaptyUI. Il est activé automatiquement lors de l'activation du module principal ; vous n'avez rien d'autre à faire. ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Seules les erreurs seront enregistrées | | `warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais méritent attention, seront enregistrés | | `info` | Les erreurs, avertissements et divers messages d'information seront enregistrés | | `verbose` | Toute information supplémentaire pouvant être utile lors du débogage, telle que les appels de fonctions, les requêtes API, etc., sera enregistrée | Vous pouvez définir le niveau de journalisation dans votre application avant ou pendant la configuration d'Adapty : ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs sauf si vous les envoyez explicitement, mais vous pouvez mettre en place des politiques de sécurité des données supplémentaires pour respecter les directives du store ou du pays. #### Désactiver la collecte et le partage des adresses IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` sur `true` pour désactiver la collecte et le partage des adresses IP des utilisateurs. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'IP ne sont pas requises pour votre application. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ios.idfaCollectionDisabled` (iOS) ou `android.adIdCollectionDisabled` (Android) sur `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour respecter les règles de l'App Store ou du Play Store, éviter d'afficher la demande d'autorisation App Tracking Transparency, ou si votre application n'a pas besoin d'attribution publicitaire ni d'analyses basées sur les identifiants publicitaires. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos, par exemple) pour améliorer les performances et réduire la consommation réseau. Vous pouvez personnaliser ces paramètres en fournissant une configuration personnalisée. Utilisez `mediaCache` pour remplacer les paramètres de cache par défaut : ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` | Paramètre | Requis | Description | |-----------|--------|-------------| | memoryStorageTotalCostLimit | optionnel | Taille totale du cache en mémoire, en octets. Valeur par défaut spécifique à la plateforme. | | memoryStorageCountLimit | optionnel | Nombre maximum d'éléments dans le cache mémoire. Valeur par défaut spécifique à la plateforme. | | diskStorageSizeLimit | optionnel | Taille maximale des fichiers sur le disque, en octets. Valeur par défaut spécifique à la plateforme. | ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont activés sur iOS et désactivés sur Android. Pour les activer également sur Android, définissez `localAccessLevelAllowed` sur `true` : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### Effacer les données lors d'une restauration de sauvegarde \{#clear-data-on-backup-restore\} Lorsque `clearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, y compris les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état vierge. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## Conseils pour l'environnement de développement \{#development-environment-tips\} #### Configurer le mode mock pour Expo Go / Expo Web \{#set-up-mock-mode-for-expo-go--expo-web\} Les environnements Expo Go et Expo Web n'ont pas accès aux modules natifs d'Adapty. Pour éviter les erreurs d'exécution tout en pouvant continuer à développer et tester l'interface et la logique de vos paywalls, Adapty propose un **mode mock**. ::::important Le mode mock n'est **pas** un outil pour tester de vrais achats : - Il **n'ouvre pas** les flux d'achat de l'App Store / Google Play et **ne crée pas** de vraies transactions. - Il **n'affiche pas** les paywalls/onboardings créés avec **Adapty Paywall Builder (AdaptyUI)**. - Les modules natifs d'Adapty sont **complètement contournés** — même l'absence de fichiers SDK natifs dans le build Xcode/Android ou une clé API invalide ne déclenchera pas d'erreurs. Pour tester de vrais achats et des paywalls Paywall Builder, utilisez un Expo Dev Client / build de production où le mode mock est automatiquement désactivé. :::: **Par défaut**, le SDK détecte automatiquement les environnements Expo Go et web et active le mode mock. Aucune configuration n'est nécessaire, sauf si vous souhaitez personnaliser les données mock. Lorsque le mode mock est actif : - Toutes les méthodes Adapty retournent des données mock sans effectuer de requêtes réseau vers les serveurs d'Adapty. - Par défaut, le profil mock initial n'a pas d'abonnements actifs. - Par défaut, `makePurchase(...)` simule un achat réussi et accorde l'accès premium. Vous pouvez personnaliser les données fictives avec `mockConfig` lors de l'activation. Consultez le format de configuration et les paramètres pris en charge [ici](https://react-native.adapty.io/interfaces/adaptymockconfig). ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` Si vous devez appeler des méthodes du SDK avant l'activation (comme `isActivated()` ou `setLogLevel()`), utilisez `enableMock()` avant `activate()`. Si le bridge est déjà initialisé, cette méthode ne fait rien. ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // Optional: pass mockConfig to customize mock data // Now you can call methods before activation await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` #### Différer l'activation du SDK à des fins de développement \{#delay-sdk-activation-for-development-purposes\} Adapty récupère à l'avance toutes les données utilisateur nécessaires lors de l'activation du SDK, ce qui permet un accès plus rapide aux données fraîches. Cependant, cela peut poser un problème dans le simulateur iOS, qui demande fréquemment une authentification pendant le développement. Bien qu'Adapty ne puisse pas contrôler le flux d'authentification StoreKit, il peut différer les requêtes effectuées par le SDK pour obtenir des données utilisateur fraîches. En activant la propriété `__debugDeferActivation`, l'appel d'activation est suspendu jusqu'à ce que vous effectuiez le prochain appel au SDK Adapty. Cela évite les demandes d'authentification inutiles si elles ne sont pas nécessaires. Il est important de noter que **cette fonctionnalité est destinée uniquement au développement**, car elle ne couvre pas tous les scénarios utilisateurs possibles. En production, l'activation ne doit pas être retardée, car les appareils réels mémorisent généralement les données d'authentification et ne redemandent pas les identifiants à répétition. Voici l'approche recommandée : ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' from any 3rd party library }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### Résoudre les erreurs d'activation du SDK lors du Fast Refresh de React Native \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} Lors du développement avec le SDK Adapty dans React Native, vous pouvez rencontrer l'erreur : `Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` Cela se produit parce que la fonctionnalité de fast refresh de React Native déclenche plusieurs appels d'activation pendant le développement. Pour éviter cela, utilisez l'option `__ignoreActivationOnFastRefresh` définie sur `__DEV__` (le flag du mode développement de React Native). ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` ## Résolution des problèmes \{#troubleshooting\} #### Erreur de version iOS minimale \{#minimum-ios-version-error\} Lors d'une compilation pour iOS, vous pourriez voir une erreur concernant la **version iOS minimale** ou la cible de déploiement. Adapty requiert **iOS 15.0+**. Étant donné qu'Expo génère le projet iOS (y compris le `Podfile`) lors de l'exécution de `expo prebuild`, **vous ne devez pas modifier le `Podfile` directement**. Configurez plutôt la cible de déploiement via le plugin de configuration `expo-build-properties`. 1. Installez le plugin : ```sh npx expo install expo-build-properties ``` 2. Mettez à jour votre configuration Expo (`app.json` ou `app.config.js`) pour définir la cible de déploiement iOS : ``` { "expo": { // ...other Expo config... "plugins": [ [ "expo-build-properties", { "ios": { // Adapty requires iOS 15.0+. "deploymentTarget": "15.0" } } ], ] } } ``` 3. Régénérez le projet iOS natif et reconstruisez : ``` npx expo prebuild --clean npx expo run:ios # or `eas build -p ios` on your CI ``` #### Conflit de manifeste Android Auto Backup \{#android-auto-backup-manifest-conflict\} Lors de l'utilisation d'Expo avec plusieurs SDK qui configurent Android Auto Backup (comme Adapty, AppsFlyer ou expo-secure-store), vous pouvez rencontrer un conflit lors de la fusion des manifestes. Une erreur type ressemble à ceci : `Manifest merger failed : Attribute application@fullBackupContent value=(@xml/secure_store_backup_rules) from AndroidManifest.xml:24:248-306 is also present at [io.adapty:android-sdk:3.12.0] AndroidManifest.xml:9:18-70 value=(@xml/adapty_backup_rules).` Pour résoudre ce conflit, vous devez laisser le plugin Adapty gérer la configuration de sauvegarde Android. Si votre projet utilise également `expo-secure-store`, désactivez sa propre configuration de sauvegarde pour éviter les conflits. Voici comment configurer votre `app.json` : ```json title="app.json" { "expo": { "plugins": [ ["react-native-adapty", { "replaceAndroidBackupConfig": true }], ["expo-secure-store", { "configureAndroidBackup": false }] ] } } ``` L'option `replaceAndroidBackupConfig` est `false` par défaut. Lorsqu'elle est activée, elle permet au plugin Adapty de contrôler les règles de sauvegarde Android. Ajoutez `"configureAndroidBackup": false` si vous utilisez `expo-secure-store` pour éviter les avertissements, car la configuration de sauvegarde de SecureStore sera désormais gérée par Adapty. :::important Cette configuration respecte uniquement les exigences de sauvegarde pour Adapty, AppsFlyer et expo-secure-store. Si d'autres bibliothèques de votre projet définissent des règles de sauvegarde personnalisées, vous devrez les configurer manuellement. ::: --- # File: sdk-installation-react-native-pure --- --- title: "Installer et configurer le SDK Adapty dans un projet React Native pur" description: "Guide étape par étape pour installer le SDK Adapty sur React Native pour les applications basées sur les abonnements." --- :::important Ce guide s'applique uniquement aux **projets React Native purs (sans Expo)**. Si vous utilisez **Expo**, suivez plutôt le [guide d'installation pour Expo](sdk-installation-react-native-expo). ::: Le SDK Adapty comprend deux modules clés pour une intégration fluide dans votre application React Native : - **Core Adapty** : ce module est indispensable au bon fonctionnement d'Adapty dans votre application. - **AdaptyUI** : ce module est nécessaire si vous utilisez le [Adapty Paywall Builder](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. AdaptyUI est activé automatiquement avec le module principal. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Prérequis \{#requirements\} Le SDK React Native d'Adapty requiert iOS 15.0 ou supérieur. La compilation pour iOS nécessite **Swift 6.0** ou une version ultérieure. Le [mode Kids](kids-mode-react-native) requiert **Swift 6.1** ou une version ultérieure. :::info À partir du SDK v3.17, Adapty SDK utilise Google Play Billing Library v8.0.0 par défaut. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK Adapty \{#install-adapty-sdk\} :::important À partir de la v4, le SDK React Native d'Adapty ne prend plus en charge l'installation CocoaPods de ses dépendances natives. Si vous avez besoin de la v4 ou d'une version ultérieure (pour le [Flow Builder](adapty-flow-builder)), suivez plutôt [SDK Adapty 4.0 : activer Swift Package Manager](#adapty-sdk-40-enable-swift-package-manager) ci-dessous. ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) 1. Installez le SDK Adapty (cela installe également `@adapty/core` automatiquement) : ```sh showLineNumbers title="Shell" # using npm npm install react-native-adapty # or using yarn yarn add react-native-adapty ``` 2. Pour iOS, installez les pods : ```sh showLineNumbers title="Shell" cd ios && pod install ``` <details> <summary>Pour Android, si votre version de React Native est antérieure à 0.73.0 (cliquez pour développer)</summary> Mettez à jour le fichier `/android/build.gradle`. Assurez-vous que la dépendance `kotlin-gradle-plugin:1.8.0` ou une version plus récente est présente : ```groovy showLineNumbers title="/android/build.gradle" ... buildscript { ... dependencies { ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" } } ... ``` </details> ### SDK Adapty 4.0 : activer Swift Package Manager \{#adapty-sdk-40-enable-swift-package-manager\} Le SDK React Native 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — nécessite **React Native 0.75 ou une version ultérieure**. Installez le SDK : ```sh showLineNumbers title="Shell" npm install react-native-adapty@^4.0.0 # or using yarn yarn add react-native-adapty@^4.0.0 ``` La v4 récupère les SDK iOS natifs (`Adapty`, `AdaptyUI`, `AdaptyPlugin`) via Swift Package Manager plutôt que via des sous-dépendances CocoaPods ([le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). SPM nécessite des frameworks dynamiques — ajoutez ce qui suit dans la cible de votre `ios/Podfile`, puis réinstallez les pods : ```ruby showLineNumbers title="ios/Podfile" use_frameworks! :linkage => :dynamic ``` ```sh showLineNumbers title="Shell" cd ios && pod install --repo-update ``` Si vous récupériez auparavant `Adapty`, `AdaptyUI` ou `AdaptyPlugin` en tant que sous-dépendances CocoaPods, supprimez d'abord toute ligne `pod 'Adapty'`, `pod 'AdaptyUI'` ou `pod 'AdaptyPlugin'` de votre `Podfile`. :::warning Passer de la liaison statique par défaut aux frameworks dynamiques peut entrer en conflit avec des bibliothèques qui ne prennent pas encore en charge les en-têtes modulaires, et est incompatible avec Flipper. Consultez [Migrer le SDK React Native Adapty vers la v4](migration-to-react-native-sdk-v4) pour plus de détails. ::: ## Activer le module Adapty du SDK Adapty \{#activate-adapty-module-of-adapty-sdk\} Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. Copiez le code suivant dans `App.tsx` pour activer Adapty : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important Attendez que `activate` soit résolu avant d'appeler toute autre méthode du SDK Adapty. Consultez [Ordre des appels dans le SDK React Native](react-native-sdk-call-order) pour la séquence complète. ::: Configurez maintenant les paywalls dans votre application : - Si vous utilisez [Adapty Paywall Builder](adapty-paywall-builder), suivez le [démarrage rapide avec Paywall Builder](react-native-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [démarrage rapide pour les paywalls personnalisés](react-native-quickstart-manual). :::tip Pour éviter les erreurs d'activation en environnement de développement, utilisez les [conseils](#development-environment-tips). ::: ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder), vous avez besoin du module AdaptyUI. Il est activé automatiquement lorsque vous activez le module principal ; vous n'avez rien d'autre à faire. ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Niveau | Description | | ---------- | ------------------------------------------------------------ | | `error` | Seules les erreurs seront enregistrées | | `warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques mais méritent attention seront enregistrés | | `info` | Les erreurs, avertissements et divers messages d'information seront enregistrés | | `verbose` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera enregistrée | Vous pouvez définir le niveau de journalisation dans votre application avant ou pendant la configuration d'Adapty : ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs à moins que vous ne les envoyiez explicitement, mais vous pouvez mettre en place des politiques de sécurité des données supplémentaires pour vous conformer aux directives des stores ou des pays. #### Désactiver la collecte et le partage des adresses IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ipAddressCollectionDisabled` sur `true` pour désactiver la collecte et le partage des adresses IP des utilisateurs. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutile lorsque les fonctionnalités basées sur l'IP ne sont pas requises pour votre application. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `ios.idfaCollectionDisabled` (iOS) ou `android.adIdCollectionDisabled` (Android) sur `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour vous conformer aux politiques de l'App Store/Play Store, éviter de déclencher la demande App Tracking Transparency, ou si votre application ne nécessite pas d'attribution publicitaire ni d'analyse basée sur les identifiants publicitaires. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire l'utilisation du réseau. Vous pouvez personnaliser les paramètres du cache en fournissant une configuration personnalisée. Utilisez `mediaCache` pour remplacer les paramètres de cache par défaut : ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` Paramètres : | Paramètre | Requis | Description | |-----------|----------|-------------| | memoryStorageTotalCostLimit | optionnel | Taille totale du cache en mémoire en octets. Par défaut, valeur spécifique à la plateforme. | | memoryStorageCountLimit | optionnel | Limite du nombre d'éléments dans le stockage en mémoire. Par défaut, valeur spécifique à la plateforme. | | diskStorageSizeLimit | optionnel | Limite de taille des fichiers sur le disque en octets. Par défaut, valeur spécifique à la plateforme. | ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont activés sur iOS et désactivés sur Android. Pour les activer également sur Android, définissez `localAccessLevelAllowed` sur `true` : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### Effacer les données lors de la restauration d'une sauvegarde \{#clear-data-on-backup-restore\} Lorsque `clearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, y compris les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise alors avec un état vierge. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## Conseils pour l'environnement de développement \{#development-environment-tips\} #### Retarder l'activation du SDK à des fins de développement \{#delay-sdk-activation-for-development-purposes\} Adapty pré-charge toutes les données utilisateur nécessaires lors de l'activation du SDK, permettant un accès plus rapide aux données actualisées. Cela peut toutefois poser problème dans le simulateur iOS, qui demande fréquemment une authentification lors du développement. Bien qu'Adapty ne puisse pas contrôler le flux d'authentification StoreKit, il peut différer les requêtes effectuées par le SDK pour obtenir des données utilisateur actualisées. En activant la propriété `__debugDeferActivation`, l'appel d'activation est suspendu jusqu'à ce que vous effectuiez le prochain appel au SDK Adapty. Cela évite les demandes d'authentification inutiles si elles ne sont pas nécessaires. Il est important de noter que **cette fonctionnalité est destinée uniquement au développement**, car elle ne couvre pas tous les scénarios utilisateur possibles. En production, l'activation ne doit pas être différée, car les appareils réels mémorisent généralement les données d'authentification et ne demandent pas répétitivement les identifiants. Voici l'approche recommandée : ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' from any 3rd party library }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### Résoudre les erreurs d'activation du SDK avec le Fast Refresh de React Native \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} Lors du développement avec le SDK Adapty dans React Native, vous pouvez rencontrer l'erreur : `Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` Cela se produit parce que la fonctionnalité de rechargement rapide de React Native déclenche plusieurs appels d'activation pendant le développement. Pour éviter cela, utilisez l'option `__ignoreActivationOnFastRefresh` définie sur `__DEV__` (le drapeau de mode développement de React Native). ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### Configurer le mode mock pour les tests locaux \{#set-up-mock-mode-for-local-testing\} Pour le développement local et les tests, vous pouvez activer le mode mock afin d'éviter d'avoir besoin de comptes sandbox App Store/Google Play et d'accélérer les itérations. Le mode mock contourne complètement les modules natifs d'Adapty et renvoie des données simulées. :::important Le mode mock **n'est pas** un outil pour tester de vrais achats : - Il **n'ouvre pas** les flux d'achat App Store / Google Play et **ne crée pas** de vraies transactions. - Il **n'affiche pas** les paywalls/onboardings créés avec **Adapty Paywall Builder (AdaptyUI)**. - Les modules natifs d'Adapty sont **complètement contournés** — même des fichiers SDK natifs manquants dans la build Xcode/Android ou une clé API invalide ne déclencheront pas d'erreurs. - Aucune donnée n'est envoyée aux serveurs d'Adapty. Pour tester de vrais achats et les paywalls Paywall Builder, désactivez le mode mock et utilisez des comptes sandbox. ::: Pour activer le mode mock, définissez `enableMock` sur `true` : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { enableMock: true, }); ``` Lorsque le mode mock est actif : - Toutes les méthodes Adapty renvoient des données mock sans effectuer de requêtes réseau vers les serveurs d'Adapty. - Par défaut, le profil mock initial n'a pas d'abonnements actifs. - Par défaut, `makePurchase(...)` simule un achat réussi et accorde l'accès premium. Vous pouvez personnaliser les données mock en utilisant `mockConfig` lors de l'activation. Consultez le format de configuration et les paramètres pris en charge [ici](https://react-native.adapty.io/interfaces/adaptymockconfig). ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` Si vous avez besoin d'appeler des méthodes du SDK avant l'activation (comme `isActivated()` ou `setLogLevel()`), utilisez `enableMock()` avant `activate()`. Si le bridge est déjà initialisé, cette méthode ne fait rien. ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // Optional: pass mockConfig to customize mock data // Now you can call methods before activation await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` ## Dépannage \{#troubleshooting\} #### Erreur de version iOS minimale \{#minimum-ios-version-error\} Si vous obtenez une erreur de version iOS minimale, mettez à jour votre Podfile : ```diff -platform :ios, min_ios_version_supported +platform :ios, '15.0' ``` #### Conflit de manifeste Android Auto Backup \{#android-auto-backup-manifest-conflict\} Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules` ou `android:allowBackup`. Symptômes typiques : `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 Ces modifications doivent être effectuées dans votre répertoire de la plateforme Android (généralement situé dans le dossier `android/` de votre projet). ::: Pour résoudre ce problème, vous devez : - Indiquer au gestionnaire de fusion de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Créer des fichiers de règles de sauvegarde qui fusionnent les règles d'Adapty avec celles des autres SDKs. #### 1. Ajoutez l'espace de noms `tools` à votre manifeste \{#1-add-the-tools-namespace-to-your-manifest\} Dans votre fichier `AndroidManifest.xml`, assurez-vous que la balise racine `<manifest>` inclut tools : ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. Remplacez les attributs de sauvegarde dans `<application>` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `<application>` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion de remplacer les valeurs des bibliothèques : ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez les fichiers de règles de sauvegarde fusionnés \{#3-create-merged-backup-rules-files\} Créez des fichiers XML dans le répertoire `res/xml/` de votre projet Android, en combinant les règles d'Adapty avec celles des autres SDKs. Android utilise des formats de règles de sauvegarde différents selon la version de l'OS, donc créer les deux fichiers garantit la compatibilité avec toutes les versions d'Android prises en charge par votre application. :::note Les exemples ci-dessous utilisent AppsFlyer comme exemple de SDK tiers. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> #### Les achats échouent après le retour depuis une autre application sur Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si l'Activity qui démarre le flux d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser de manière incorrecte lorsque l'utilisateur revient depuis Google Play, une application bancaire ou un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son traitement comme annulé. Pour que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flux d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui démarre le flux d'achat est définie sur `standard` ou `singleTop` : ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Erreurs de build Swift 6 causées par le remplacement de SWIFT_VERSION dans le Podfile \{#swift-6-build-errors-caused-by-podfile-swift_version-override\} Lors de la compilation de votre application React Native pour iOS, vous pouvez voir des erreurs de compilation Swift 6 sur les cibles de pod Adapty. Les symptômes typiques incluent des incompatibilités `@Sendable` dans `AdaptyUIBuilderLogic`, une conformité `Sendable` manquante sur les types Adapty, ou des erreurs d'isolation d'acteur. Les pods Adapty déclarent `s.swift_version = '6.0'` et nécessitent Swift 6 pour être compilés. Votre propre code d'application peut rester sur Swift 5 — seules les cibles de pod Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`, `AdaptyLogger`, `AdaptyPlugin`) doivent être compilées avec Swift 6. La cause la plus fréquente est un hook `post_install` dans `ios/Podfile` qui réécrit `SWIFT_VERSION` pour chaque cible de pod : ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` **Correctif** : Excluez les cibles de pod Adapty du remplacement : ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name) target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` Exécutez ensuite `pod install` depuis le répertoire `ios/` et recompilez. Pour vérifier, ouvrez `ios/Pods/Pods.xcodeproj`, sélectionnez la cible de pod `Adapty` → **Build Settings** → **Swift Language Version**. Elle devrait indiquer **Swift 6**. --- # File: react-native-quickstart-paywalls --- --- title: "Activer les achats avec le Flow Builder dans le SDK React Native" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – des séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez créer l'interface dans votre propre code, utilisez plutôt un paywall — voir [Implémenter des paywalls manuellement](react-native-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez des flows dans votre application (par exemple `main`, `onboarding`, `settings`). Vous associez des flows à des placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère tout le processus d'achat, la validation des reçus et la gestion des abonnements en arrière-plan. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre application, mais vous récupérez tout de même l'objet flow depuis Adapty pour garder de la flexibilité dans les offres de produits. Voir le [guide](react-native-quickstart-manual). | | Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limitations dans Adapty. Voir l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans l'Adapty Flow Builder.** Si vous préférez créer l'interface du paywall vous-même, voir [Implémenter des paywalls manuellement](react-native-quickstart-manual). ::: Pour afficher un flow créé dans l'Adapty Flow Builder, vous n'avez besoin que de : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre application. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow quand les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans l'Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez-y votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-reactnative) dans le code de votre application. Ce guide utilise les API du SDK Adapty React Native v4. ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'afficher des flows différents selon les audiences ou d'exécuter des [tests A/B](ab-tests). Pour obtenir un flow créé dans l'Adapty Flow Builder, récupérez l'objet `flow` par l'ID de [placement](placements) en utilisant la méthode `getFlow`. Le flow contient les éléments d'interface et les styles nécessaires à son affichage. ```typescript showLineNumbers title="React Native" try { const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); // the requested flow } catch (error) { // handle the error } ``` ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez le flow, quelques lignes suffisent pour l'afficher. <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour intégrer un flow dans votre arborescence de composants existante, utilisez directement le composant `AdaptyFlowView` dans votre hiérarchie de composants React Native : ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>( (result, product) => result.type !== 'user_cancelled', [], ); return ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onPurchaseCompleted={onPurchaseCompleted} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour afficher le flow comme un écran indépendant, créez une `view` avec la méthode `createFlowView`, définissez ses gestionnaires d'événements, puis appelez `view.present()`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`. ```typescript showLineNumbers title="React Native" try { const view = await createFlowView(flow); view.setEventHandlers({ onPurchaseCompleted(result, product) { return result.type !== 'user_cancelled'; }, }); await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> :::tip Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](react-native-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#3-handle-button-actions\} Quand les utilisateurs cliquent sur des boutons dans le flow, le SDK React Native gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des URLs. Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent que vous gériez leurs actions dans votre code. Ou bien, vous pouvez souhaiter remplacer leur comportement par défaut. Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire. <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour le composant React, gérez les actions directement dans le composant `AdaptyFlowView` : ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>( () => true, // allow the flow to close [], ); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>( (actionId) => false, [], ); return ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onCloseButtonPress={onCloseButtonPress} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour la présentation modale, implémentez les gestionnaires d'événements via `setEventHandlers` : ```typescript showLineNumbers title="React Native" const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` </TabItem> </Tabs> :::tip Consultez nos guides sur la gestion des [actions](react-native-handle-paywall-actions) et des [événements](react-native-handling-events-1) des boutons. ::: ## Étapes suivantes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'application. [Testez vos achats](react-native-test) pour vous assurer que vous pouvez effectuer un achat test depuis le flow. Vous devez maintenant [vérifier le niveau d'accès des utilisateurs](react-native-check-subscription-status) pour vous assurer d'afficher un flow ou d'accorder l'accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment toutes les étapes de ce guide peuvent être intégrées ensemble dans votre application. <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```javascript showLineNumbers title="React Native (TSX)" export default function FlowScreen() { const [flow, setFlow] = useState(null); const loadFlow = async () => { try { const flowData = await adapty.getFlow('YOUR_PLACEMENT_ID'); setFlow(flowData); } catch (error) { console.warn('Error loading flow:', error); } }; const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>( () => true, [], ); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>( (result, product) => result.type !== 'user_cancelled', [], ); useEffect(() => { loadFlow(); }, []); return ( <View style={{ flex: 1 }}> {flow ? ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onCloseButtonPress={onCloseButtonPress} onPurchaseCompleted={onPurchaseCompleted} /> ) : ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title="Load Flow" onPress={loadFlow} /> </View> )} </View> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" export default function FlowScreen() { const showFlow = async () => { try { const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); const view = await createFlowView(flow); view.setEventHandlers({ onCloseButtonPress() { return true; }, onPurchaseCompleted(result, product) { return result.type !== 'user_cancelled'; }, }); await view.present(); } catch (error) { // handle any error that may occur during the process console.warn('Error showing flow:', error); } }; // you can add a button to manually trigger the flow for testing purposes return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title="Show Flow" onPress={showFlow} /> </View> ); } ``` </TabItem> </Tabs> --- # File: react-native-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK React Native" description: "Découvrez comment vérifier le statut d'abonnement dans votre application React Native avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — que ce soit un paywall ou l'accès aux fonctionnalités payantes. ## Obtenir le statut d'abonnement \{#get-subscription-status\} Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appelez `getProfile` si vous avez besoin des dernières données de profil immédiatement (par exemple au lancement de l'application) ou si vous souhaitez forcer une mise à jour. - Configurez les **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement à chaque changement de statut d'abonnement. ### Récupérer le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour du profil dans votre application : 1. Utilisez `adapty.addEventListener('onLatestProfileLoad')` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode à chaque changement de statut d'abonnement de l'utilisateur. 2. Stockez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser dans toute votre application sans effectuer de requêtes réseau supplémentaires. ```javascript class SubscriptionManager { private currentProfile: any = null; constructor() { // Listen for profile updates adapty.addEventListener('onLatestProfileLoad', (profile) => { this.currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() hasAccess(): boolean { return this.currentProfile?.accessLevels?.['premium']?.isActive ?? false; } } ``` :::note Adapty appelle automatiquement le listener d'événement `onLatestProfileLoad` au démarrage de votre application, fournissant des données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Associer le profil à la logique de paywall \{#connect-profile-with-paywall-logic\} Lorsque vous devez prendre des décisions immédiates concernant l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier le profil de l'utilisateur directement. Cette approche est utile pour des scénarios tels que le lancement de l'application, l'accès aux sections premium, ou avant d'afficher du contenu spécifique. ```javascript const checkAccessLevel = async () => { try { const profile = await adapty.getProfile(); return profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive === true; } catch (error) { console.warn('Error checking access level:', error); return false; // Show paywall if access check fails } }; const initializePaywall = async () => { try { await loadPaywall(); const hasAccess = await checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } catch (error) { console.warn('Error initializing paywall:', error); } }; ``` ## Prochaines étapes \{#next-steps\} Maintenant que vous savez comment suivre le statut d'abonnement, découvrez comment [travailler avec les profils utilisateur](react-native-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce pour quoi ils ont payé. --- # File: react-native-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK React Native" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans React Native." --- :::important Ce guide vous concerne si vous disposez de votre propre système d'authentification. Vous y apprendrez comment gérer les profils utilisateurs dans Adapty afin de l'aligner avec votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application possède (ou possédera) une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez un **customer user ID** pour faire le lien entre les profils Adapty et votre système d'authentification interne. Voici les différences entre les utilisateurs anonymes et identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|----------------------------------------------------------------|--------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil entre les sessions et les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'app | Les données des utilisateurs identifiés persistent entre les installations de l'app | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lorsque le SDK est activé au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, cet achat est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme lors de l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, par défaut, ses achats sont automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. Ainsi, avec les utilisateurs anonymes, de nouveaux profils seront créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). :::note Les restaurations depuis une sauvegarde se comportent différemment des réinstallations. Par défaut, lorsqu'un utilisateur restaure depuis une sauvegarde, le SDK conserve les données mises en cache et ne crée pas de nouveau profil. Vous pouvez configurer ce comportement avec le paramètre `clearDataOnBackup`. [En savoir plus](sdk-installation-react-native-pure#clear-data-on-backup-restore). ::: Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. ## Utilisateurs identifiés \{#identified-users\} Deux options s'offrent à vous pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID au moment de leur authentification. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils disposent d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après qu'ils se soient connectés ou inscrits), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez jamais utilisé ce customer user ID auparavant**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez la valeur du paramètre en dur, tous les utilisateurs seront considérés comme un seul. ::: Attendez toujours la résolution de `identify` avec `await` avant d'appeler d'autres méthodes du SDK. Les appels simultanés produisent l'erreur `#3006 profileWasChanged` ou atterrissent sur le profil anonyme. Consultez [Ordre des appels dans le SDK React Native](react-native-sdk-call-order). ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID au moment d'activer le SDK, vous pouvez l'envoyer dans la méthode `activate` au lieu d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'au moment de l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après l'appel à `identify`. Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé) ou un nouveau. Si vous en passez un nouveau, le profil créé lors de l'activation sera automatiquement lié à ce customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées sur la base des ID d'appareil. Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est regénéré qu'après la réinstallation de l'application. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une nième installation, ni de l'utilisation d'un customer user ID existant. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génèrent pas d'événements d'installation supplémentaires. Si vous souhaitez compter les installations par utilisateurs uniques plutôt que par appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics). ::: ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID" // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. }); ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si votre application propose un bouton de déconnexion, utilisez la méthode `logout`. :::important La déconnexion des utilisateurs crée un nouveau profil anonyme pour l'utilisateur. ::: ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the error } ``` :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty l'associe à son ID de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty assigne le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez récupérer le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](react-native-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](react-native-check-subscription-status) pour que les données se synchronisent automatiquement. ## Prochaines étapes \{#next-steps\} Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre application ! Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu - [**Onboardings**](react-native-onboardings) : Engagez les utilisateurs avec des onboardings et stimulez la rétention - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code - [**Définir des attributs de profil personnalisés**](react-native-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher différents paywalls à différents utilisateurs --- # File: adapty-sdk-integration-skill-react-native --- --- title: "Intégrer Adapty dans votre application React Native avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application React Native de bout en bout avec votre outil de codage IA." --- :::important La compétence est en version bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-react-native) à la place — il guide votre outil IA à travers chaque étape avec la bonne documentation. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-react-native --- --- title: "Intégrer Adapty dans votre application React Native avec l'aide de l'IA" description: "Un guide pas à pas pour intégrer Adapty dans votre application React Native avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne étape par étape dans l'intégration d'Adapty dans votre application React Native à l'aide d'un outil de codage IA — vous lui fournissez les bonnes docs Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite une configuration dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire via un skill LLM interactif, ou manuellement depuis le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre app, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Il vous suffit de [connecter vos stores](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris pour savoir quand ouvrir le Dashboard afin de connecter vos stores. ### Approche manuelle via le Dashboard \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir. 1. **Connectez vos stores** : Dans l'Adapty Dashboard, allez dans **App settings → General**. Connectez l'App Store et Google Play si votre app cible les deux plateformes. C'est indispensable pour que les achats fonctionnent. [Connecter les stores](integrate-payments) 2. **Copiez votre clé SDK publique** : Dans l'Adapty Dashboard, allez dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez à `adapty.activate("YOUR_PUBLIC_SDK_KEY")`. 3. **Créez au moins un produit** : Dans l'Adapty Dashboard, rendez-vous sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les livre via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : Dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID du placement est la chaîne que vous passez à `adapty.getPaywall("YOUR_PLACEMENT_ID")`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : Dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels['premium']?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des apps. Si les utilisateurs payants accèdent à des fonctionnalités différentes selon le produit (par exemple un plan `basic` vs un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois que vous avez ces cinq éléments, vous êtes prêt à coder. Dites à votre LLM : "Ma clé SDK publique est X, mon ID de placement est Y" pour qu'il génère du code d'initialisation et de récupération de paywall correct. ::: ### À configurer quand vous êtes prêt \{#set-up-when-ready\} Ces éléments ne sont pas indispensables pour démarrer, mais vous en aurez besoin à mesure que votre intégration mûrit : - **Tests A/B** : Configurez-les sur la page **Placements**. Aucune modification de code nécessaire. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : Ajoutez d'autres appels `getPaywall` avec des IDs de placement différents. - **Intégrations analytics** : Configurez-les sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytics](analytics-integration) et [intégrations attribution](attribution-integration). ## Fournir les docs Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs en fonction de vos questions — pas besoin de coller des URL manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, lancez : ``` npx ctx7 setup ``` Cette commande détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the React Native SDK ``` :::warning Même si Context7 supprime le besoin de coller des liens de docs manuellement, l'ordre d'implémentation reste important. Suivez le [parcours d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne. ::: ### Utiliser les docs en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle doc Adapty en texte brut Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-react-native.md](https://adapty.io/docs/fr/adapty-cursor-react-native.md). Chaque étape du [parcours d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc "Envoyez ceci à votre LLM" avec des liens `.md` à coller. Pour accéder à plus de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Parcours d'implémentation \{#implementation-walkthrough\} Le reste de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devriez voir une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode planification (comme Cursor ou le mode plan de Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et les docs Adapty avant d'écrire du code. Indiquez à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides qu'il devra suivre : - [**Adapty Paywall Builder**](adapty-paywall-builder) : Vous créez des paywalls dans l'éditeur no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](react-native-making-purchases) : Vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats. - [**Mode Observer**](observer-vs-full-mode) : Vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour l'analytics et les intégrations. Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le guide de démarrage](react-native-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez la dépendance Adapty SDK via npm (ou yarn) et activez-la avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans ça. Nous avons des guides d'installation distincts pour Expo et les projets React Native bare — choisissez celui qui correspond à votre configuration. **Guides :** - [Installer avec Expo](sdk-installation-react-native-expo) - [Installer avec React Native bare](sdk-installation-react-native-pure) Envoyez ceci à votre LLM (choisissez celui qui correspond à votre configuration, ou envoyez les deux) : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-react-native-expo.md - https://adapty.io/docs/fr/sdk-installation-react-native-pure.md ``` :::tip[Point de contrôle] - **Attendu :** L'app se compile et tourne sur iOS et Android. Les logs de Metro bundler affichent le log d'activation Adapty. - **Problème fréquent :** "Public API key is missing" → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de la façon dont vous gérez les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **Guides :** - [Activer les achats avec les paywalls (guide de démarrage)](react-native-quickstart-paywalls) - [Récupérer les paywalls Paywall Builder et leur configuration](react-native-get-pb-paywalls) - [Afficher les paywalls](react-native-present-paywalls) - [Gérer les événements de paywall](react-native-handling-events-1) - [Répondre aux actions des boutons](react-native-handle-paywall-actions) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/react-native-quickstart-paywalls.md - https://adapty.io/docs/fr/react-native-get-pb-paywalls.md - https://adapty.io/docs/fr/react-native-present-paywalls.md - https://adapty.io/docs/fr/react-native-handling-events-1.md - https://adapty.io/docs/fr/react-native-handle-paywall-actions.md ``` :::tip[Point de contrôle] - **Attendu :** Le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Problème fréquent :** Paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement à celui du tableau de bord et que le placement a bien une audience assignée. ::: </TabItem> <TabItem value="manual" label="Paywalls manuels"> **Guides :** - [Activer les achats dans votre paywall personnalisé (guide de démarrage)](react-native-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-react-native) - [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-react-native) - [Effectuer des achats](react-native-making-purchases) - [Restaurer les achats](react-native-restore-purchase) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/react-native-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-react-native.md - https://adapty.io/docs/fr/present-remote-config-paywalls-react-native.md - https://adapty.io/docs/fr/react-native-making-purchases.md - https://adapty.io/docs/fr/react-native-restore-purchase.md ``` :::tip[Point de contrôle] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Problème fréquent :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Mode Observer"> **Guides :** - [Présentation du mode Observer](observer-vs-full-mode) - [Implémenter le mode Observer](implement-observer-mode-react-native) - [Signaler les transactions en mode Observer](report-transactions-observer-mode-react-native) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-react-native.md - https://adapty.io/docs/fr/report-transactions-observer-mode-react-native.md ``` :::tip[Point de contrôle] - **Attendu :** Après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans l'**Event Feed** du tableau de bord Adapty. - **Problème fréquent :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez le profil utilisateur pour un niveau d'accès actif afin de restreindre le contenu premium. **Guide :** [Vérifier le statut de l'abonnement](react-native-check-subscription-status) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/react-native-check-subscription-status.md ``` :::tip[Point de contrôle] - **Attendu :** Après un achat sandbox, `profile.accessLevels['premium']?.isActive` retourne `true`. - **Problème fréquent :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Liez les comptes utilisateurs de votre app aux profils Adapty pour que les achats persistent sur tous les appareils. :::important Ignorez cette étape si votre app ne dispose pas d'authentification. ::: **Guide :** [Identifier les utilisateurs](react-native-quickstart-identify) Envoyez ceci à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/react-native-quickstart-identify.md ``` :::tip[Point de contrôle] - **Attendu :** Après avoir appelé `adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Problème fréquent :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution de profil anonyme. ::: ### Préparer la mise en production \{#prepare-for-release\} Une fois votre intégration fonctionnelle en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt. **Guide :** [Checklist de mise en production](release-checklist) Envoyez ceci à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Point de contrôle] - **Attendu :** Tous les éléments de la checklist confirmés : connexions aux stores, notifications serveur, flux d'achat, vérifications des niveaux d'accès et exigences de confidentialité. - **Problème fréquent :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**. ::: ## Fichiers d'index de docs en texte brut \{#plain-text-doc-index-files\} Si vous devez donner à votre LLM un contexte plus large au-delà des pages individuelles, nous hébergeons des fichiers d'index qui listent ou combinent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : Liste toutes les pages avec des liens `.md`. Une [norme émergente](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par ex. ChatGPT), vous devrez télécharger `llms.txt` et l'uploader dans le chat en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : Toute la documentation du site Adapty combinée en un seul fichier. Très volumineux — à utiliser uniquement quand vous avez besoin d'une vue d'ensemble complète. - [`react-native-llms.txt`](https://adapty.io/docs/fr/react-native-llms.txt) et [`react-native-llms-full.txt`](https://adapty.io/docs/fr/react-native-llms-full.txt) spécifiques à React Native : sous-ensembles propres à la plateforme qui économisent des tokens par rapport au site complet. --- # File: react-native-paywalls --- --- title: "Flows et paywalls - React Native" description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre application React Native." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['react-native-get-pb-paywalls', 'react-native-present-paywalls', 'react-native-handling-events-1', 'react-native-handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les flows et paywalls Adapty, consultez notre [guide de démarrage rapide](react-native-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['react-native-quickstart-manual', 'fetch-paywalls-and-products-react-native', 'present-remote-config-paywalls-react-native', 'react-native-making-purchases']} /> Pour d'autres guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](react-native-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['react-native-use-fallback-paywalls', 'react-native-web-paywall']} /> --- # File: react-native-get-pb-paywalls --- --- title: "Récupérer les flows et paywalls - React Native" description: "Récupérez les flows et les paywalls depuis Adapty dans votre application React Native." --- <SDKv4> <MethodPromo method="getFlow" /> Après avoir [conçu votre flow ou votre paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. Notez que cette rubrique concerne les flows et les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez la rubrique [Récupérer les paywalls et les produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-react-native). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des flows et des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-reactnative) dans votre application mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la façon dont cela doit l'être. Vous devez néanmoins récupérer son ID via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Récupérez le flow ou le paywall et créez sa [vue](react-native-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible — idéalement bien avant de l'afficher. La méthode `createFlowView` charge la configuration de la vue et lance en arrière-plan le téléchargement et la mise en cache des images. Plus vous l'appelez tôt, plus ces téléchargements ont de temps pour se terminer. Au moment d'afficher le flow ou le paywall, sa configuration et ses images peuvent déjà être en cache et prêtes à l'affichage. Pour obtenir un flow ou un paywall, utilisez la méthode `getFlow` : ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlow(placementId); // the requested flow/paywall } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |-------------------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne recevront peut-être pas les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir de toujours obtenir la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en arrière-plan.</p><p>Pour Android : Vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas fixer de limite, utilisez `TimeInterval.INFINITE`.</p> | ## Paramètres de réponse \{#response-parameters\} | Paramètre | Description | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objet `AdaptyFlow` contenant les identifiants du flow (`id`, `variationId`), son nom, son placement, ses variantes de paywall (`paywalls`) et les éventuels Remote Configs (`remoteConfigs`). | ## Récupérer la configuration de la vue \{#fetch-the-view-configuration\} :::important Assurez-vous d'activer le bouton **Show on device** dans le builder. Si cette option n'est pas activée, la configuration de la vue ne sera pas disponible. ::: Si le placement a été conçu dans le **Flow Builder** ou le **Paywall Builder**, Adapty génère l'interface utilisateur pour vous. Créez la vue avec `createFlowView`, puis [présentez le flow ou le paywall](react-native-present-paywalls). Si le placement est un paywall personnalisé sans interface dans le Builder, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-react-native) à la place. Dans le SDK React Native, appelez `createFlowView` directement — inutile de récupérer d'abord la configuration de la vue. :::warning Le résultat de la méthode `createFlowView` ne peut être utilisé qu'une seule fois. Si vous devez l'utiliser à nouveau, appelez de nouveau la méthode `createFlowView`. L'appeler deux fois sans recréer la vue peut entraîner l'erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | requis | Un objet `AdaptyFlow` permettant d'obtenir un contrôleur pour le flow/paywall souhaité. | | **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) avec laquelle afficher la vue — par exemple, `en` ou `pt-br`. Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de `en`. Nécessite le SDK 4.0.2 ou version ultérieure. Voir [Localisations et codes de langue](react-native-localizations-and-locale-codes). | | **customTags** | optionnel | Définit un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de placeholders dans le contenu, remplacés dynamiquement par des chaînes spécifiques pour personnaliser le contenu du flow/paywall. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | | **prefetchProducts** | optionnel | À activer pour optimiser le moment d'affichage des produits à l'écran. Lorsque `true`, AdaptyUI récupère automatiquement les produits nécessaires. Par défaut : `false`. | | **android.enableSafeArea** | optionnel | Android uniquement (ignoré sur iOS). À passer en tant qu'objet imbriqué : `android: { enableSafeArea: true }`. Lorsque `true`, la vue du flow applique les marges de zone sécurisée. Par défaut `true` pour la présentation modale (`createFlowView` + `present()`) et `false` pour le composant `AdaptyFlowView` intégré. La valeur par défaut convient à la plupart des cas. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation de flow](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](react-native-localizations-and-locale-codes). ::: Une fois que vous avez la vue, [affichez le flow/paywall](react-native-present-paywalls). ## Récupérer un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En règle générale, les flows et les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `getFlow`, comme indiqué dans la section [Récupérer le flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés. - **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'un chargement plus rapide des flows ou des paywalls, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow/paywall } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs peuvent ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou par un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre flow/paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisé, vous ciblez ces éléments par leur identifiant et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement de l'image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK React Native Adapty vers la version 3.8.0 ou supérieure. ::: Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via un simple dictionnaire : ```javascript const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createFlowView(flow, { customAssets }) ``` :::note Si une ressource est introuvable, le flow/paywall reviendra à son apparence par défaut. ::: </SDKv4> <SDKv3> Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape de ce processus consiste à récupérer le paywall associé au placement et sa configuration d'affichage, comme décrit ci-dessous. :::warning Le nouveau Paywall Builder fonctionne avec React Native SDK version 3.0 ou supérieure. ::: Veuillez noter que ce sujet concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez le sujet [Récupérer les paywalls et produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-react-native). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-reactnative) dans votre application mobile. </details> ## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration d'affichage](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour récupérer un paywall, utilisez la méthode `getPaywall` : ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywall(placementId, locale); // the requested paywall } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |-------------------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs sont confrontés à une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en coulisses.</p><p>Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.</p> | ## Paramètres de réponse \{#response-parameters\} | Paramètre | Description | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objet [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) contenant une liste d'identifiants de produits, l'identifiant du paywall, la Remote Config, ainsi que plusieurs autres propriétés. | ## Récupérer la configuration de vue d'un paywall conçu avec le Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible à la récupération. ::: Après avoir récupéré le paywall, vérifiez s'il inclut une `ViewConfiguration`, ce qui indique qu'il a été créé avec le Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si la `ViewConfiguration` est présente, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-react-native). Dans le SDK React Native, appelez directement la méthode `createPaywallView` sans récupérer manuellement la configuration de la vue au préalable. :::warning Le résultat de la méthode `createPaywallView` ne peut être utilisé qu'une seule fois. Si vous devez l'utiliser à nouveau, appelez à nouveau la méthode `createPaywallView`. L'appeler deux fois sans recréer peut entraîner l'erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createPaywallView} from 'react-native-adapty/dist/ui'; if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { //use your custom logic } ``` Paramètres : | Paramètre | Présence | Description | | :------------------- | :------- | :----------------------------------------------------------- | | **paywall** | obligatoire | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. | | **customTags** | optionnel | Définit un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de marqueurs de substitution dans le contenu du paywall, remplacés dynamiquement par des chaînes spécifiques pour personnaliser le contenu du paywall. Consultez la rubrique Custom tags in paywall builder pour plus de détails. | | **prefetchProducts** | optionnel | À activer pour optimiser le moment d'affichage des produits à l'écran. Lorsque la valeur est `true`, AdaptyUI récupère automatiquement les produits nécessaires. Par défaut : `false`. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](react-native-localizations-and-locale-codes). ::: Une fois que vous avez la vue, [affichez le paywall](react-native-present-paywalls). ## Récupérer un paywall pour l'audience par défaut afin d'accélérer le chargement \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité descendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et futures), vous risquez de rencontrer des difficultés. Il vous faudra soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent avoir des problèmes d'affichage. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.2 du SDK React Native. ::: | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de locale](react-native-localizations-and-locale-codes) pour plus d'informations sur les codes de locale et notre recommandation d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne verront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter des requêtes réseau.</p><p></p><p>Notez que le cache est conservé après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos de votre paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des ID prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leur ID et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans le tableau de bord Adapty. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK React Native d'Adapty vers la version 3.8.0 ou supérieure. ::: Voici un exemple illustrant comment fournir des ressources personnalisées via un simple dictionnaire : ```javascript const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createPaywallView(paywall, { customAssets }) ``` :::note Si une ressource est introuvable, le paywall reviendra à son apparence par défaut. ::: </SDKv3> --- # File: react-native-present-paywalls --- --- title: "Afficher les flows et paywalls - React Native" description: "Présentez des flows et des paywalls aux utilisateurs de votre application React Native avec Adapty." --- <SDKv4> <MethodPromo method="getFlow" label="Display flows and paywalls" /> Si vous avez créé un flow ou un paywall dans le Flow Builder, vous n'avez pas besoin de vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow contient à la fois ce qui doit être affiché et comment cela doit être affiché. Avant de commencer, assurez-vous que : 1. Vous avez [créé un flow ou un paywall](create-paywall). 2. Vous l'avez ajouté à un [placement](placements). 3. Vous avez [récupéré le flow et préparé la vue](react-native-get-pb-paywalls). :::warning Ce guide concerne **les flows et les paywalls Paywall Builder** uniquement, qui nécessitent le SDK v4.0 ou une version ultérieure. Le processus de présentation des flows diffère pour les paywalls Remote Config. - Pour présenter des **paywalls Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls). ::: Le SDK Adapty React Native propose deux façons de présenter les flows et les paywalls : - **Composant React** : un composant intégré vous permet de l'incorporer dans l'architecture et le système de navigation de votre application. - **Présentation modale** ## Composant React \{#react-component\} Pour intégrer un flow dans votre arborescence de composants existante, utilisez le composant `AdaptyFlowView` directement dans votre hiérarchie de composants React Native. Le composant intégré vous permet de l'incorporer dans l'architecture et le système de navigation de votre application. :::tip Le composant `AdaptyFlowView` crée sa vue au moment du rendu, c'est-à-dire lorsque la configuration et les images sont chargées. Pour les précharger, appelez [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) pour le même flow plus tôt dans votre application. Le composant réutilise alors les données en cache et s'affiche sans attendre les téléchargements. ::: ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const flowParams = useMemo(() => ({ loadTimeoutMs: 3000, locale: 'en', // The localization to render the flow with }), []); const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []); const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []); const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []); const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => {}, []); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyFlowView flow={flow} params={flowParams} style={styles.flow} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onAppeared={onAppeared} onError={onError} onLoadingProductsFailed={onLoadingProductsFailed} onCustomAction={onCustomAction} onUrlPress={onUrlPress} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` ## Présentation modale \{#modal-presentation\} Pour afficher un flow en tant qu'écran autonome, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous avez besoin d'afficher le flow à nouveau, appelez `createFlowView` une fois de plus pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer est interdit. Cela entraînera une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers title="React Native (TSX)" const view = await createFlowView(flow); // Optional: handle flow events (close, purchase, restore, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important Appeler `setEventHandlers` plusieurs fois écrasera les gestionnaires que vous fournissez, remplaçant à la fois les gestionnaires par défaut et ceux précédemment définis pour ces événements spécifiques. ::: ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez comment le flow est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## Utiliser un minuteur défini par le développeur \{#use-developer-defined-timer\} Pour utiliser des minuteurs définis par le développeur dans votre application mobile, utilisez le `timerId`, dans cet exemple `CUSTOM_TIMER_NY`, le **Timer ID** du minuteur défini par le développeur que vous avez configuré dans l'Adapty Dashboard. Cela garantit que votre application met à jour dynamiquement le minuteur avec la valeur correcte — comme `13d 09h 03m 34s` (calculée comme l'heure de fin du minuteur, par exemple le Jour de l'An, moins l'heure actuelle). <Tabs> <TabItem value="component" label="React component"> ```typescript showLineNumbers title="React Native (TSX)" const flowParams = { customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } }; <AdaptyFlowView flow={flow} params={flowParams} // ... your event handlers /> ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createFlowView(flow, { customTimers }); ``` </TabItem> </Tabs> Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** du minuteur défini par le développeur dans l'Adapty Dashboard. Le `timerResolver` permet à votre application de mettre à jour dynamiquement le minuteur avec la valeur correcte — par exemple `13j 09h 03m 34s` (calculée comme la date de fin du minuteur, comme le Jour de l'An, moins l'heure actuelle). ## Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'une vue de flow est affichée sur Android. Sur Android, les alertes RN classiques apparaissent derrière la vue de flow, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du flow sur toutes les plateformes. ```typescript showLineNumbers title="React Native (TSX)" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the flow await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## Remplacer un abonnement par un autre \{#replace-one-subscription-with-another\} Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre est déjà actif sur Android, vous pouvez contrôler la façon dont ce nouvel achat doit être traité en passant des paramètres de mise à jour d'abonnement lors de la création de la vue flow. Pour remplacer l'abonnement actuel par le nouveau, utilisez `productPurchaseParams` dans `createFlowView` avec les paramètres `oldSubVendorProductId` et `prorationMode`. ```typescript showLineNumbers title="React Native (TSX)" const productPurchaseParams = flow.paywalls .flatMap((variation) => variation.productIdentifiers) .map((productId) => { let params = {}; if (Platform.OS === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createFlowView(flow, { productPurchaseParams }); ``` </SDKv4> <SDKv3> Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez [créé un paywall](create-paywall). 2. Vous avez ajouté le paywall à un [placement](placements). 3. Vous avez [récupéré le paywall et préparé la vue](react-native-get-pb-paywalls). :::warning Ce guide concerne uniquement les **paywalls du nouveau Paywall Builder**, qui nécessitent le SDK v3.0 ou une version ultérieure. La procédure de présentation des paywalls diffère selon la version du Paywall Builder utilisée pour les concevoir et selon les paywalls avec Remote Config. - Pour présenter des **paywalls avec Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls). ::: Le SDK Adapty React Native propose deux façons de présenter les paywalls : - **Composant React** : un composant intégré que vous pouvez incorporer à l'architecture et au système de navigation de votre application. - **Présentation modale** ## Composant React \{#react-component\} :::note L'approche par **composant React** nécessite le SDK 3.14.0 ou une version ultérieure. ::: Pour intégrer un paywall dans votre arborescence de composants existante, utilisez directement le composant `AdaptyPaywallView` dans la hiérarchie de composants React Native. Le composant intégré vous permet de l'incorporer dans l'architecture et le système de navigation de votre application. :::note Sur Android, si le paywall ne s'étend pas derrière la barre de statut, un overlay visuel peut apparaître en haut. Nous vous recommandons de le désactiver pour vos paywalls. Voir [Overlay visuel en haut du paywall (Android)](#visual-overlay-at-the-top-of-the-paywall-android). ::: ```typescript showLineNumbers title="React Native (TSX)" function MyPaywall({ paywall }) { const paywallParams = useMemo(() => ({ loadTimeoutMs: 3000, }), []); const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []); const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []); const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []); const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => {}, []); const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyPaywallView paywall={paywall} params={paywallParams} style={styles.paywall} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onPaywallShown={onPaywallShown} onRenderingFailed={onRenderingFailed} onLoadingProductsFailed={onLoadingProductsFailed} onCustomAction={onCustomAction} onUrlPress={onUrlPress} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` ## Présentation modale \{#modal-presentation\} Pour afficher un paywall en tant qu'écran autonome, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createPaywallView`](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous avez besoin d'afficher le paywall à nouveau, appelez `createPaywallView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer est interdit. Cela provoquera une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers title="React Native (TSX)" const view = await createPaywallView(paywall); // Optional: handle paywall events (close, purchase, restore, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important 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. ::: ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## Utiliser un minuteur défini par le développeur \{#use-developer-defined-timer\} Pour utiliser des minuteurs définis par le développeur dans votre application mobile, utilisez le `timerId`, dans cet exemple `CUSTOM_TIMER_NY`, le **Timer ID** du minuteur défini par le développeur que vous avez configuré dans l'Adapty Dashboard. Cela permet à votre application de mettre à jour dynamiquement le minuteur avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme la date de fin du minuteur, par exemple le Jour de l'An, moins l'heure actuelle). <Tabs> <TabItem value="component" label="React component"> ```typescript showLineNumbers title="React Native (TSX)" const paywallParams = { customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } }; <AdaptyPaywallView paywall={paywall} params={paywallParams} // ... your event handlers /> ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createPaywallView(paywall, { customTimers }); ``` </TabItem> </Tabs> Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** du timer défini par le développeur que vous avez configuré dans l'Adapty Dashboard. Le `timerResolver` permet à votre application de mettre à jour dynamiquement le timer avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme la date de fin du timer, comme le Jour de l'An, moins l'heure actuelle). ## Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue d'alerte natives lorsqu'une vue de paywall est affichée sur Android. Sur Android, les alertes RN classiques apparaissent derrière la vue du paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes. ```typescript showLineNumbers title="React Native (TSX)" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## Remplacer un abonnement par un autre \{#replace-one-subscription-with-another\} Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre abonnement est actif sur Android, vous pouvez contrôler la façon dont le nouvel achat doit être traité en passant des paramètres de mise à jour d'abonnement lors de la création de la vue paywall. Pour remplacer l'abonnement actuel par le nouveau, utilisez `productPurchaseParams` dans `createPaywallView` avec les paramètres `oldSubVendorProductId` et `prorationMode`. ```typescript showLineNumbers title="React Native (TSX)" const productPurchaseParams = paywall.productIdentifiers.map((productId) => { let params = {}; if (Platform.OS === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createPaywallView(paywall, { productPurchaseParams }); ``` ## Résolution des problèmes \{#troubleshooting\} ### Superposition visuelle en haut du paywall (Android) \{#visual-overlay-at-the-top-of-the-paywall-android\} :::note Ce paramètre est pris en charge à partir du SDK React Native 3.15.5 et n'est disponible que dans les projets React Native en mode bare. Si vous utilisez un workflow géré par Expo, vous ne pouvez pas ajouter cette ressource Android directement. Pour appliquer ce paramètre, vous devez créer un plugin de configuration Expo personnalisé qui ajoute la ressource Android correspondante et l'enregistrer dans app.config.js. Cela est nécessaire car Expo gère le projet Android natif à votre place. ::: Si `AdaptyPaywallView` ne s'étend pas derrière la barre de statut, une superposition visuelle peut quand même apparaître en haut. Pour la supprimer, ajoutez la ressource booléenne suivante à votre application : 1. Accédez à `android/app/src/main/res/values`. S'il n'existe pas de fichier `bools.xml`, créez-le. 2. Ajoutez la ressource suivante : ```xml <resources> <bool name="adapty_paywall_enable_safe_area_paddings">false</bool> </resources> ``` Notez que ces modifications s'appliquent globalement à tous les paywalls de votre application. </SDKv3> --- # File: react-native-handle-paywall-actions --- --- title: "Répondre aux actions des flows - React Native" description: "Gérez les actions des boutons des flows et paywalls dans React Native avec Adapty pour une meilleure monétisation de votre app." --- <SDKv4> Si vous créez des flows ou des paywalls avec le Flow Builder ou le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le flow/paywall builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et préexistantes dans votre code. :::warning **Les achats, restaurations, fermetures de flows/paywalls et ouvertures d'URL sont gérés automatiquement.** Vous pouvez configurer leur comportement par défaut ou implémenter des réponses pour les actions personnalisées. ::: :::note Le SDK expose un gestionnaire de flow `onRequestPermission` pour les demandes de permissions système, comme les notifications push ou l'accès à la caméra. Les flows ne déclenchent pas encore ces demandes, vous n'avez donc pas besoin de l'implémenter pour l'instant. ::: ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton qui fermera votre flow ou paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le flow ou le paywall. :::info Dans le SDK React Native, l'action `close` déclenche par défaut la fermeture du flow ou du paywall. Vous pouvez toutefois modifier ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un flow peut déclencher l'ouverture d'un autre. ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez l'action de fermeture via les props de gestionnaire d'événements individuels : ```javascript function MyPaywall({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => { // Handle close button press - navigate away or hide component navigation.goBack(); }, [navigation]); return ( <AdaptyFlowView flow={flow} style={styles.container} onCloseButtonPress={onCloseButtonPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez le gestionnaire de fermeture : ```javascript const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow flow or paywall closing } }); ``` </TabItem> </Tabs> ## Ouvrir des URL depuis les flows et les paywalls \{#open-urls-from-flows-and-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, conditions d'utilisation et restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même manière que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK React Native, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois modifier ce comportement dans votre code si nécessaire. ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez l'ouverture d'URL via la prop de gestionnaire d'événements : ```javascript function MyPaywall({ flow }) { const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onUrlPress={onUrlPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez le gestionnaire d'URL : ```javascript const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { Linking.openURL(url); return false; // Keep flow or paywall open }, }); ``` </TabItem> </Tabs> ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre app, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall : <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez les actions personnalisées via la prop de gestionnaire d'événements : ```javascript function MyPaywall({ flow }) { const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez les gestionnaires d'actions personnalisées : ```javascript const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, }); ``` </TabItem> </Tabs> </SDKv4> <SDKv3> Si vous créez des paywalls avec le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le paywall builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre app pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et préexistantes dans votre code. :::warning **Seuls les achats, restaurations, fermetures de paywalls et ouvertures d'URL sont gérés automatiquement.** Toutes les autres actions de boutons nécessitent une implémentation appropriée dans le code de l'app. ::: ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton qui fermera votre paywall : 1. Dans le paywall builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le paywall. :::info Dans le SDK React Native, l'action `close` déclenche par défaut la fermeture du paywall. Vous pouvez toutefois modifier ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un paywall peut déclencher l'ouverture d'un autre. ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez l'action de fermeture via les props de gestionnaire d'événements individuels : ```javascript function MyPaywall({ paywall }) { const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => { // Handle close button press - navigate away or hide component navigation.goBack(); }, [navigation]); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCloseButtonPress={onCloseButtonPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez le gestionnaire de fermeture : ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow paywall closing } }); ``` </TabItem> </Tabs> ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, conditions d'utilisation et restauration des achats), ajoutez un élément **Link** dans le paywall builder et gérez-le de la même manière que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. :::info Dans le SDK React Native, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois modifier ce comportement dans votre code si nécessaire. ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez l'ouverture d'URL via la prop de gestionnaire d'événements : ```javascript function MyPaywall({ paywall }) { const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onUrlPress={onUrlPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez le gestionnaire d'URL : ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { Linking.openURL(url); return false; // Keep paywall open }, }); ``` </TabItem> </Tabs> ## Se connecter à l'app \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre app : 1. Dans le paywall builder, ajoutez un bouton et assignez-lui l'action **Login**. 2. Dans le code de votre app, implémentez un gestionnaire pour l'action `login` qui identifie votre utilisateur. <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez la connexion via la prop de gestionnaire d'événements : ```javascript function MyPaywall({ paywall }) { const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => { if (actionId === 'login') { navigation.navigate('Login'); } }, [navigation]); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez le gestionnaire de connexion : ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'login') { navigation.navigate('Login'); } } }); ``` </TabItem> </Tabs> ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre app, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre paywall : <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, gérez les actions personnalisées via la prop de gestionnaire d'événements : ```javascript function MyPaywall({ paywall }) { const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => { if (actionId === 'openNewPaywall') { // Display another paywall } }, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez les gestionnaires d'actions personnalisées : ```javascript const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another paywall } }, }); ``` </TabItem> </Tabs> </SDKv3> --- # File: react-native-handling-events-1 --- --- title: "Gérer les événements de flow et de paywall - React Native" description: "Gérez les événements de flow et de paywall dans votre application React Native avec le SDK d'Adapty." --- <SDKv4> :::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 de boutons](react-native-handle-paywall-actions) 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 : <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour un composant React, vous gérez les événements via des props de gestionnaire d'événements individuelles dans le composant `AdaptyFlowView` : ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []); const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []); const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []); const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url, openIn) => { adapty.openWebUrl(url, openIn); return false; }, []); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onAppeared={onAppeared} onError={onError} onLoadingProductsFailed={onLoadingProductsFailed} onUrlPress={onUrlPress} onCustomAction={onCustomAction} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour une présentation modale, implémentez la méthode des gestionnaires d'événements. :::important Appeler `setEventHandlers` plusieurs fois remplacera les gestionnaires que vous fournissez, en remplaçant à la fois les gestionnaires par défaut et ceux définis précédemment pour ces événements spécifiques. ::: ```javascript showLineNumbers title="React Native (TSX)" const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; }, onAndroidSystemBack() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type !== 'user_cancelled'; }, onPurchaseStarted(product) { /***/}, onPurchaseFailed(error, product) { /***/ }, onRestoreCompleted(profile) { /***/ }, onRestoreFailed(error) { /***/ }, onProductSelected(productId) { /***/}, onError(error) { /***/ }, onLoadingProductsFailed(error) { /***/ }, onUrlPress(url, openIn) { adapty.openWebUrl(url, openIn); return false; // Keep flow open }, onAppeared() { /***/ }, onDisappeared() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` </TabItem> </Tabs> <Details> <summary>Exemples d'événements (Cliquez pour agrandir)</summary> ```javascript // 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 } ``` </Details> 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 \{#event-handlers\} | Gestionnaire d'événements | Description | |:---------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | Déclenché lorsqu'un utilisateur effectue une action personnalisée, par exemple en cliquant sur un [bouton personnalisé](paywall-buttons). | | **onUrlPress** | Déclenché lorsqu'un utilisateur clique sur une URL dans votre flow. | | **onAndroidSystemBack** | Présentation modale uniquement : déclenché lorsqu'un utilisateur appuie sur le bouton système Android **Retour**. | | **onCloseButtonPress** | Dé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. | | **onPurchaseCompleted** | Dé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`. | | **onPurchaseStarted** | Déclenché lorsqu'un utilisateur appuie sur le bouton d'action « Acheter » pour démarrer le processus d'achat. | | **onPurchaseFailed** | Dé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. | | **onRestoreStarted** | Déclenché lorsqu'un utilisateur lance un processus de restauration d'achat. | | **onRestoreCompleted** | Dé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](react-native-listen-subscription-changes) pour savoir comment le vérifier. | | **onRestoreFailed** | Déclenché lorsque le processus de restauration échoue et fournit une `AdaptyError`. | | **onProductSelected** | Dé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. | | **onError** | Dé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. | | **onLoadingProductsFailed** | Dé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. | | **onAppeared** | Déclenché lorsque le flow est affiché à l'utilisateur. Sur iOS, également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un flow et qu'un paywall web s'ouvre dans un navigateur intégré à l'application. | | **onDisappeared** | Présentation modale uniquement : déclenché lorsque le flow est fermé par l'utilisateur. Sur iOS, également déclenché lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un flow dans un navigateur intégré disparaît de l'écran. | | **onWebPaymentNavigationFinished** | Déclenché après une tentative d'ouverture d'un [paywall web](web-paywall) pour un achat, qu'elle soit réussie ou non. | | **onAnalytics** | Ré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. | | **onRequestAppReview** | Ré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. | | **onRequestPermission** | Ré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. | | **onObserverPurchaseInitiated** | Mode 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](#handle-purchases-in-observer-mode) ci-dessous. | | **onObserverRestoreInitiated** | Mode 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](#handle-purchases-in-observer-mode) ci-dessous. | ### Gérer les achats en mode observateur \{#handle-purchases-in-observer-mode\} Si vous avez activé le SDK en [mode observateur](implement-observer-mode-react-native) (`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](report-transactions-observer-mode-react-native) à Adapty ensuite. ```typescript showLineNumbers 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; }, }); ``` </SDKv4> <SDKv3> :::important 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](react-native-handle-paywall-actions) pour en savoir plus. ::: Les paywalls configurés avec le [Paywall Builder](adapty-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. :::warning 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 : <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour le composant React, vous gérez les événements via des props de gestionnaire d'événements individuels dans le composant `AdaptyPaywallView` : ```typescript showLineNumbers title="React Native (TSX)" function MyPaywall({ paywall }) { const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []); const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []); const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []); const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onPaywallShown={onPaywallShown} onRenderingFailed={onRenderingFailed} onLoadingProductsFailed={onLoadingProductsFailed} onUrlPress={onUrlPress} onCustomAction={onCustomAction} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour la présentation modale, implémentez la méthode des gestionnaires d'événements. :::important Appeler `setEventHandlers` plusieurs fois écrasera les gestionnaires que vous fournissez, en remplaçant à la fois les gestionnaires par défaut et ceux précédemment définis pour ces événements spécifiques. ::: ```javascript showLineNumbers title="React Native (TSX)" const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; }, onAndroidSystemBack() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type !== 'user_cancelled'; }, onPurchaseStarted(product) { /***/}, onPurchaseFailed(error) { /***/ }, onRestoreCompleted(profile) { /***/ }, onRestoreFailed(error) { /***/ }, onProductSelected(productId) { /***/}, onRenderingFailed(error) { /***/ }, onLoadingProductsFailed(error) { /***/ }, onUrlPress(url) { Linking.openURL(url); return false; // Keep paywall open }, onPaywallShown() { /***/ }, onPaywallClosed() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` </TabItem> </Tabs> <Details> <summary>Exemples d'événements (Cliquer pour développer)</summary> ```javascript // 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 } ``` </Details> 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 \{#event-handlers\} | Gestionnaire d'événements | Description | |:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | Déclenché lorsqu'un utilisateur effectue une action personnalisée, par exemple en cliquant sur un [bouton personnalisé](paywall-buttons). | | **onUrlPress** | Déclenché lorsqu'un utilisateur clique sur une URL dans votre paywall. | | **onAndroidSystemBack** | Présentation modale uniquement : déclenché lorsqu'un utilisateur appuie sur le bouton système Android **Back**. | | **onCloseButtonPress** | Dé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. | | **onPurchaseCompleted** | Dé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`. | | **onPurchaseStarted** | Déclenché lorsqu'un utilisateur appuie sur le bouton d'action « Acheter » pour lancer le processus d'achat. | | **onPurchaseFailed** | Dé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. | | **onRestoreStarted** | Déclenché lorsqu'un utilisateur démarre un processus de restauration d'achat. | | **onRestoreCompleted** | Dé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](react-native-listen-subscription-changes) pour savoir comment le vérifier. | | **onRestoreFailed** | Déclenché lorsque le processus de restauration échoue et fournit `AdaptyError`. | | **onProductSelected** | Déclenché lorsqu'un produit du paywall est sélectionné, ce qui vous permet de suivre ce que l'utilisateur choisit avant l'achat. | | **onRenderingFailed** | Dé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. | | **onLoadingProductsFailed** | Dé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. | | **onPaywallShown** | Déclenché lorsque le paywall est affiché à l'utilisateur. Sur iOS, également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall et qu'un paywall web s'ouvre dans un navigateur intégré. | | **onPaywallClosed** | Présentation modale uniquement : déclenché lorsque le paywall est fermé par l'utilisateur. Sur iOS, également déclenché lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. | | **onWebPaymentNavigationFinished** | Déclenché après une tentative d'ouverture d'un [paywall web](web-paywall) pour un achat, qu'elle soit réussie ou non. | </SDKv3> --- # File: react-native-use-fallback-paywalls --- --- title: "Utiliser les paywalls de secours dans React Native" description: "Configurez des paywalls de secours dans votre projet React Native pour gérer les scénarios hors ligne." --- Les paywalls de secours d'Adapty fonctionnent aussi bien dans les projets **Expo** que dans les projets **React Native pur**. Ces environnements utilisent des systèmes de build différents, donc les étapes de configuration diffèrent également. Choisissez le guide de configuration qui correspond à votre projet : <CustomDocCardList /> --- # File: react-native-use-fallback-paywalls-expo --- --- title: "Utiliser les paywalls de secours dans un projet Expo" description: "Configurez les paywalls de secours dans un projet Expo React Native via le plugin de configuration react-native-adapty." --- :::important Ce guide s'applique aux **projets Expo**. Si vous utilisez **React Native pur (sans Expo)**, suivez plutôt le [guide de secours pour React Native pur](react-native-use-fallback-paywalls-pure). ::: To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: Le SDK Adapty lit le fichier de secours depuis le bundle **natif** — une ressource iOS à l'intérieur du package `.app`, ou une entrée sous `android/app/src/main/assets/`. Dans un projet Expo, `npx expo prebuild --clean` régénère ces répertoires à chaque exécution, il n'est donc pas possible d'y déposer les fichiers manuellement. Le plugin de configuration `react-native-adapty` intègre le fichier dans le bundle natif à votre place. :::tip Une configuration complète et fonctionnelle est disponible dans l'exemple d'application [`FocusJournalExpo`](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo). ::: ## Configuration \{#configuration\} 1. Placez les fichiers JSON de secours n'importe où dans votre projet — généralement à côté des autres ressources : ``` <your-project>/ └── assets/ ├── ios_fallback.json └── android_fallback.json ``` 2. Ajoutez l'option `fallbackFile` à l'entrée `react-native-adapty` dans `app.json` (ou `app.config.js`). Chaque clé de plateforme est optionnelle — ne configurez que les plateformes dont vous avez besoin : ```json title="app.json" { "expo": { "plugins": [ [ "react-native-adapty", { "fallbackFile": { "ios": "./assets/ios_fallback.json", "android": "./assets/android_fallback.json" } } ] ] } } ``` :::note Adapty exporte un fichier JSON de secours différent pour chaque plateforme — les identifiants de produits Apple sur iOS, les identifiants de produits Google Play sur Android. Pointez chaque plateforme vers son propre fichier. ::: 3. Régénérez les projets natifs : ```sh title="Shell" npx expo prebuild ``` Le plugin ajoute le fichier iOS aux ressources du bundle du projet Xcode et copie le fichier Android dans `android/app/src/main/assets/`. La sortie du prebuild inclut des lignes comme : ``` [react-native-adapty] Registered ios_fallback.json as iOS bundle resource [react-native-adapty] Copied android_fallback.json to android assets/ ``` 4. Enregistrez le fichier auprès du SDK au moment de l'exécution : ```typescript showLineNumbers title="App.tsx" import { adapty } from 'react-native-adapty'; await adapty.activate('PUBLIC_SDK_KEY'); await adapty.setFallback({ ios: { fileName: 'ios_fallback.json' }, android: { relativeAssetPath: 'android_fallback.json' }, }); ``` Les noms de fichiers passés à `setFallback` doivent correspondre aux noms de base des fichiers configurés sous `fallbackFile`. :::important `setFallback` doit s'exécuter avant que le SDK ne récupère le flow, le paywall ou l'onboarding cible. ::: ## Vérification \{#verification\} Après `npx expo prebuild`, vérifiez les deux plateformes : - **Android** : Listez le contenu de `android/app/src/main/assets/`. Le fichier configuré sous `fallbackFile.android` doit être présent, et le nom de fichier réservé à iOS ne doit pas apparaître ici. - **iOS** : Recherchez le nom de fichier iOS dans `ios/<ProjectName>.xcodeproj/project.pbxproj`. Il doit apparaître dans `PBXFileReference`, le groupe `Resources`, et `PBXResourcesBuildPhase`. Le nom de fichier réservé à Android ne doit pas apparaître dans `project.pbxproj`. --- # File: react-native-use-fallback-paywalls-pure --- --- title: "Utiliser les paywalls de secours dans un projet React Native pur" description: "Configurer les paywalls de secours dans un projet React Native pur (non-Expo)." --- :::important Ce guide s'applique aux **projets React Native purs (non-Expo)**. Si vous utilisez **Expo**, suivez plutôt le [guide de secours pour Expo](react-native-use-fallback-paywalls-expo). ::: To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration ### Android 1. Ajoutez le fichier de configuration de secours à votre application. Choisissez l'un des répertoires suivants : * **android/app/src/main/assets/** * **android/app/src/main/res/raw/** Remarque : le dossier `res/raw` impose des conventions de nommage particulières (commencer par une lettre, pas de majuscules, pas de caractères spéciaux sauf le tiret bas, et pas d'espaces dans les noms). 2. Mettez à jour la propriété `android` de la constante `FileLocation` : * Si le fichier se trouve dans le répertoire `assets`, indiquez son chemin relatif au répertoire. * Si le fichier se trouve dans le répertoire `res/raw`, indiquez le nom du fichier sans l'extension. ### iOS 1. Ajoutez le fichier JSON de secours au bundle de votre projet : ouvrez le menu **File** dans XCode et sélectionnez l'option **Add Files to "YourProjectName"**. 2. Passez le nom de votre fichier de configuration à la propriété `ios` de la constante `FileLocation`. ## Exemple <Tabs groupId="current-os" queryString> <TabItem value="current" label="Current (v3.8+)" default> ```typescript showLineNumbers //after v3.8 const fileLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } } await adapty.setFallback(fileLocation); ``` </TabItem> <TabItem value="old" label="Legacy (before v3.8)"> ```typescript showLineNumbers //Legacy (before v3.8) const paywallsLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } } await adapty.setFallbackPaywalls(paywallsLocation); ``` </TabItem> </Tabs> Paramètres : | Paramètre | Description | | :------------------- | :------------------------------------------------------- | | **fileLocation** | Objet représentant l'emplacement du fichier de configuration de secours. | --- # File: react-native-localizations-and-locale-codes --- --- title: "Utiliser les localisations et les codes de langue dans le SDK React Native" description: "Découvrez comment localiser les paywalls dans votre application React Native avec le SDK Adapty." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu quand Adapty choisit la localisation d'un flow, et quand vous lisez un Remote Config pour un paywall personnalisé. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. C'est pourquoi Adapty s'appuie sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous aide à anticiper quelle localisation un utilisateur reçoit. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des traits d'union. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de locale \{#locale-code-matching\} Quand Adapty recherche la localisation correspondant à la locale d'un utilisateur, voici ce qui se passe : 1. La chaîne de locale est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de locale correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est trouvée non plus, Adapty renvoie le contenu dans la locale par défaut du flow Cette approche permet à `'pt_BR'`, `pt-BR` et `pt-br` de pointer vers la même localisation. ## Implémentation des localisations \{#implementing-localizations\} Dans le SDK v4, vous ne passez pas de code de langue lors de la récupération d'un flow — `getFlow` retourne le flow avec toutes ses localisations, et Adapty en applique une lors de la construction de la vue du flow. - **Flows créés dans le builder** : le SDK ne lit pas les paramètres régionaux de l'appareil, vous devez donc les résoudre dans votre application et les passer via le paramètre `locale` de `createFlowView`, ou dans la prop `params` du composant intégré `AdaptyFlowView`. Ce paramètre est facultatif — si vous l'omettez, le flow s'affiche en `en`, ou dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow ne dispose pas de localisation `en`. Si vous demandez une localisation que le flow ne possède pas, la vue revient silencieusement à la locale par défaut, et les chaînes manquantes dans la localisation choisie sont tirées de cette locale par défaut. ```typescript showLineNumbers import { createFlowView } from 'react-native-adapty'; const view = await createFlowView(flow, { locale: 'es' }); ``` `view.locale` indique la localisation avec laquelle la vue a été réellement construite — la locale que vous avez demandée si cette localisation existe, ou la locale par défaut du flow sinon. Le paramètre `locale` et `view.locale` nécessitent le SDK React Native 4.0.2 ou version ultérieure, et `view.locale` est `undefined` sur les versions antérieures. - **Paywalls personnalisés (Remote Config)** : `getFlow` renvoie chaque localisation configurée dans `flow.remoteConfigs`. Chaque entrée contient un code `lang` et un objet `data`. Sélectionnez l'entrée correspondant à l'utilisateur, avec votre propre mécanisme de fallback : ```typescript showLineNumbers const flow = await adapty.getFlow('placement_id'); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; // read your values from config?.data ``` Les règles de correspondance des codes de locale décrites ci-dessus expliquent comment Adapty normalise les codes `lang` stockés dans chaque Remote Config. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu dans plusieurs situations — par exemple, lorsque vous souhaitez récupérer le bon paywall pour la localisation actuelle de votre application. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Nous nous appuyons donc sur un standard interne commun à toutes les plateformes que nous supportons. Cela dit, justement parce que ces codes sont complexes, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin de toujours recevoir ce que vous attendez. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty reçoit un appel du SDK côté client avec le code de langue et commence à rechercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de langue reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. On recherche ensuite la localisation dont le code de langue correspond exactement 3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, on renvoie le contenu dans la langue par défaut du paywall De cette façon, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat. ## Mise en œuvre des localisations : méthode recommandée \{#implementing-localizations-recommended-way\} Si vous vous interrogez sur les localisations, il y a de bonnes chances que vous gériez déjà des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de localisation. Extrayez ensuite la valeur de cette clé lors de l'appel à notre SDK, comme ceci : ```javascript showLineNumbers // 1. Modify your localization files (e.g., using react-i18next) /* 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 const MyComponent = () => { const { t } = useTranslation(); const fetchPaywall = async () => { const locale = t('adapty_paywalls_locale'); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; }; ``` C'est ainsi que vous vous assurez d'avoir un contrôle total sur la localisation qui sera récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : l'autre approche \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de langue pour chaque localisation. Cela implique d'extraire un code de langue depuis l'appareil, par exemple via [`react-native-localize`](https://github.com/zoontek/react-native-localize) : ```javascript showLineNumbers const fetchPaywall = async () => { // getLocales() returns the user's preferred locales in BCP-47 format (e.g., 'en-US', 'pt-BR') const locale = RNLocalize.getLocales()[0].languageTag; // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; ``` Notez que nous ne recommandons pas cette approche pour plusieurs raisons : 1. Sur iOS, les langues préférées et la locale régionale actuelle ne sont pas identiques. Pour que la localisation soit correctement sélectionnée, vous devrez soit vous appuyer sur la logique de résolution d'Apple — qui fonctionne nativement avec l'approche recommandée utilisant des fichiers de chaînes localisées — soit la recréer vous-même. 2. La locale de l'appareil peut ne correspondre à aucune localisation configurée dans Adapty. Dans ce cas, le SDK utilise en priorité une correspondance sur le premier sous-tag ou, en dernier recours, `en` — ce qui n'est peut-être pas la langue par défaut souhaitée pour cet utilisateur. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: react-native-web-paywall --- --- title: "Implémenter les paywalls web" description: "Apprenez à implémenter les paywalls web dans votre application React Native avec le SDK Adapty." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé le SDK Adapty version 3.6.1 ou ultérieure. ::: ## Ouvrir les paywalls web \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `.openWebPaywall` : 1. Génère une URL unique permettant à Adapty d'associer un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `.getProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. ```typescript showLineNumbers title="React Native (TSX)" try { await adapty.openWebPaywall(product); } catch (error) { console.warn('Failed to open web paywall:', error); } ``` :::note Il existe deux versions de la méthode `openWebPaywall` : 1. `openWebPaywall(product)` qui génère des URL à partir du paywall et ajoute également les données du produit aux URL. 2. `openWebPaywall(paywall)` qui génère des URL à partir du paywall sans ajouter les données du produit aux URL. Utilisez-la lorsque vos produits dans le paywall Adapty diffèrent de ceux du paywall web. ::: #### Gérer les erreurs \{#handle-errors\} | Erreur | Description | Action recommandée | |-----------------------------------------|-------------------------------------------------------------------|------------------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | Le paywall n'a pas d'URL d'achat web configurée | Vérifiez que le paywall a été correctement configuré dans l'Adapty Dashboard | | AdaptyError.productWithoutPurchaseUrl | Le produit n'a pas d'URL d'achat web | Vérifiez la configuration du produit dans l'Adapty Dashboard | | AdaptyError.failedOpeningWebPaywallUrl | Impossible d'ouvrir l'URL dans le navigateur | Vérifiez les paramètres de l'appareil ou proposez une autre méthode d'achat | | AdaptyError.failedDecodingWebPaywallUrl | Impossible d'encoder correctement les paramètres dans l'URL | Vérifiez que les paramètres d'URL sont valides et correctement formatés | ## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} :::important L'ouverture des paywalls web dans un navigateur intégré est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les paywalls web s'ouvrent dans le navigateur externe. Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. La page d'achat web s'affiche ainsi directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application. Pour activer cette option, passez `WebPresentation.BrowserInApp` comme second argument à `openWebPaywall` : ```typescript showLineNumbers title="React Native (TSX)" try { await adapty.openWebPaywall( product, WebPresentation.BrowserInApp, // default – WebPresentation.BrowserOutApp ); } catch (error) { console.warn('Failed to open web paywall:', error); } ``` --- # File: react-native-present-flows-in-observer-mode --- --- title: "Présenter des flows en mode Observateur - React Native" description: "Présentez des flows et des paywalls créés avec le Paywall Builder en mode Observateur dans votre application React Native tout en gérant les achats avec votre propre code." --- Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment cela doit l'être. :::warning Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez la rubrique [Afficher les flows et paywalls](react-native-present-paywalls). ::: :::info Cette fonctionnalité nécessite le SDK Adapty React Native 4.0 ou version ultérieure — auparavant, elle n'était disponible que dans les SDK natifs iOS et Android. Consultez le [guide de migration](migration-to-react-native-sdk-v4) pour mettre à niveau. ::: <details> <summary>Avant de commencer à afficher des flows (Cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios) et [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez le [guide d'installation du SDK React Native](sdk-installation-reactnative). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](react-native-get-pb-paywalls) dans le code de votre application mobile. </details> En mode Observateur, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou un paywall rendu par Adapty, le SDK appelle votre gestionnaire d'événements `onObserverPurchaseInitiated` ou `onObserverRestoreInitiated` — effectuez l'achat ou la restauration avec votre propre code à cet endroit. ## Définir les gestionnaires d'événements en mode observateur \{#set-the-observer-mode-event-handlers\} Contrairement aux autres plateformes, il n'existe pas d'objet resolver séparé — les gestionnaires font partie des [gestionnaires d'événements](react-native-handling-events-1) habituels, donc configurez-les sur chaque flow que vous présentez. <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour le composant React, passez les gestionnaires en tant que props à `AdaptyFlowView` : ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onObserverPurchaseInitiated = useCallback< FlowEventHandlers['onObserverPurchaseInitiated'] >((product, onStartPurchase, onFinishPurchase) => { onStartPurchase(); // the flow shows its loading indicator myPurchaseApi(product.vendorProductId) .then((transactionId) => adapty.reportTransaction(transactionId, flow.variationId)) .finally(() => onFinishPurchase()); // the flow hides the loading indicator }, [flow]); const onObserverRestoreInitiated = useCallback< FlowEventHandlers['onObserverRestoreInitiated'] >((onStartRestore, onFinishRestore) => { onStartRestore(); myRestoreApi().finally(() => onFinishRestore()); }, []); return ( <AdaptyFlowView flow={flow} onObserverPurchaseInitiated={onObserverPurchaseInitiated} onObserverRestoreInitiated={onObserverRestoreInitiated} // ... your other event handlers /> ); } ``` :::note Dans le composant intégré, la valeur retournée par un handler ne ferme pas le flow — démontez vous-même le composant après un achat ou une restauration réussis. ::: </TabItem> <TabItem value="standalone" label="Présentation modale"> Pour une présentation modale, définissez les handlers sur la vue que vous avez créée : ```typescript showLineNumbers title="React Native (TSX)" const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) { onStartPurchase(); // the flow shows its loading indicator myPurchaseApi(product.vendorProductId) .then((transactionId) => adapty.reportTransaction(transactionId, flow.variationId)) .finally(() => onFinishPurchase()); // the flow hides the loading indicator return false; // keep the flow open; dismiss it yourself after success }, onObserverRestoreInitiated(onStartRestore, onFinishRestore) { onStartRestore(); myRestoreApi().finally(() => onFinishRestore()); return false; }, }); ``` </TabItem> </Tabs> Le handler `onObserverPurchaseInitiated` vous informe que l'utilisateur a initié un achat, et `onObserverRestoreInitiated` — que l'utilisateur a initié une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse. N'oubliez pas non plus d'appeler les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. C'est nécessaire pour le bon comportement du flow, notamment pour afficher le loader : | Callback | Description | | :----------------- | :------------------------------------------------------------------------------------------------ | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | ## Présenter le flow \{#present-the-flow\} Présentez le flow comme d'habitude : [récupérez le flow et créez sa vue](react-native-get-pb-paywalls), puis [présentez-le](react-native-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — les handlers se déclenchent uniquement lorsque le SDK a été activé avec `observerMode: true`. :::warning N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-react-native). Sinon, Adapty ne reconnaîtra pas la transaction et ne pourra pas déterminer le paywall source de l'achat. ::: --- # File: react-native-troubleshoot-paywall-builder --- --- title: "Troubleshoot Paywall Builder in React Native SDK" description: "Troubleshoot Paywall Builder in React Native SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK React Native. ## L'obtention d'une configuration de paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La récupération de la configuration de vue pour un flow ou un paywall échoue. **Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le compteur de vues du paywall affiche le double du nombre attendu. **Cause** : Vous appelez peut-être `logShowFlow` (SDK React Native v4+) / `logShowPaywall` dans votre code, ce qui duplique le compteur de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et paywalls créés avec ces outils, les analytics sont suivies automatiquement, vous n'avez donc pas besoin d'utiliser cette méthode. **Solution** : Vérifiez que vous n'appelez pas `logShowFlow` (SDK React Native v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder qui ne sont pas couverts ci-dessus. **Solution** : Migrez le SDK vers la dernière version à l'aide des [guides de migration](react-native-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: react-native-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement dans le SDK React Native" description: "Apprenez à implémenter les paywalls manuellement dans votre application React Native avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty en utilisant la méthode `makePurchase`. Ainsi, nous gérerons tous les scénarios utilisateur, et vous n'aurez qu'à traiter les résultats des achats. :::important `makePurchase` fonctionne avec les produits créés dans Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['react-native-quickstart-manual', 'fetch-paywalls-and-products-react-native', 'present-remote-config-paywalls-react-native', 'react-native-making-purchases', 'react-native-restore-purchase', 'react-native-troubleshoot-purchases']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, mais souhaitez tout de même bénéficier des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode-react-native', 'report-transactions-observer-mode-react-native', 'react-native-troubleshoot-purchases']} /> --- # File: react-native-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec le SDK React Native" description: "Intégrez le SDK Adapty dans vos paywalls React Native personnalisés pour activer les achats intégrés." --- Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total de l'implémentation du paywall, pendant que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les achats précédents. :::important **Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la solution la plus simple pour activer les achats, utilisez [Adapty Flow Builder](react-native-quickstart-paywalls). Avec le Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différents designs sans republier votre app. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre app. - [**Placements**](placements) – où et quand vous affichez les paywalls dans votre app (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de paywalls différents à différents utilisateurs. Assurez-vous de bien comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En résumé, c'est simplement votre façon de gérer les produits que vous vendez dans votre app. Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](react-native-quickstart-identify) pour comprendre les spécificités et vous assurer de bien gérer vos utilisateurs. ## Étape 1. Obtenir les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`. 2. Obtenir le tableau des produits pour ce flow à l'aide de la méthode `getPaywallProducts`. ```typescript showLineNumbers async function loadPaywall() { try { const flow: AdaptyFlow = await adapty.getFlow('YOUR_PLACEMENT_ID'); const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts(flow); // Use products to build your custom paywall UI } catch (error) { // Handle the error } } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour. ```typescript showLineNumbers async function purchaseProduct(product: AdaptyPaywallProduct) { try { const purchaseResult: AdaptyPurchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': // Purchase successful, profile updated break; case 'user_cancelled': // User canceled the purchase break; case 'pending': // Purchase is pending (e.g., user will pay offline with cash) break; } } catch (error) { // Handle the error } } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Les stores d'applications exigent que toutes les apps avec des abonnements proposent un moyen pour les utilisateurs de restaurer leurs achats. Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et retournera le profil mis à jour. ```typescript showLineNumbers async function restorePurchases() { try { const profile: AdaptyProfile = await adapty.restorePurchases(); // Restore successful, profile updated } catch (error) { // Handle the error } } ``` ## Prochaines étapes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'app. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez [CustomPurchaseScreen.tsx](https://github.com/adaptyteam/AdaptySDK-React-Native/blob/master/examples/ExpoGoWebMock/src/CustomPurchaseScreen.tsx) dans notre exemple d'app, qui illustre la gestion des achats avec une gestion appropriée des erreurs, des états de chargement et la gestion de l'état de l'interface. Ensuite, [vérifiez si les utilisateurs ont finalisé leur achat](react-native-check-subscription-status) pour déterminer si vous devez afficher le paywall ou accorder l'accès aux fonctionnalités payantes. --- # File: fetch-paywalls-and-products-react-native --- --- title: "Récupérer les paywalls et les produits pour les paywalls à Remote Config dans le SDK React Native" description: "Récupérez les paywalls et les produits dans le SDK React Native d'Adapty pour améliorer la monétisation des utilisateurs." --- <SDKv4> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne le Remote Config et les paywalls personnalisés. Pour récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Récupérer les flows du Flow Builder et les paywalls du Paywall Builder ainsi que leur configuration](react-native-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-reactnative) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) regroupe des produits provenant à la fois de l'App Store et de Google Play. Ces produits cross-platform sont intégrés dans des flows et des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) à l'aide de la méthode `getFlow`. :::important **Ne codez pas les ID de produit en dur.** Le seul ID à coder en dur est l'ID du placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements de façon dynamique — si un flow renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlow(id); // the requested flow } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |-------------------|--------|-----------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé qu'en cas de réinstallation ou de nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](react-native-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours autonome en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos flows tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en coulisses.</p> | :::note Dans la v4, `getFlow` ne prend plus de paramètre `locale`. Pour les paywalls personnalisés, toutes les locales disponibles sont retournées dans le Remote Config du flow (`flow.remoteConfigs`) — choisissez celle qui correspond à la langue de l'appareil ou au paramètre de l'application. ::: Ne codez pas les identifiants de produit en dur ! Les flows étant configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent évoluer dans le temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit les afficher. Mais si vous en récupérez 3 plus tard, votre application doit tous les afficher sans aucune modification du code. La seule chose à coder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, ses variations de paywall (`paywalls`), et un tableau `remoteConfigs` (une entrée par locale configurée). Pour récupérer les produits du flow, appelez `getPaywallProducts(flow)`. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond : ```typescript showLineNumbers try { // ...flow const products = await adapty.getPaywallProducts(flow); // the requested products list } catch (error) { // handle the error } ``` Paramètres de la réponse : | Paramètre | Description | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) avec : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de paywall, vous aurez probablement besoin d'accéder aux propriétés de l'objet [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir des détails complets sur toutes les propriétés disponibles. | Propriété | Description | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue de l'appareil. | | **Price** | Pour afficher le prix dans une version localisée, utilisez `product.price?.localizedString`. Cette localisation est basée sur les informations de langue de l'appareil. Vous pouvez également accéder au prix sous forme de nombre via `product.price?.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price?.currencySymbol`. | | **Subscription Period** | Pour afficher la période (par ex. semaine, mois, année, etc.), utilisez `product.subscription?.localizedSubscriptionPeriod`. Cette localisation est basée sur la langue de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscription?.subscriptionPeriod`. Vous pouvez ensuite accéder à la propriété `unit` pour obtenir la durée (c'est-à-dire `'day'`, `'week'`, `'month'`, `'year'` ou `'unknown'`). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `'month'` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix d'introduction. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `paymentMode` : une chaîne dont les valeurs possibles sont `'free_trial'`, `'pay_as_you_go'`, `'pay_up_front'` et `'unknown'`. Les essais gratuits correspondent au type `'free_trial'`.<br/>• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, recherchez `0` ici.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon la langue de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affichera `'3 days'` dans ce champ.<br/>• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Son fonctionnement est identique à celui décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la langue de l'utilisateur. | ## Accélérer la récupération des flows avec le flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs ont une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience fluide plutôt que de ne rien afficher. Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme détaillé dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-react-native#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getFlow` La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon le pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide des flows, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur la méthode `getFlow` décrite [ci-dessus](fetch-paywalls-and-products-react-native#fetch-flow-information). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tentera de charger les données depuis le serveur et retournera les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique porte sur le Remote Config et les paywalls personnalisés. Pour savoir comment récupérer les paywalls configurés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](react-native-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquer pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et incorporez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et incorporez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-reactnative) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus à la fois de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés dans des paywalls, ce qui vous permet de les présenter dans des emplacements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **Ne codez pas les ID de produits en dur.** Le seul ID à coder en dur est l'ID du placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywall(id, locale); // the requested paywall } catch (error) { // handle the error } ``` | Paramètre | Présence | Description | |-------------------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](react-native-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si votre application est utilisée dans des conditions de connectivité instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc fiable de l'utiliser en cours de session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](react-native-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir la dernière version de vos paywalls tout en assurant une fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan.</p> | N'intégrez pas les identifiants de produit en dur dans votre code ! Comme les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez 3 par la suite, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à intégrer en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) contenant : une liste d'identifiants de produits, l'identifiant du paywall, la Remote Config, et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le paywall, vous pouvez interroger le tableau de produits qui lui correspond : ```typescript showLineNumbers try { // ...paywall const products = await adapty.getPaywallProducts(paywall); // the requested products list } catch (error) { // handle the error } ``` Paramètres de réponse : | Paramètre | Description | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Liste d'objets [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) avec : identifiant du produit, nom du produit, prix, devise, durée d'abonnement et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles. | Propriété | Description | |--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue du terminal. | | **Price** | Pour afficher le prix localisé, utilisez `product.price?.localizedString`. Cette localisation est basée sur les paramètres régionaux du terminal. Vous pouvez également accéder au prix sous forme numérique via `product.price?.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price?.currencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. semaine, mois, année, etc.), utilisez `product.subscription?.localizedSubscriptionPeriod`. Cette localisation est basée sur les paramètres régionaux du terminal. Pour récupérer la période d'abonnement de façon programmatique, utilisez `product.subscription?.subscriptionPeriod`. Vous pouvez accéder à la propriété `unit` pour obtenir la durée (c'est-à-dire `'day'`, `'week'`, `'month'`, `'year'` ou `'unknown'`). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `'month'` dans la propriété unit et `3` dans la propriété numberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou un indicateur signalant qu'un abonnement inclut une offre de lancement, consultez la propriété `product.subscription?.offer?.phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix d'introduction. Chaque objet de phase contient les propriétés suivantes :<br/>• `paymentMode` : une chaîne de caractères pouvant valoir `'free_trial'`, `'pay_as_you_go'`, `'pay_up_front'` ou `'unknown'`. Les essais gratuits correspondent au type `'free_trial'`.<br/>• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, cette valeur sera `0`.<br/>• `localizedNumberOfPeriods` : une chaîne localisée selon les paramètres régionaux du terminal décrivant la durée de l'offre. Par exemple, un essai de trois jours affichera `'3 days'` dans ce champ.<br/>• `subscriptionPeriod` : vous permet également d'obtenir les détails individuels de la période de l'offre. Son fonctionnement est identique à ce qui est décrit dans la section précédente.<br/>• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon les paramètres régionaux de l'utilisateur. | ## Accélérer la récupération du paywall avec le paywall de l'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous inquiéter d'optimiser ce processus. Toutefois, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ces situations, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de n'afficher aucun paywall. Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-react-native#fetch-paywall-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `getPaywall` La méthode `getPaywallForDefaultAudience` présente quelques inconvénients notables : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes d'affichage. - **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](fetch-paywalls-and-products-react-native#fetch-paywall-information). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.2 du SDK React Native. ::: | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag indique la langue, le second la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](react-native-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre façon de les utiliser.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv3> --- # File: present-remote-config-paywalls-react-native --- --- title: "Afficher un paywall conçu via Remote Config dans React Native SDK" description: "Découvrez comment présenter des paywalls Remote Config dans Adapty React Native SDK pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un flow via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre vue de flow. Nous fournissons une méthode pour récupérer la configuration distante, vous donnant la liberté de présenter votre flow personnalisé configuré via Remote Config. ## Récupérer la Remote Config du flow et l'afficher \{#get-flow-remote-config-and-present-it\} En v4, un flow contient une entrée `AdaptyRemoteConfig` par langue configurée dans le tableau `remoteConfigs`. Choisissez la langue correspondant à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin dans son champ `data`. ```typescript showLineNumbers try { const flow = await adapty.getFlow("YOUR_PLACEMENT_ID"); const config = flow.remoteConfigs?.find((c) => c.lang === "en") ?? flow.remoteConfigs?.[0]; const headerText = config?.data?.["header_text"]; } catch (error) { // handle the error } ``` À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler pour composer une page visuellement attractive. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et conviviale sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-react-native#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du flow terminé, passez à la configuration du tunnel d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](react-native-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](react-native-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant ainsi une expérience fluide dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos flows. Les données sur les achats sont collectées automatiquement, mais l'enregistrement des vues de flow nécessite votre intervention, car vous seul savez quand un utilisateur voit un flow. Pour enregistrer un événement de vue de flow, appelez simplement `.logShowFlow(flow)` — il sera reflété dans vos métriques de paywall dans les funnels et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit automatiquement les vues dans ces cas. ::: ```typescript showLineNumbers await adapty.logShowFlow(flow); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :------- |:-------------------------------------------------------------------------------------| | **flow** | requis | Un objet `AdaptyFlow` obtenu via `adapty.getFlow(placementId)`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre vue de paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous donnant la liberté de présenter votre paywall personnalisé configuré via Remote Config. ## Récupérer la Remote Config du paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir la Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires. ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: "YOUR_PLACEMENT_ID" }); const headerText = paywall.remoteConfig?.data?.["header_text"]; } catch (error) { // handle the error } ``` À ce stade, une fois que vous avez récupéré toutes les valeurs nécessaires, il est temps de les assembler pour composer une page visuellement attractive. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et conviviale sur tous les appareils. :::warning Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-react-native#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B. ::: Une fois l'affichage du paywall terminé, passez à la configuration du tunnel d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](react-native-making-purchases). Nous recommandons de [créer un paywall de secours appelé fallback paywall](react-native-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant ainsi une expérience fluide dans ces situations. ## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Les données sur les achats sont collectées automatiquement, mais l'enregistrement des vues de paywall nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall. Pour enregistrer un événement de vue de paywall, appelez simplement `.logShowPaywall(paywall)` — il sera reflété dans vos métriques de paywall dans les funnels et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```typescript showLineNumbers await adapty.logShowPaywall(paywall); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:--------------------------------------------------------------------------------------------| | **paywall** | requis | Un objet [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall). | </SDKv3> --- # File: react-native-making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK React Native" description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour offrir aux utilisateurs l'accès à des contenus ou services premium. Cependant, afficher ces paywalls suffit uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour les personnaliser. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode distincte appelée `.makePurchase()` pour finaliser un achat et déverrouiller le contenu souhaité. Cette méthode constitue la passerelle permettant aux utilisateurs d'interagir avec les paywalls et de procéder aux transactions souhaitées. Si votre paywall dispose d'une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés via le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de la publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter une seule étape. Sans cela, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez des instructions pas à pas ?** Consultez le [guide de démarrage rapide](react-native-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: ```typescript showLineNumbers 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 } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :-------- |:-------------------------------------------------------------------------------------------------------------------------------| | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Si la requête a réussi, la réponse contient cet objet. Un objet [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur dans l'application.</p><p>Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.</p> | :::warning **Remarque :** si vous utilisez encore la version StoreKit d'Apple inférieure à v2.0 et une version du SDK Adapty inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple. ::: ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur choisit un nouvel abonnement plutôt que de renouveler l'abonnement actuel, le comportement dépend du store : - Pour l'App Store, l'abonnement est automatiquement mis à jour au sein du groupe d'abonnements. Si un utilisateur achète un abonnement d'un groupe alors qu'il a déjà un abonnement d'un autre groupe, les deux abonnements seront actifs simultanément. - Pour Google Play, l'abonnement n'est pas automatiquement mis à jour. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer l'abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire : ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product, params); 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 } ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------- | :------- | :----------------------------------------------------------- | | **params** | requis | un objet de type [`MakePurchaseParamsInput`](https://react-native.adapty.io/types/makepurchaseparamsinput). | :::info **Version 3.8.2+** : La structure `MakePurchaseParamsInput` a été mise à jour. `oldSubVendorProductId` et `prorationMode` sont désormais imbriqués sous `subscriptionUpdateParams`, et `isOfferPersonalized` est déplacé au niveau supérieur. Exemple : ```javascript makePurchase(product, { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } }); ``` ::: Vous pouvez en savoir plus sur les abonnements et les modes de remplacement dans la documentation Google Developer : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement réel n'aura lieu qu'à la fin de la période de facturation de l'abonnement actuel. ## Utiliser des codes promotionnels sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie du code dans votre application : ```typescript showLineNumbers adapty.presentCodeRedemptionSheet(); ``` :::danger D'après nos observations, la feuille de saisie de code promotionnel peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, vous devez ouvrir l'URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ## Gérer les plans prépayés (Android) \{#manage-prepaid-plans-android\} Si les utilisateurs de votre application peuvent acheter des [plans prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, acheter un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour les plans prépayés. ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { android: { pendingPrepaidPlansEnabled: true } }); ``` --- # File: react-native-restore-purchase --- --- title: "Restaurer les achats dans une application mobile avec React Native SDK" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats sur iOS et Android permet aux utilisateurs de retrouver l'accès à du contenu précédemment acheté — abonnements ou achats intégrés — sans être débité à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent accéder à leurs achats passés sans repayer. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.restorePurchases()` : ```typescript showLineNumbers try { const profile = await adapty.restorePurchases(); const isSubscribed = profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // restore access } } catch (error) { // handle the error } ``` Paramètres de réponse : | Paramètre | Description | |---------|-----------| | **Profile** | <p>Un objet [`AdaptyProfile`](https://react-native.adapty.io/interfaces/adaptyprofile). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.</p><p>Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.</p> | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: implement-observer-mode-react-native --- --- title: "Implémenter le mode Observateur dans le SDK React Native" description: "Implémentez le mode Observateur dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK React Native." --- Si vous disposez déjà de votre propre infrastructure d'achat et que vous n'êtes pas prêt à basculer entièrement vers Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analytique. Si cela correspond à vos besoins, il vous suffit de : 1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [React Native](sdk-installation-reactnative). 2. [Signaler les transactions](report-transactions-observer-mode-react-native) depuis votre infrastructure d'achat existante vers Adapty. ### Configuration du mode Observateur \{#observer-mode-setup\} Activez le mode Observateur si vous gérez les achats et le statut des abonnements vous-même et que vous utilisez Adapty uniquement pour envoyer des événements d'abonnement et des données analytiques. :::important En mode Observateur, le SDK Adapty ne clôturera aucune transaction ; assurez-vous donc de les gérer vous-même. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { observerMode: true, // Enable observer mode }); ``` Paramètres : | Paramètre | Description | | --------------------------- | ------------------------------------------------------------ | | observerMode | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observateur \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observateur. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls Remote Config](present-remote-config-paywalls-react-native). 3. [Associez les paywalls](report-transactions-observer-mode-react-native) aux transactions d'achat. --- # File: report-transactions-observer-mode-react-native --- --- title: "Signaler des transactions en mode Observer dans le SDK React Native" description: "Signalez les transactions d'achat en mode Observer Adapty pour les informations utilisateur et le suivi des revenus dans le SDK React Native." --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+ (current)" default> En mode Observer, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```typescript showLineNumbers const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | requis | <ul><li> Pour iOS : identifiant de la transaction.</li><li> Pour Android : identifiant de type chaîne (`purchase.getOrderId`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall). | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> En mode Observer, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store ou les restaurer. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` sur les deux plateformes pour signaler explicitement chaque transaction, et utilisez `restorePurchases` sur Android comme étape supplémentaire pour garantir qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas ces méthodes, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```typescript showLineNumbers if (Platform.OS === 'android') { try { await adapty.restorePurchases(); } catch (error) { // handle the error } } ... const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | requis | <ul><li> Pour iOS, StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</li><li> Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</li><li> Pour Android : identifiant de type chaîne (`purchase.getOrderId`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall). | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **Signalement des transactions** - Les versions jusqu'à 3.1.x écoutent automatiquement les transactions dans l'App Store, le signalement manuel n'est donc pas nécessaire. - La version 3.2 ne prend pas en charge le mode Observer. </TabItem> <TabItem value="kotlin" label="Android and Android-based cross-platforms" default> **Signalement des transactions** Utilisez `restorePurchases` pour signaler une transaction à Adapty en mode Observer, comme expliqué sur la page [Restaurer les achats dans le code mobile](react-native-restore-purchase). :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: </TabItem> </Tabs> **Association des paywalls aux transactions** Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous souhaitez utiliser des paywalls et/ou des tests A/B en mode Observer, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de configurer cela correctement avant de publier votre application, sinon cela entraînera des erreurs dans les analyses. ```typescript const variationId = paywall.variationId; try { await adapty.setVariationId('transactionId', variationId); } catch (error) { // handle the `AdaptyError` } ``` Paramètres de la requête : | Paramètre | Présence | Description | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | requis | <p>Pour iOS, StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</p><p>Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</p><p>Pour Android : identifiant de type chaîne (purchase.getOrderId de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</p> | | variationId | requis | L'identifiant de type chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall). | </TabItem> </Tabs> --- # File: react-native-troubleshoot-purchases --- --- title: "Troubleshoot purchases in React Native SDK" description: "Troubleshoot purchases in React Native SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK React Native. ## makePurchase est appelé avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et le statut de l'abonnement ne sont pas mis à jour dans Adapty. **Cause** : Cela indique généralement une configuration incomplète du Google Play Store. **Solution** : Assurez-vous d'avoir suivi toutes les [étapes de configuration Google Play](initial-android). ## makePurchase est appelé deux fois \{#makepurchase-is-invoked-twice\} **Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat. **Cause** : Cela se produit généralement lorsque le flux d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur. **Solution** : Assurez-vous d'avoir suivi toutes les [étapes de configuration Google Play](initial-android). ## AdaptyError.cantMakePayments en mode observateur \{#adaptyerrorcantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` en utilisant `makePurchase` en mode observateur. **Cause** : En mode observateur, vous devez gérer les achats de votre côté et ne pas utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observateur. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observateur. Consultez [Implémenter le mode observateur](implement-observer-mode-react-native) pour plus de détails. ## Erreur 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\} **Problème** : Vous recevez une erreur de facturation indisponible de Google Play Store. **Cause** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil. **Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes car `makePurchasesCompletionHandlers` est introuvable. **Cause** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de complétion d'achat liés au sandbox. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés aux achats qui ne sont pas couverts ci-dessus. **Solution** : Migrez le SDK vers la dernière version en utilisant les [guides de migration](react-native-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions récentes du SDK. --- # File: react-native-user --- --- title: "Utilisateurs et accès dans le SDK React Native" description: "Découvrez comment gérer les utilisateurs et les niveaux d'accès dans votre application React Native avec le SDK Adapty." --- <CustomDocCardList /> --- # File: react-native-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK React Native" description: "Découvrez comment identifier les utilisateurs dans votre application React Native avec le SDK Adapty." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devriez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyée à toutes les intégrations. ### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur au moment de la configuration, transmettez-le simplement comme paramètre `customerUserId` à la méthode `.activate()` : ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID" }); ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous ne disposez pas d'un identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'utilisation les plus courants sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié. ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // successfully identified } catch (error) { // handle the error } ``` Paramètres de la requête : - **Customer User ID** (requis) : un identifiant utilisateur de type chaîne de caractères. :::warning Nouvelle soumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces situations, le SDK Adapty basculera automatiquement pour travailler avec le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, comme des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez soumettre à nouveau ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the error } ``` Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`. ## Assigner un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de lier les transactions App Store à l'identité interne de vos utilisateurs. StoreKit associe ce token à chaque transaction, afin que votre backend puisse faire correspondre les données App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications App Store restent correctement liés. Vous pouvez définir le token de deux façons : lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `appAccountToken` avec `customerUserId`. Si vous ne transmettez que le token, il ne sera pas inclus dans la transaction. ::: ```typescript showLineNumbers // During configuration: adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID", ios: { appAccountToken: "YOUR_APP_ACCOUNT_TOKEN" }, }); // Or when identifying users try { await adapty.identify("YOUR_USER_ID", { ios: {appAccountToken: 'YOUR_APP_ACCOUNT_TOKEN'} }); // successfully identified } catch (error) { // handle the error } ``` ### Définir des identifiants de compte obfusqués (Android) \{#set-obfuscated-account-ids-android\} Google Play exige des identifiants de compte obfusqués pour certains cas d'utilisation afin de renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants aident Google Play à identifier les achats tout en gardant les informations des utilisateurs anonymes, ce qui est particulièrement important pour la prévention des fraudes et l'analyse. Vous devrez peut-être définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations spécifiques en matière de confidentialité. Les identifiants obfusqués permettent à Google Play de suivre les achats sans exposer les identifiants réels des utilisateurs. ```typescript showLineNumbers // During configuration: adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID", android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' } }); // Or when identifying users try { await adapty.identify("YOUR_USER_ID", { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' } }); // successfully identified } catch (error) { // handle the error } ``` ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: react-native-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK React Native" description: "Apprenez à mettre à jour les attributs utilisateur et les données de profil dans votre app React Native avec le SDK Adapty." --- Vous pouvez définir des attributs optionnels tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre app. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` : ```typescript showLineNumbers // Only for TypeScript validation const params: AdaptyProfileParameters = { email: 'email@email.com', phoneNumber: '+18888888888', firstName: 'John', lastName: 'Appleseed', gender: 'other', birthday: new Date().toISOString(), }; try { await adapty.updateProfile(params); } catch (error) { // handle `AdaptyError` } ``` Notez que les attributs définis précédemment via la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés autorisées `<Key>` de `AdaptyProfileParameters.Builder` et les valeurs `<Value>` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum, valeurs autorisées : `female`, `male`, `other` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre app. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, ainsi que dans les analyses pour déterminer quelles métriques produit influencent le plus les revenus. ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); } catch (error) { // handle `AdaptyError` } ``` Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` : ```typescript showLineNumbers try { // to remove a key, pass null as its value await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); } catch (error) { // handle `AdaptyError` } ``` Il peut parfois être utile de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut être obsolète, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment — les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clés peuvent contenir jusqu'à 30 caractères. Ils peuvent inclure des caractères alphanumériques et l'un des symboles suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre flottant, avec 50 caractères maximum. --- # File: react-native-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK React Native" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application React Native." --- Avec Adapty, le suivi du statut d'abonnement est simplifié. Inutile d'insérer manuellement des identifiants de produits dans votre code. Il vous suffit de vérifier la présence d'un [niveau d'accès](access-level) actif pour confirmer l'état d'abonnement d'un utilisateur. <details> <summary>Avant de vérifier le statut d'abonnement (cliquez pour développer)</summary> - Pour iOS, configurez les [notifications serveur App Store](enable-app-store-server-notifications) - Pour Android, configurez les [notifications en temps réel pour les développeurs (RTDN)](enable-real-time-developer-notifications-rtdn) </details> ## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile). Nous recommandons de récupérer le profil au démarrage de l'application, par exemple lors de l'[identification d'un utilisateur](react-native-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque changement. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander en permanence. Pour être notifié des mises à jour du profil, écoutez les changements de profil comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](react-native-listen-subscription-changes) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` Paramètres de la réponse : | Paramètre | Description | | --------- | ------------------------------------------------------------ | | Profile | <p>Un objet [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.</p><p></p><p>La méthode `.getProfile` fournit le résultat le plus récent, car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont retournées. Il est également important de noter que le SDK Adapty met à jour le cache `AdaptyProfile` régulièrement afin de maintenir ces informations aussi à jour que possible.</p> | La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de presse et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer des niveaux d'accès « sports » et « science ». Mais la plupart du temps, vous n'aurez besoin que d'un seul niveau d'accès ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès par défaut « premium ». Voici un exemple de vérification du niveau d'accès « premium » par défaut : ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.["premium"]?.isActive; if (isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir les messages d'Adapty, vous devez effectuer quelques configurations supplémentaires : ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addEventListener('onLatestProfileLoad', profile => { // handle any changes to subscription state }); ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Cela signifie que même si le serveur est indisponible, les données mises en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil. Il est toutefois important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier s'il y a des mises à jour ou des changements liés au profil. S'il y a des modifications, comme de nouvelles transactions ou d'autres mises à jour, elles sont envoyées dans les données mises en cache afin de les maintenir synchronisées avec le serveur. --- # File: react-native-deal-with-att --- --- title: "Gérer l'ATT dans le SDK React Native" description: "Démarrez avec Adapty sur React Native pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. ```typescript showLineNumbers try { await adapty.updateProfile({ // you can also pass a string value (validated via tsc) if you prefer appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); } catch (error) { // handle `AdaptyError` } ``` :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de transmettre les données en temps voulu aux intégrations que vous avez configurées. ::: --- # File: kids-mode-react-native --- --- title: "Mode Enfants dans le SDK React Native" description: "Activez facilement le Mode Enfants pour respecter les politiques d'Apple et Google. Aucune collecte d'IDFA, GAID ou données publicitaires dans le SDK React Native." --- Si votre application React Native est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/) et de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour répondre à ces politiques et passer les revues des stores. :::important Sur iOS, le Mode Enfants est activé via le trait du package Swift `KidsMode`, qui exclut à la compilation tout le code lié à l'IDFA, AdSupport et AppTrackingTransparency. Il nécessite le SDK v4 (qui installe le SDK iOS natif via Swift Package Manager) et **Xcode 26** ou une version ultérieure. Voir [Modifications dans votre Podfile iOS](#updates-in-your-ios-podfile) ci-dessous. ::: ## Ce qui est requis \{#whats-required\} Vous devez configurer le SDK Adapty pour désactiver la collecte 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) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) De plus, nous recommandons d'utiliser l'identifiant utilisateur avec précaution. Un identifiant au format `<Prénom.Nom>` sera assurément considéré comme une collecte de données personnelles, tout comme l'utilisation d'une adresse e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité. ## Activation du Mode Enfants \{#enabling-kids-mode\} ### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\} Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\} Pour respecter les politiques, désactivez la collecte de l'IDFA de l'utilisateur (iOS), du GAID/AAID (Android) et de l'adresse IP lors de l'activation du SDK Adapty : ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { // Disable IP address collection ipAddressCollectionDisabled: true, // Disable IDFA collection on iOS ios: { idfaCollectionDisabled: true, }, // Disable Google Advertising ID collection on Android android: { adIdCollectionDisabled: true, }, }); ``` ### Modifications dans votre Podfile iOS \{#updates-in-your-ios-podfile\} Pour la catégorie Enfants de l'App Store (ou la conformité COPPA), le SDK iOS natif doit être compilé avec le trait du package Swift `KidsMode`, qui exclut à la compilation tout le code lié à l'IDFA, AdSupport et AppTrackingTransparency. React Native installe le SDK natif via Swift Package Manager, qui ne peut pas transmettre les traits de package ; le SDK fournit donc un helper Podfile qui applique le trait à votre place. Cette étape nécessite **Xcode 26** ou une version ultérieure. Dans `ios/Podfile`, importez le helper et appelez-le **après** `react_native_post_install` : ```ruby showLineNumbers title="ios/Podfile" require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native-adapty/ios/adapty_kids_mode.rb", {paths: [process.argv[1]]}, )', __dir__]).strip # ... post_install do |installer| react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false ) adapty_enable_kids_mode(installer) end ``` Puis exécutez `pod install` : ```sh showLineNumbers title="Shell" cd ios && pod install ``` Pour confirmer que le Mode Enfants est actif, vérifiez que la ligne de log `adapty.activate(...)` indique `kids_mode_enabled: true`. Conservez l'appel au helper dans `post_install` de façon permanente — React Native recrée les références au package Swift à chaque `pod install`, et le helper réapplique le trait à chaque fois. ### Modifications dans votre manifest Android \{#updates-in-your-android-manifest\} :::note Si votre application cible **uniquement** les enfants et est compilée contre Android 13 (API 33) ou supérieur, Google Play exige que vous ne demandiez pas la permission `AD_ID`. Un autre SDK dans votre application (analytics, attribution ou publicités) peut ajouter cette permission via la fusion de manifests. Définir `adIdCollectionDisabled` empêche Adapty de collecter l'ID, mais ne supprime pas une permission déclarée par un autre SDK. ::: Pour supprimer la permission, ajoutez ce qui suit à l'intérieur de l'élément `<manifest>` de `android/app/src/main/AndroidManifest.xml`. L'élément `<manifest>` doit déclarer `xmlns:tools="http://schemas.android.com/tools"`. ```xml showLineNumbers title="AndroidManifest.xml" <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" /> ``` --- # File: react-native-onboardings --- --- title: "Onboardings dans le SDK React Native" description: "Découvrez comment utiliser les onboardings dans votre application React Native avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](react-native-get-pb-paywalls) : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Récupérer les flows & paywalls](react-native-get-pb-paywalls) et [Afficher les flows & paywalls](react-native-present-paywalls) pour commencer. ::: <CustomDocCardList /> --- # File: react-native-get-onboardings --- --- title: "Récupérer les onboardings dans le SDK React Native" description: "Apprenez à récupérer les onboardings dans Adapty pour React Native." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](react-native-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — avec des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance au moteur WebView. Consultez [Récupérer les flows & paywalls](react-native-get-pb-paywalls) et [Afficher les flows & paywalls](react-native-present-paywalls) pour commencer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application React Native. La première étape consiste à récupérer l'onboarding associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK React Native Adapty](sdk-installation-reactnative) en version 3.8.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer un onboarding \{#fetch-onboarding\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'ensemble de l'expérience — le contenu affiché, la façon dont il est présenté, et le traitement des interactions utilisateur (comme les réponses à des quiz ou la saisie de formulaires). Le conteneur suit également automatiquement les événements analytics, vous n'avez donc pas besoin d'implémenter un suivi des vues séparé. Pour de meilleures performances, récupérez la configuration de l'onboarding tôt afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher aux utilisateurs. Pour récupérer un onboarding, utilisez la méthode `getOnboarding` : ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboarding(placementId, locale); // the requested onboarding } catch (error) { // handle the error } ``` Ensuite, appelez la méthode `createOnboardingView` pour créer une instance de vue. :::warning Le résultat de la méthode `createOnboardingView` ne peut être utilisé qu'une seule fois. Si vous devez l'utiliser à nouveau, appelez à nouveau la méthode `createOnboardingView`. L'appeler deux fois sans recréer l'instance peut entraîner l'erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createOnboardingView} from 'react-native-adapty/dist/ui'; if (onboarding.hasViewConfiguration) { try { const view = await createOnboardingView(onboarding); } catch (error) { // handle the error } } else { //use your custom logic } ``` Paramètres : | Paramètre | Présence | Description | |-------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeoutMs** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en arrière-plan.</p> | Paramètres de réponse : | Paramètre | Description | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://react-native.adapty.io/interfaces/adaptyonboarding) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. | ## Accélérer la récupération de l'onboarding avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, lorsque vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un onboarding par défaut pour garantir une expérience utilisateur fluide plutôt que de n'afficher aucun onboarding. Pour répondre à ce besoin, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer l'onboarding via la méthode `getOnboarding`, comme détaillé dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus. :::warning Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des difficultés lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les versions plus anciennes puissent s'afficher incorrectement. - **Aucune personnalisation** : affiche uniquement le contenu pour l'audience "All Users", sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si une récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding). ::: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboardingForDefaultAudience(placementId, locale); // the requested onboarding } catch (error) { // handle the error } ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | --- # File: react-native-present-onboardings --- --- title: "Présenter les onboardings dans React Native SDK" description: "Découvrez comment présenter des onboardings dans React Native pour booster les conversions et les revenus." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez plutôt les [flows](react-native-get-pb-paywalls) : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Récupérer les flows & paywalls](react-native-get-pb-paywalls) et [Afficher les flows & paywalls](react-native-present-paywalls) pour démarrer. ::: Si vous avez personnalisé un onboarding via le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et la façon dont cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez installé [Adapty React Native SDK](sdk-installation-reactnative) 3.8.0 ou ultérieur. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Adapty React Native SDK propose deux façons de présenter les onboardings : - **Composant React** : un composant embarqué qui vous permet de l'intégrer à l'architecture et au système de navigation de votre application. - **Présentation modale** ## Composant React \{#react-component\} Pour intégrer un onboarding dans votre arbre de composants existant, utilisez le composant `AdaptyOnboardingView` directement dans la hiérarchie de vos composants React Native. Ce composant embarqué vous permet de l'intégrer à l'architecture et au système de navigation de votre application. :::note Sur Android, nous recommandons une configuration supplémentaire pour `AdaptyOnboardingView` afin d'éviter un artefact de rendu visuel. Consultez [L'interface système chevauche le contenu de l'onboarding sur Android](#system-ui-overlaps-onboarding-content-on-android). ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="old" label="SDK version < 3.14" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { return ( <AdaptyOnboardingView onboarding={onboarding} style={{ flex: 1 }} eventHandlers={{ onAnalytics(event, meta) { // Handle analytics events }, onClose(actionId, meta) { // Handle close actions }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle state updates }, onFinishedLoading(meta) { // Handle when onboarding finishes loading }, onError(error) { // Handle errors }, }} /> ); } ``` </TabItem> </Tabs> ## Présentation modale \{#modal-presentation\} Pour afficher un onboarding en tant qu'écran autonome que les utilisateurs peuvent fermer, utilisez la méthode `view.present()` sur le `view` créé par la méthode `createOnboardingView`. Chaque `view` ne peut être utilisé qu'une seule fois. Si vous devez afficher à nouveau l'onboarding, appelez `createOnboardingView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser le même `view` sans le recréer est interdit. Cela entraînera une erreur `AdaptyUIError.viewAlreadyPresented`. ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView(onboarding); // Optional: handle onboarding events (close, custom actions, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> <TabItem value="old" label="SDK version < 3.14" default> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView(onboarding); view.setEventHandlers(); // handle close press, etc try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ### Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Ce paramètre accepte les valeurs `'full_screen'` (par défaut) ou `'page_sheet'`. ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## Loader pendant l'onboarding \{#loader-during-onboarding\} Lors de la présentation d'un onboarding dans React Native, vous pouvez remarquer un bref flash blanc ou un écran de chargement avant que l'onboarding n'apparaisse. Cela se produit pendant l'initialisation de la vue native sous-jacente. Vous pouvez gérer cela de différentes façons selon vos besoins et votre workflow. #### Contrôler l'écran de démarrage via onFinishedLoading \{#control-splash-screen-using-onfinishedloading\} :::note Cette approche n'est disponible qu'avec le composant React. Elle n'est pas disponible pour la présentation modale. ::: L'approche recommandée pour React Native est de garder votre écran de démarrage ou un overlay personnalisé visible jusqu'à ce que l'onboarding soit entièrement chargé, puis de le masquer manuellement. Avec le composant React (`AdaptyOnboardingView`), attendez l'événement `onFinishedLoading` avant de masquer votre écran de démarrage ou votre overlay : <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const [isLoading, setIsLoading] = useState(true); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => { // Hide your splash screen or custom overlay here setIsLoading(false); }, []); return ( <> <AdaptyOnboardingView onboarding={onboarding} onFinishedLoading={onFinishedLoading} // ... other callbacks /> {isLoading && <YourCustomLoadingOverlay />} </> ); } ``` </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const [isLoading, setIsLoading] = useState(true); return ( <> <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onFinishedLoading(meta) { // Hide your splash screen or custom overlay here setIsLoading(false); }, // ... other handlers }} /> {isLoading && <YourCustomLoadingOverlay />} </> ); } ``` </TabItem> </Tabs> #### Personnaliser le loader natif \{#customize-native-loader\} :::important Le workflow géré par Expo ne prend pas en charge l'ajout de layouts natifs personnalisés (par exemple, `res/layout` sur Android). Pour les applications Expo, contrôler l'écran de démarrage ou utiliser un overlay React Native est la seule solution viable. ::: Vous pouvez remplacer le loader natif en utilisant des layouts spécifiques à chaque plateforme sur Android et iOS. Si vous utilisez la présentation modale, c'est votre seule option. Cependant, cette approche est généralement moins pratique pour les applications React Native : - Nécessite des implémentations séparées pour Android et iOS - Non compatible avec le workflow géré par Expo Définissez un placeholder pour chaque plateforme : - **iOS** : Ajoutez `AdaptyOnboardingPlaceholderView.xib` à votre projet Xcode. [En savoir plus](ios-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding). - **Android** : Créez `adapty_onboarding_placeholder_view.xml` dans `res/layout` et définissez-y un placeholder. [En savoir plus](android-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding). ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15.1. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience fluide en affichant les pages web directement dans votre application, sans que les utilisateurs aient à changer d'app. Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `WebPresentation.BrowserOutApp` : <Tabs groupId="rn-onboarding-views" queryString> <TabItem value="component" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} externalUrlsPresentation={WebPresentation.BrowserOutApp} // default – BrowserInApp onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView( onboarding, { externalUrlsPresentation: WebPresentation.BrowserOutApp } // default – BrowserInApp ); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## Résolution des problèmes \{#troubleshooting\} ### L'interface système chevauche le contenu de l'onboarding sur Android \{#system-ui-overlaps-onboarding-content-on-android\} :::note Ce paramètre n'est pris en charge que dans les projets React Native bare. Si vous utilisez un workflow géré par Expo, vous ne pouvez pas ajouter cette ressource Android directement. Pour appliquer ce paramètre, vous devez créer un plugin de configuration Expo personnalisé qui ajoute la ressource Android correspondante et l'enregistrer dans app.config.js. Cela est nécessaire car Expo gère le projet Android natif à votre place. ::: Lors de l'utilisation de `AdaptyOnboardingView` sur Android, des éléments de l'interface système tels que la barre de statut et la barre de navigation peuvent apparaître par-dessus le contenu du paywall. Pour éviter cela, ajoutez la ressource booléenne suivante à votre application : 1. Accédez à `android/app/src/main/res/values`. S'il n'existe pas de fichier `bools.xml`, créez-le. 2. Ajoutez la ressource suivante : ```xml <resources> <bool name="adapty_onboarding_enable_safe_area_paddings">false</bool> </resources> ``` Notez que ces modifications s'appliquent globalement à tous les onboardings de votre application. ## Étapes suivantes \{#next-steps\} Une fois votre onboarding présenté, vous voudrez [gérer les interactions et événements utilisateur](react-native-handling-onboarding-events). Découvrez comment traiter les événements de l'onboarding pour répondre aux actions des utilisateurs et suivre les analytics. --- # File: react-native-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK React Native" description: "Gérez les événements liés à l'onboarding dans React Native avec Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](react-native-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Récupérer les flows & paywalls](react-native-get-pb-paywalls) et [Afficher les flows & paywalls](react-native-present-paywalls) pour commencer. ::: Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. La manière de gérer ces événements dépend de l'approche de présentation utilisée : - **Présentation modale** : nécessite la mise en place de gestionnaires d'événements qui traitent les événements pour toutes les vues d'onboarding - **Composant React** : gère les événements via des paramètres de callback inline directement dans le widget Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK React Native Adapty](sdk-installation-reactnative) version 3.8.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Pour contrôler ou surveiller les processus se déroulant sur l'écran d'onboarding dans votre application mobile, implémentez des gestionnaires d'événements : <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Pour le composant React, vous gérez les événements via des props de gestionnaire d'événements individuels dans le composant `AdaptyOnboardingView` : ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Pour la présentation modale, implémentez la méthode de gestionnaires d'événements. :::important Appeler `setEventHandlers` plusieurs fois écrasera les gestionnaires que vous avez définis, remplaçant à la fois les gestionnaires par défaut et ceux précédemment configurés pour ces événements spécifiques. ::: ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onAnalytics(event, meta) { // Track analytics events }, onClose(actionId, meta) { // Handle close action view.dismiss(); return true; }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle user input updates }, onFinishedLoading(meta) { // Onboarding finished loading }, onError(error) { // Handle loading errors }, }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> Pour les versions du SDK antérieures à 3.14, seule la présentation modale est prise en charge : ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onAnalytics(event, meta) { // Track analytics events }, onClose(actionId, meta) { // Handle close action view.dismiss(); return true; }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle user input updates }, onFinishedLoading(meta) { // Onboarding finished loading }, onError(error) { // Handle loading errors }, }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## Types d'événements \{#event-types\} Les sections suivantes décrivent les différents types d'événements que vous pouvez gérer, quelle que soit l'approche de présentation utilisée. ### Gérer les actions personnalisées \{#handle-custom-actions\} Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un ID. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez ensuite utiliser cet ID dans votre code et le gérer comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé, comme **Login** ou **Allow notifications**, le gestionnaire d'événements sera déclenché avec le paramètre `actionId` correspondant à l'**Action ID** défini dans le builder. Vous pouvez créer vos propres IDs, comme "allowNotifications". <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onCustom={onCustom} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, }); ``` </TabItem> </Tabs> <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "actionId": "allow_notifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Cet événement est déclenché lorsque le chargement d'un onboarding est terminé : <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => { console.log('Onboarding loaded:', meta.onboardingId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onFinishedLoading={onFinishedLoading} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` </TabItem> </Tabs> <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton auquel l'action **Close** est assignée. <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Notez que vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding, navigation }) { const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => { navigation.goBack(); }, [navigation]); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onClose={onClose} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onClose(actionId, meta) { await view.dismiss(); return true; }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onClose(actionId, meta) { await view.dismiss(); return true; }, }); ``` </TabItem> </Tabs> <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall à l'intérieur de l'onboarding. Si vous souhaitez ouvrir un paywall après sa fermeture, il existe une méthode plus simple : gérez l'action de fermeture et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La façon la plus fluide de travailler avec les paywalls dans les onboardings est de faire correspondre l'ID d'action à un ID de placement de paywall. <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => { openPaywall(actionId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onPaywall={onPaywall} /> ); } const openPaywall = async (placementId) => { // Implement your paywall opening logic here }; ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> Notez que, sur iOS, une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous affichez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding en arrière-plan par programmation. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue d'onboarding avant de présenter le paywall. ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onPaywall(actionId, meta) { view.dismiss().then(() => { openPaywall(actionId); }); }, }); const openPaywall = async (placementId) => { // Implement your paywall opening logic here }; ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> Notez que, sur iOS, une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous affichez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding en arrière-plan par programmation. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue d'onboarding avant de présenter le paywall. ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onPaywall(actionId, meta) { view.dismiss().then(() => { openPaywall(actionId); }); }, }); const openPaywall = async (placementId) => { // Implement your paywall opening logic here }; ``` </TabItem> </Tabs> <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### Suivi de la navigation \{#tracking-navigation\} Vous recevez un événement d'analytics lorsque divers événements liés à la navigation se produisent pendant le flow d'onboarding : <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => { trackEvent(event.name, meta.onboardingId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onAnalytics(event, meta) { trackEvent(event.name, meta.onboardingId); }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onAnalytics(event, meta) { trackEvent(event.name, meta.onboardingId); }, }); ``` </TabItem> </Tabs> L'objet `event` peut être l'un des types suivants : |Type | Description | |------------|-------------| | `onboardingStarted` | Lorsque l'onboarding a été chargé | | `screenPresented` | Lorsqu'un écran est affiché | | `screenCompleted` | Lorsqu'un écran est terminé. Inclut un `elementId` optionnel (identifiant de l'élément terminé) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque les utilisateurs effectuent une action pour quitter l'écran. | | `secondScreenPresented` | Lorsque le deuxième écran est affiché | | `userEmailCollected` | Déclenché lorsque l'adresse e-mail de l'utilisateur est collectée via le champ de saisie | | `onboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, [attribuez l'ID `final` au dernier écran](design-onboarding). | | `unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `onboardingId` | Identifiant unique du flow d'onboarding | | `screenClientId` | Identifiant de l'écran actuel | | `screenIndex` | Position de l'écran actuel dans le flow | | `screensTotal` | Nombre total d'écrans dans le flow | <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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 } } ``` </Details> --- # File: react-native-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK React Native" description: "Enregistrez et utilisez les données des onboardings dans votre application React Native avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](react-native-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir les flows & paywalls](react-native-get-pb-paywalls) et [Afficher les flows & paywalls](react-native-present-paywalls) pour commencer. ::: Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ, la méthode `onStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Par exemple : ```javascript // Présentation plein écran const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Traiter les données }, }); // Widget intégré <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Traiter les données }, }} /> ``` Consultez le format de l'action [ici](https://react-native.adapty.io/types/onboardingstateupdatedaction). <Details> <summary>Exemples de données enregistrées (le format peut différer selon votre implémentation)</summary> ```javascript // Exemple d'une action de sélection enregistrée { "elementId": "preference_selector", "elementType": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "totalScreens": 3 } } // Exemple d'une action de sélection multiple enregistrée { "elementId": "interests_selector", "elementType": "multi_select", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ], "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "totalScreens": 3 } } // Exemple d'une action de saisie enregistrée { "elementId": "name_input", "elementType": "input", "value": { "type": "text", "value": "John Doe" }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "totalScreens": 3 } } // Exemple d'une action de sélecteur de date enregistrée { "elementId": "birthday_picker", "elementType": "date_picker", "value": { "day": 15, "month": 6, "year": 1990 }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "totalScreens": 3 } } ``` </Details> ## Cas d'utilisation \{#use-cases\} ### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](react-native-setting-user-attributes) avec les données saisies lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci : ```javascript showLineNumbers // Présentation plein écran const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Enregistrer les préférences ou réponses de l'utilisateur if (action.elementType === 'input') { const profileParams = {}; // Associer elementId au champ de profil approprié switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Mettre à jour le profil si des données sont disponibles if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // gérer l'erreur }); } } }, }); // Widget intégré <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Enregistrer les préférences ou réponses de l'utilisateur if (action.elementType === 'input') { const profileParams = {}; // Associer elementId au champ de profil approprié switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Mettre à jour le profil si des données sont disponibles if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // gérer l'erreur }); } } }, }} /> ``` ### Personnaliser les paywalls selon les réponses \{#customize-paywalls-based-on-answers\} En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs une fois l'onboarding terminé. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher différents CTA et produits à différents groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et attribuez des IDs significatifs à ses options. 2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](react-native-setting-user-attributes) pour les utilisateurs. ```javascript showLineNumbers // Présentation plein écran const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Gérer les réponses au quiz et définir des attributs personnalisés if (action.elementType === 'select') { const profileParams = {}; // Associer les réponses au quiz aux attributs personnalisés switch (action.elementId) { case 'experience': // Définir l'attribut personnalisé 'experience' avec la valeur sélectionnée (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Mettre à jour le profil si des données sont disponibles if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // gérer l'erreur }); } } }, }); // Widget intégré <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Gérer les réponses au quiz et définir des attributs personnalisés if (action.elementType === 'select') { const profileParams = {}; // Associer les réponses au quiz aux attributs personnalisés switch (action.elementId) { case 'experience': // Définir l'attribut personnalisé 'experience' avec la valeur sélectionnée (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Mettre à jour le profil si des données sont disponibles if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // gérer l'erreur }); } } }, }} /> ``` 3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](react-native-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall comme [réponse à l'action de ce bouton](react-native-handling-onboarding-events#opening-a-paywall). --- # File: react-native-best-practices --- --- title: "Meilleures pratiques avec le SDK React Native" description: "Modèles de référence pour intégrer le SDK Adapty sur React Native — ordre d'appel, gestion des erreurs et autres règles pour la mise en production." --- <CustomDocCardList /> --- # File: react-native-sdk-call-order --- --- title: "Ordre des appels dans le SDK React Native" description: "Évitez les pertes d'accès premium, les attributions manquantes et les erreurs intermittentes #2002 en appelant les méthodes du SDK Adapty dans le bon ordre." --- `adapty.activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant qu'il n'est pas résolu, le SDK n'a aucun état. Tout appel émis avant ou en parallèle d'`activate()` échoue avec [`#2002 notActivated`](react-native-handle-errors#custom-network-codes). Si votre application authentifie des utilisateurs et que vous récupérez un customer user ID après le lancement, appelez `adapty.identify()` à ce moment-là. N'appelez pas les méthodes liées aux actions utilisateur tant qu'`identify` n'est pas résolu. Les appels qui entrent en concurrence avec lui échouent soit avec [`#3006 profileWasChanged`](react-native-handle-errors#custom-network-codes), soit atterrissent sur le profil anonyme créé à l'activation. Quand cela se produit, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks UID avant d'appeler `adapty.activate`. Sinon, l'identifiant MMP se retrouve sur un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre chemin dépend de deux choses : quand vous connaissez le customer user ID, et si vous utilisez un SDK MMP ou analytics. - **Étapes 2 et 5** : Obligatoires pour chaque application. Activez le SDK, puis appelez les méthodes du SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou analytics (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie des utilisateurs et récupère le customer user ID après le lancement. Si vous disposez du customer user ID au lancement de l'application, passez-le directement dans `activate()` (étape 2a). Cette approche ne crée jamais de profil anonyme, donc l'étape 4 est inutile. | Étape | Appel | Quand | Notes | |-------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre SDK MMP ou analytics (AppsFlyer, Adjust, PostHog, Branch) | Au lancement de l'application, en premier | Attendez le callback UID du MMP, par exemple `getAppsFlyerUID`. | | 2a | `adapty.activate('YOUR_PUBLIC_SDK_KEY', { customerUserId: 'YOUR_USER_ID' })` | Au lancement, après l'étape 1, si vous avez le customer user ID | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `adapty.activate('YOUR_PUBLIC_SDK_KEY')` sans `customerUserId` | Au lancement, après l'étape 1, si vous n'avez pas le customer user ID (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `adapty.updateAttribution(data, source, networkUserId)` pour chaque MMP | Après l'étape 2, avant tout appel lié à une action utilisateur | Nécessaire pour que les identifiants MMP atterrissent sur le bon profil. | | 4 | `await adapty.identify('YOUR_USER_ID')` | Après l'étape 3 (ou l'étape 2 sans MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Toujours `await`. Les appels concurrents pendant `identify` produisent `#3006 profileWasChanged`. | | 5 | `getPaywall`, `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 sans MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne des pertes d'accès premium pour les utilisateurs de retour, un `appsflyer_id` manquant sur les profils, et des paywalls retournés pour la mauvaise audience. ::: ## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent sur une caisse web (Stripe, Paddle) puis installent l'application native, le premier `activate()` sur l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre le customer user ID avant le lancement de l'application (depuis votre flux d'authentification ou le referrer d'installation), passez-le directement dans `activate()`. Sinon, l'achat web est invisible sur l'appareil tant que vous n'appelez pas `identify('YOUR_USER_ID')` puis `restorePurchases`. Pour les métadonnées à envoyer avec chaque caisse web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: react-native-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK React Native" description: "Récupérez les paywalls Adapty de façon fiable : timing, mise en cache et stratégies de secours pour React Native." --- Une récupération fiable d'un paywall dans React Native fait trois choses : un affichage rapide, le retour du paywall ciblé par audience, et un repli gracieux quand le réseau est lent. Les règles ci-dessous couvrent le timing, la mise en cache et les stratégies de secours pour y parvenir. :::tip Ces règles supposent que `adapty.activate()` et `adapty.identify()` ont déjà été résolus. Consultez [Ordre d'appel dans le SDK React Native](react-native-sdk-call-order). ::: ## Règles et pièges \{#rules-and-pitfalls\} | À faire | À éviter | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements en parallèle au démarrage. | Le pré-chargement en masse bloque le thread JS et produit un écran noir pendant la rafale. | | Appelez `getPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `onProfileUpdate`. | Appeler `getPaywall` au montage du composant racine. | L'attribution n'est pas encore arrivée. Le paywall se résout contre l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeoutMs` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre `getPaywall` indéfiniment. | Sans timeout, les utilisateurs sur une connexion médiocre voient un écran vide jusqu'à ce que le réseau réponde — ou ferment l'application. | Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products-react-native) pour la référence des paramètres `fetchPolicy` et `loadTimeoutMs`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour les connexions médiocres \{#tune-for-poor-connectivity\} Pour les marchés avec une connectivité régulièrement médiocre (zones rurales, transports, régions affectées par le routage) : - Définissez `fetchPolicy: .returnCacheDataElseLoad` sur chaque récupération sauf la toute première. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Définissez `loadTimeoutMs` à 3–5 secondes et acceptez le paywall de secours quand le timeout se déclenche. - Ne conditionnez pas l'affichage du paywall à `getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface. --- # File: react-native-show-aa-targeted-paywall --- --- title: "Afficher un paywall ciblé AA au premier lancement dans React Native SDK" description: "Affichez un paywall immédiatement et mettez-le à jour pour les utilisateurs Apple Ads une fois l'attribution appliquée dans React Native, en utilisant AdaptyProfile.appliedAttributionSources." --- L'attribution Apple Ads (AA) arrive de façon asynchrone après `adapty.activate()`. Au premier lancement, elle n'est généralement pas encore disponible, donc `getPaywall` se résout sur l'audience par défaut et les utilisateurs Apple Ads ratent votre paywall segmenté AA. Plutôt que de retarder l'affichage du paywall jusqu'à la réception de l'attribution, affichez-en un immédiatement et actualisez-le dès que l'attribution AA est appliquée — les utilisateurs Apple Ads obtiennent ainsi la variante ciblée, et les autres voient un paywall sans attendre. `AdaptyProfile.appliedAttributionSources` vous indique quand l'attribution AA a été appliquée. ## Avant de commencer \{#before-you-start\} Vous avez besoin de : - Adapty React Native SDK **3.17.1** ou version ultérieure. - Apple Ads configuré pour l'application dans Adapty. Voir [Apple Ads](apple-search-ads). ## Comment ça fonctionne \{#how-it-works\} Après `adapty.activate()`, le SDK demande l'attribution Apple Ads à Apple en arrière-plan et transmet le résultat au backend d'Adapty. Quand AA devient la source d'attribution active pour le profil, le SDK envoie un `AdaptyProfile` mis à jour à votre listener `onLatestProfileLoad`, avec `'apple_search_ads'` dans son tableau `appliedAttributionSources`. Cela vous permet de charger le paywall en deux étapes : 1. Appelez `getPaywall` immédiatement. Sans attribution appliquée, Adapty résout la requête sur l'audience par défaut, et l'utilisateur voit un paywall sans délai. 2. Quand `'apple_search_ads'` apparaît, appelez de nouveau `getPaywall`. Adapty résout alors la requête sur l'audience Apple Ads et renvoie le paywall ciblé, qui remplace le premier. `appliedAttributionSources` peut être vide ou absent. Cela signifie soit que : - L'attribution Apple Ads n'a pas encore été traitée pour ce profil, soit - aucune attribution n'est arrivée du tout. Dans les deux cas, l'étape 1 est sûre — Adapty résout la requête sur l'audience qui correspond à l'état actuel du profil, généralement l'audience par défaut. L'étape 2 s'exécute uniquement quand `'apple_search_ads'` apparaît. :::important À chaque lancement suivant, le profil mis en cache contient déjà `'apple_search_ads'` dans `appliedAttributionSources`, donc le premier `getPaywall` renvoie directement le paywall segmenté Apple Ads — sans deuxième requête ni changement visible. Le flow en deux étapes ne s'applique qu'au premier lancement, pendant que l'attribution est encore en transit. ::: ## Implémentation \{#implementation\} Affichez un paywall immédiatement, puis écoutez l'apparition de `'apple_search_ads'` et actualisez le paywall dès qu'il arrive. 1. **Activez le SDK.** Voir [Installer et configurer le React Native SDK](sdk-installation-reactnative). 2. **Chargez et présentez un paywall** avec `getPaywall` comme d'habitude — n'attendez pas l'attribution. 3. **Abonnez-vous aux mises à jour du profil** avec `adapty.addEventListener('onLatestProfileLoad', …)` et surveillez `'apple_search_ads'`. Quand il apparaît, récupérez de nouveau le paywall et présentez le nouveau. Si vous n'avez pas encore configuré le listener, voir [Écouter les mises à jour d'abonnement](react-native-check-subscription-status#listen-to-subscription-updates) : ```typescript const subscription = adapty.addEventListener('onLatestProfileLoad', async profile => { if (!profile.appliedAttributionSources?.includes('apple_search_ads')) return; const targeted = await adapty.getPaywall(placementId); // present the targeted paywall in place of the first one }); // Call subscription.remove() after the upgrade, or after a timeout (see below). ``` 4. **Arrêtez d'écouter après un délai.** La plupart des utilisateurs ne reçoivent jamais d'attribution Apple Ads, donc supprimez le listener après un moment plutôt que de le garder actif toute la session. Configurez un [paywall de secours](react-native-use-fallback-paywalls) pour le placement afin que l'utilisateur voie toujours quelque chose en cas d'échec d'une requête. ## Exemple complet \{#complete-example\} `onAppleAdsAttribution` se résout dès que l'attribution Apple Ads est appliquée, ou est rejetée après `timeoutMs`. L'exemple ci-dessous charge un paywall immédiatement, puis le récupère de nouveau quand l'attribution arrive — les utilisateurs Apple Ads obtiennent le paywall ciblé, et si l'attribution n'arrive jamais le premier paywall reste en place : ```typescript const APPLE_ADS_SOURCE = 'apple_search_ads'; const placementId = 'YOUR_PLACEMENT_ID'; function hasAppleAdsAttribution(profile: AdaptyProfile): boolean { return profile.appliedAttributionSources?.includes(APPLE_ADS_SOURCE) ?? false; } /** * Resolves once Apple Ads attribution is applied to the profile. * Rejects with a timeout error if attribution never arrives within `timeoutMs`. * Call after `adapty.activate()`. */ export function onAppleAdsAttribution(timeoutMs: number): Promise<void> { return new Promise((resolve, reject) => { let timer: ReturnType<typeof setTimeout> | undefined; let subscription: { remove: () => void } | undefined; const stop = () => { clearTimeout(timer); subscription?.remove(); }; subscription = adapty.addEventListener('onLatestProfileLoad', profile => { if (!hasAppleAdsAttribution(profile)) return; stop(); resolve(); }); timer = setTimeout(() => { stop(); reject(new Error(`Apple Ads attribution timed out after ${timeoutMs}ms`)); }, timeoutMs); }); } let paywall = await adapty.getPaywall(placementId); onAppleAdsAttribution(30_000) .then(() => adapty.getPaywall(placementId)) .then(updated => { paywall = updated; }) .catch(() => { console.log('Apple Ads attribution or loading failed'); }); ``` Au premier lancement, un utilisateur Apple Ads voit brièvement le paywall par défaut avant qu'il soit remplacé. Si vous présentez des paywalls avec le Paywall Builder, réfléchissez à si la re-présentation est acceptable, ou n'appliquez la mise à jour qu'avant l'affichage du paywall. Ajustez `timeoutMs` selon la durée pendant laquelle vous souhaitez maintenir l'écoute — l'attribution qui arrive le fait généralement dans les quelques secondes suivant le lancement. Si votre application écoute déjà `onLatestProfileLoad` à d'autres fins (par exemple, [vérifier le statut de l'abonnement](react-native-check-subscription-status#listen-to-subscription-updates)), vous n'avez pas besoin de modifier quoi que ce soit. `adapty.addEventListener` prend en charge plusieurs listeners indépendants, donc celui-ci s'ajoute sans affecter les autres. --- # File: react-native-test --- --- title: "Test & release in React Native SDK" description: "Apprenez à tester et publier votre application React Native avec le SDK Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application React Native, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu sur iOS et Android. Cela implique de tester l'intégration du SDK ainsi que le flux d'achat réel avec l'environnement sandbox d'Apple et l'environnement de test de Google Play. ## Tester votre application \{#test-your-app\} Pour tester vos achats intégrés de manière approfondie, consultez nos guides de test spécifiques à chaque plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android). ## Préparer la publication \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [liste de vérification avant publication](release-checklist) pour confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats s'effectuent correctement et sont remontés à Adapty - L'accès se déverrouille et se restaure correctement - Les exigences en matière de confidentialité et de validation sont respectées --- # File: react-native-reference --- --- title: "Référence pour le SDK React Native" description: "Documentation de référence pour le SDK React Native d'Adapty." --- Cette page contient la documentation de référence pour le SDK React Native d'Adapty. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://react-native.adapty.io/modules)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](react-native-handle-errors)** - Gestion des erreurs et dépannage --- # File: react-native-handle-errors --- --- title: "Handle errors in React Native SDK" description: "Handle errors in React Native SDK." --- Chaque erreur retournée par le SDK est un `AdaptyErrorCode`. Voici un exemple : :::tip **Activez les logs verbeux avant de déboguer.** La plupart des `AdaptyError`s encapsulent une erreur sous-jacente de StoreKit, Play Billing, réseau ou backend. Avec les logs verbeux activés (`adapty.setLogLevel('verbose')` — voir Journalisation pour [RN pur](sdk-installation-react-native-pure#logging) ou [Expo](sdk-installation-react-native-expo#logging)), l'erreur encapsulée est affichée dans la console, ce qui indique généralement la cause réelle. ::: :::important Si ces solutions ne résolvent pas votre problème, consultez la section [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support et nous aider à vous assister plus efficacement. ::: ```typescript showLineNumbers try { const params: MakePurchaseParamsInput = {}; await adapty.makePurchase(product, params); } catch (error) { if ( error instanceof AdaptyError && error.adaptyCode === getErrorCode(ErrorCode['2']) ) { // payment cancelled } } ``` ## Codes StoreKit système \{#system-storekit-codes\} | Erreur | Code | Solution | |-----|----|-----------| | [unknown](https://developer.apple.com/documentation/storekit/skerror/code/unknown) | 0 | Code d'erreur indiquant qu'une erreur inconnue ou inattendue s'est produite. <br/> Réessayez ou consultez la section [Autres problèmes](#other-issues). | | [clientInvalid](https://developer.apple.com/documentation/storekit/skerror/code/clientinvalid) | 1 | Ce code d'erreur indique que le client n'est pas autorisé à effectuer l'action tentée. | | [paymentCancelled](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 2 | <p>Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.</p><p>Aucune action n'est requise, mais en termes de logique métier, vous pouvez proposer une réduction à votre utilisateur ou lui rappeler plus tard.</p> | | [paymentInvalid](https://developer.apple.com/documentation/storekit/skerror/code/paymentinvalid) | 3 | Cette erreur indique que l'un des paramètres de paiement n'a pas été reconnu par l'App Store. | | [paymentNotAllowed](https://developer.apple.com/documentation/storekit/skerror/code/paymentnotallowed) | 4 | Ce code d'erreur indique que l'utilisateur n'est pas autorisé à valider des paiements. | | [storeProductNotAvailable](https://developer.apple.com/documentation/storekit/skerror/code/storeproductnotavailable) | 5 | Ce code d'erreur indique que le produit demandé n'est pas disponible dans le store. <br/> Essayez de réinstaller l'application. | | [cloudServicePermissionDenied](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicepermissiondenied) | 6 | Ce code d'erreur indique que l'utilisateur n'a pas autorisé l'accès aux informations du service Cloud. | | [cloudServiceNetworkConnectionFailed](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicenetworkconnectionfailed) | 7 | Ce code d'erreur indique que l'appareil n'a pas pu se connecter au réseau. | | [cloudServiceRevoked](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicerevoked/) | 8 | Ce code d'erreur indique que l'utilisateur a révoqué l'autorisation d'utiliser ce service Cloud. | | [privacyAcknowledgementRequired](https://developer.apple.com/documentation/storekit/skerror/code/privacyacknowledgementrequired) | 9 | Ce code d'erreur indique que l'utilisateur n'a pas encore accepté la politique de confidentialité d'Apple. | | [unauthorizedRequestData](https://developer.apple.com/documentation/storekit/skerror/code/unauthorizedrequestdata) | 10 | Ce code d'erreur indique que l'application tente d'utiliser une propriété pour laquelle elle ne dispose pas des droits requis. | | [invalidOfferIdentifier](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferidentifier) | 11 | <p>L'[`identifiant`](https://developer.apple.com/documentation/storekit/skpaymentdiscount/identifier) de l'offre n'est pas valide. Par exemple, vous n'avez pas configuré d'offre avec cet identifiant dans l'App Store, ou vous avez révoqué l'offre.</p><p>Assurez-vous de configurer les offres souhaitées dans AppStore Connect et de transmettre un identifiant d'offre valide.</p> | | [invalidSignature](https://developer.apple.com/documentation/storekit/skerror/code/invalidsignature) | 12 | Ce code d'erreur indique que la signature dans une réduction de paiement n'est pas valide. | | [missingOfferParams](https://developer.apple.com/documentation/storekit/skerror/code/missingofferparams) | 13 | Ce code d'erreur indique que des paramètres sont manquants dans une réduction de paiement. | | [invalidOfferPrice](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferprice/) | 14 | Ce code d'erreur indique que le prix que vous avez spécifié dans App Store Connect n'est plus valide. Les offres doivent toujours représenter un prix réduit. | ## Codes Android personnalisés \{#custom-android-codes\} | Erreur | Code | Solution | |-----|----|-----------| | adaptyNotInitialized | 20 | Vous devez configurer correctement le SDK Adapty via la méthode `Adapty.activate`. Découvrez comment procéder [pour React Native](sdk-installation-reactnative). | | productNotFound | 22 | Cette erreur indique que le produit demandé pour l'achat n'est pas disponible dans le store. | | invalidJson | 23 | Le JSON du paywall n'est pas valide. Corrigez-le dans l'Adapty Dashboard. Consultez la rubrique [Personnaliser le paywall avec Remote Config](customize-paywall-with-remote-config) pour plus de détails. | | currentSubscriptionToUpdateNotFoundInHistory | 24 | L'abonnement d'origine à renouveler est introuvable. | | pendingPurchase | 25 | Cette erreur indique que l'état de l'achat est en attente plutôt qu'acheté. Consultez la page [Gestion des transactions en attente](https://developer.android.com/google/play/billing/integrate#pending) dans la documentation Android Developer pour plus de détails. | | billingServiceTimeout | 97 | Cette erreur indique que la requête a atteint le délai d'attente maximal avant que Google Play puisse répondre. Cela peut être causé, par exemple, par un retard dans l'exécution de l'action demandée par l'appel à la bibliothèque Play Billing. | | featureNotSupported | 98 | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. | | billingServiceDisconnected | 99 | Cette erreur fatale indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. | | billingServiceUnavailable | 102 | Cette erreur transitoire indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau entre l'appareil client et les services Google Play Billing. | | billingUnavailable | 103 | <p>Cette erreur indique qu'une erreur de facturation utilisateur s'est produite pendant le processus d'achat. Voici des exemples de situations pouvant provoquer cette erreur :</p><p></p><p>1\. L'application Play Store sur l'appareil de l'utilisateur est obsolète.</p><p>2. L'utilisateur se trouve dans un pays non pris en charge.</p><p>3. L'utilisateur est un utilisateur d'entreprise, et son administrateur a désactivé les achats pour les utilisateurs.</p><p>4. Google Play n'est pas en mesure de débiter le moyen de paiement de l'utilisateur. Par exemple, la carte de crédit de l'utilisateur a peut-être expiré.</p><p>5. L'utilisateur n'est pas connecté à l'application Play Store.</p> | | developerError | 105 | Il s'agit d'une erreur fatale indiquant que vous utilisez incorrectement une API. | | billingError | 106 | Il s'agit d'une erreur fatale indiquant un problème interne avec Google Play lui-même. | | itemAlreadyOwned | 107 | Le produit consommable a déjà été acheté. | | itemNotOwned | 108 | Cette erreur indique que l'action demandée sur l'article a échoué sin | ## Codes StoreKit personnalisés \{#custom-storekit-codes\} | Erreur | Code | Solution | |-----|----|-----------| | noProductIDsFound | 1000 | <p>Cette erreur indique qu'aucun des produits que vous avez demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le.</p><p>Si vous rencontrez cette erreur, suivez les étapes de la section [Correction de l'erreur Code-1000 `noProductIDsFound`](InvalidProductIdentifiers-react-native).</p> | | productRequestFailed | 1002 | <p>Impossible de récupérer les produits disponibles pour le moment. Cause possible :</p><p></p><p>- Aucun cache n'a encore été créé et il n'y a pas de connexion Internet en même temps.</p> | | cantMakePayments | 1003 | Les achats intégrés ne sont pas autorisés sur cet appareil. Consultez le [guide](cantMakePayments-react-native) de dépannage. | | noPurchasesToRestore | 1004 | Cette erreur indique que Google Play n'a pas trouvé l'achat à restaurer. | | cantReadReceipt | 1005 | <p>Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.</p><p>Aucune action n'est requise, mais en termes de logique métier, vous pouvez proposer une réduction à votre utilisateur ou lui rappeler plus tard.</p> | | productPurchaseFailed | 1006 | L'achat du produit a échoué. Cela encapsule une erreur StoreKit sous-jacente — lisez l'erreur encapsulée (ou activez les logs verbeux pour la voir dans la console) pour connaître la raison réelle. L'erreur encapsulée est généralement l'un des codes StoreKit 0 à 14 du tableau ci-dessus — le plus souvent `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` ou `invalidOfferPrice`. Si vous ne pouvez pas identifier une raison précise, essayez un nouveau [profil sandbox](test-purchases-in-sandbox) ; si le problème persiste, contactez le support Apple. | | refreshReceiptFailed | 1010 | Cette erreur indique que le reçu n'a pas été reçu. Applicable uniquement à StoreKit 1. | | receiveRestoredTransactionsFailed | 1011 | La restauration des achats a échoué. | ## Codes réseau personnalisés \{#custom-network-codes\} | Erreur | Code | Solution | | :------------------- | :--- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | notActivated | 2002 | Le SDK Adapty n'est pas activé. <br/> Ce problème survient généralement lorsqu'un écran de démarrage ou un hook d'interface précoce appelle des méthodes Adapty avant que `adapty.activate` ne retourne. Le symptôme est intermittent et peut ne pas se reproduire sur simulateur car le timing sur appareil réel est différent. Utilisez `await` sur `activate` avant de planifier tout autre appel SDK. Voir [Ordre des appels dans le SDK React Native](react-native-sdk-call-order) pour la séquence complète. | | badRequest | 2003 | Requête incorrecte. <br/> Assurez-vous d'avoir effectué toutes les étapes nécessaires pour [intégrer l'App Store](app-store-connection-configuration). | | serverError | 2004 | Erreur serveur. <br/> Réessayez après un certain temps. Si le problème n'est pas résolu, contactez l'équipe support Adapty. | | networkFailed | 2005 | Cette erreur indique des problèmes de connexion réseau sur l'appareil de l'utilisateur. <br/> Essayez de désactiver le VPN ou de passer du réseau cellulaire au Wi-Fi, ou inversement. | | decodingFailed | 2006 | Cette erreur indique que le décodage de la réponse a échoué. <br/> Vérifiez votre code et assurez-vous que les paramètres envoyés sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. | | encodingFailed | 2009 | Cette erreur indique que l'encodage de la requête a échoué. | | missingURL | 2010 | L'URL demandée est nil. | | analyticsDisabled | 3000 | Nous ne pouvons pas gérer les événements d'analytics, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). | | wrongParam | 3001 | Cette erreur indique que certains de vos paramètres ne sont pas corrects. <br/> Si vous utilisez le Paywall Builder d'Adapty et ne pouvez pas afficher un paywall à cause de cette erreur, activez **Show on device** dans le Paywall Builder.<br/> Une autre cause possible est que la version du fichier [paywall de secours](fallback-paywalls) local ne correspond pas à la version du SDK. Téléchargez un nouveau fichier depuis le tableau de bord. | | activateOnceError | 3005 | Il n'est pas possible d'appeler la méthode `.activate` plus d'une fois. | | profileWasChanged | 3006 | Le profil utilisateur a été modifié pendant l'opération. <br/> Cela se produit lorsqu'une méthode est appelée pendant qu'`adapty.identify` est toujours en cours — l'appel en cours atterrit sur un profil qui est sur le point d'être remplacé, et le SDK le rejette. Utilisez toujours `await` sur `identify` avant tout appel d'action utilisateur. Voir [Ordre des appels dans le SDK React Native](react-native-sdk-call-order). | | unsupportedData | 3007 | Cette erreur indique que le format de données n'est pas pris en charge par le SDK. | | persistingDataError | 3100 | Une erreur s'est produite lors de la sauvegarde des données. | | fetchTimeoutError | 3101 | Cette erreur indique que l'opération de récupération a expiré. | ## Autres problèmes \{#other-issues\} Si vous n'avez pas encore trouvé de solution, voici les prochaines étapes possibles : - **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de passer aux dernières versions du SDK, car elles sont plus stables et incluent des corrections pour les problèmes connus. - **Contacter l'équipe support ou obtenir l'aide de la communauté** sur le [forum de support](https://adapty.featurebase.app/). - **Contacter l'équipe support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou si cela n'a pas résolu le problème, contactez notre équipe support. Notez que votre problème sera résolu plus rapidement si vous [activez les logs verbeux](sdk-installation-reactnative) et partagez les logs avec l'équipe. Vous pouvez également joindre des extraits de code pertinents. --- # File: InvalidProductIdentifiers-react-native --- --- title: "Correction de l'erreur Code-1000 noProductIDsFound dans le SDK React Native" description: "Résolvez les erreurs d'identifiants de produit invalides lors de la gestion des abonnements dans Adapty." --- L'erreur avec le code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, vous pouvez l'ignorer en toute sécurité. Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre : ## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\} 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Vérifier les produits \{#step-3-check-products\} 1. Rendez-vous dans **App Store Connect** et accédez à [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. Vos produits apparaissent dans la section **Subscriptions**. 3. Assurez-vous que le produit que vous testez est marqué **Ready to Submit**. <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Comparez l'identifiant du produit dans le tableau avec celui de l'onglet [**Products**](https://app.adapty.io/products) dans l'Adapty Dashboard. Si les identifiants ne correspondent pas, copiez l'identifiant du produit depuis le tableau et [créez un produit](create-product) avec cet identifiant dans l'Adapty Dashboard. <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3. Vérifier la disponibilité du produit \{#step-4-check-product-availability\} 1. Retournez dans **App Store Connect** et ouvrez la même section **Subscriptions**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis sont bien listés. <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. Retournez dans la section **Monetization** → **Subscriptions** d'**App Store Connect**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à **Subscription Pricing** et développez la section **Current Pricing for New Subscribers**. <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Vérifiez que tous les prix requis sont bien listés. <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Vérifier le statut des applications payantes, le compte bancaire et les formulaires fiscaux \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. Sur la page d'accueil d'[**App Store Connect**](https://appstoreconnect.apple.com/), cliquez sur **Business**. <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez le nom de votre entreprise. <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Faites défiler vers le bas et vérifiez que votre **Paid Apps Agreement**, votre **Bank Account** et vos **Tax forms** affichent tous le statut **Active**. <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En suivant ces étapes, vous devriez pouvoir résoudre l'avertissement `InvalidProductIdentifiers` et rendre vos produits disponibles dans le store. ## Étape 6. Recréer le produit s'il est bloqué \{#step-6-recreate-the-product-if-its-stuck\} Les étapes 1 à 5 peuvent toutes être validées — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK retourne toujours `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre de produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit. Supprimez le produit dans App Store Connect et recréez-le avec le même identifiant de produit. Attendez jusqu'à 24 heures après la recréation pour que la propagation s'effectue. --- # File: cantMakePayments-react-native --- --- title: "Correction de l'erreur Code-1003 cantMakePayment dans le SDK React Native" description: "Résoudre l'erreur de paiement lors de la gestion des abonnements dans Adapty." --- L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil. Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes : - Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous. - Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous. ## Problème : Restrictions de l'appareil \{#issue-device-restrictions\} | Problème | Solution | |--------------------------------|-------------------------------------------------------------------------------------------------------------| | Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) | | Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte | | Restrictions régionales | Utilisez un compte App Store d'une région prise en charge | ## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\} Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat. Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK. --- # File: react-native-sdk-migration-guides --- --- title: "Guides de migration du SDK React Native" description: "Guides de migration pour les versions du SDK Adapty React Native." --- Cette page regroupe tous les guides de migration pour le SDK Adapty React Native. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir les instructions détaillées : - **[Migrer vers v4.0](migration-to-react-native-sdk-v4)** - **[Migrer vers v3.14](migration-react-native-314)** - **[Migrer vers v3.8](react-native-migration-guide-380)** - **[Migrer vers v3.4](migration-to-react-native-sdk-34)** - **[Migrer vers v3.3](migration-to-react-native330)** - **[Migrer vers v3.0](migration-to-react-native-sdk-v3)** --- # File: migration-to-react-native-sdk-v4 --- --- title: "Migrer le SDK Adapty React Native vers la v. 4.0" description: "Migrez vers le SDK Adapty React Native v4.0 en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder." --- Le SDK Adapty React Native 4.0 introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucune modification de configuration n'est nécessaire côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall(placementId, locale?, params?)` | `adapty.getFlow(placementId, params?)` | | `adapty.getPaywallForDefaultAudience(placementId, locale?, params?)` | `adapty.getFlowForDefaultAudience(placementId, params?)` | | `adapty.getPaywallProducts(paywall)` | `adapty.getPaywallProducts(flow)` | | `adapty.logShowPaywall(paywall)` | `adapty.logShowFlow(flow)` | | `AdaptyPaywall` (type) | `AdaptyFlow` | | `createPaywallView(paywall)` | `createFlowView(flow)` | | `AdaptyPaywallView` (composant) | `AdaptyFlowView` | | `EventHandlers` (type) | `FlowEventHandlers` | | `onPaywallShown` | `onAppeared` | | `onPaywallClosed` | `onDisappeared` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` garde son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` prend désormais un `AdaptyFlow`. Les méthodes `getFlow` et `getFlowForDefaultAudience` n'acceptent plus de paramètre `locale` — passez-le à `createFlowView` à la place. Les méthodes de vue `present`, `dismiss`, `setEventHandlers` et `showDialog`, ainsi que les gestionnaires d'événements `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` et `onAndroidSystemBack` conservent les mêmes noms qu'en v3. Certains comportements par défaut ont changé — voir [Changements de comportement par défaut](#default-behavior-changes). ## Version iOS minimale \{#minimum-ios-version\} Le SDK React Native Adapty 4.0 fait passer la version minimale de déploiement iOS de iOS 13.0 à **iOS 15.0**. Définissez votre cible de déploiement iOS à 15.0 ou supérieure avant de procéder à la mise à jour. ## Installation \{#installation\} ### Mettre à jour le package Mettez à jour le package `react-native-adapty` vers la v4.0 : ```bash showLineNumbers npm install react-native-adapty@4.0.0 # or yarn add react-native-adapty@4.0.0 ``` ### iOS : les SDK natifs passent désormais par Swift Package Manager [Le dépôt de specs CocoaPods passe en lecture seule en décembre 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), aussi à partir de la v4, les SDK natifs `Adapty`, `AdaptyUI` et `AdaptyPlugin` **ne sont plus inclus en tant que sous-dépendances CocoaPods** — le podspec les récupère via **Swift Package Manager** (grâce au helper `spm_dependency`). Deux points à respecter : - **React Native 0.75 ou version ultérieure** — nécessaire pour le helper de podspec `spm_dependency`. Sur une version plus ancienne, `pod install` échoue avec une erreur explicite ; mettez d'abord à jour React Native, ou restez sur `react-native-adapty` 3.x. - **Frameworks dynamiques** — les dépendances SPM nécessitent un linkage dynamique. La façon de l'activer diffère entre Expo et bare React Native. #### Expo Ajoutez le plugin de configuration [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/) et définissez les frameworks iOS en dynamique dans `app.json` (ou `app.config.js`) : ```json showLineNumbers title="app.json" { "expo": { "plugins": [ [ "expo-build-properties", { "ios": { "useFrameworks": "dynamic", "buildReactNativeFromSource": true } } ] ] } } ``` `buildReactNativeFromSource` est requis sur **Expo SDK 57 et versions ultérieures**. Expo SDK 57 embarque un framework React Native précompilé dont les en-têtes sont inaccessibles aux autres packages lorsque les frameworks sont dynamiques, ce qui provoque des erreurs de build iOS comme `'React/RCTBridge.h' file not found` dans `expo-updates` ou `@expo/ui`. Compiler React Native depuis les sources permet d'éviter ce conflit, au prix de builds iOS plus longs. Sur Expo SDK 56 et versions antérieures, vous pouvez omettre cette option. Installez ensuite le plugin et régénérez le projet natif : ```bash showLineNumbers npx expo install expo-build-properties npx expo prebuild --clean ``` #### Bare React Native Ajoutez les frameworks dynamiques à votre cible iOS, puis réinstallez les pods : ```ruby showLineNumbers title="ios/Podfile" use_frameworks! :linkage => :dynamic ``` ```bash showLineNumbers cd ios && pod install --repo-update ``` Si vous avez précédemment ajouté `Adapty`, `AdaptyUI` ou `AdaptyPlugin` en tant que sous-dépendances CocoaPods, supprimez d'abord toute ligne explicite `pod 'Adapty'`, `pod 'AdaptyUI'` ou `pod 'AdaptyPlugin'` de votre `Podfile`. :::warning Passer de la liaison statique par défaut aux frameworks dynamiques peut entrer en conflit avec des bibliothèques qui ne prennent pas encore en charge les en-têtes modulaires, et est incompatible avec Flipper. Si vous rencontrez des problèmes de compilation, consultez cet [article sur l'intégration de Swift Package Manager avec les bibliothèques React Native](https://www.callstack.com/blog/integrating-swift-package-manager-with-react-native-libraries). ::: Consultez [Installer le SDK Adapty](sdk-installation-reactnative) pour la configuration complète. ## Récupérer des flows \{#fetching-flows\} ### getPaywall → getFlow Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et le paramètre `locale` se déplace de l'appel de récupération vers `createFlowView` ; pour les paywalls personnalisés, toutes les locales sont retournées dans `flow.remoteConfigs` : ```diff showLineNumbers - const paywall = await adapty.getPaywall('YOUR_PLACEMENT_ID', 'en'); + const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); + const view = await createFlowView(flow, { locale: 'en' }); ``` `locale` reste optionnel dans `createFlowView` : si vous l'omettez, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne possède pas de version `en`. Cette fonctionnalité nécessite le SDK 4.0.2 ou une version ultérieure — voir [Localisations et codes de langue](react-native-localizations-and-locale-codes). `getPaywallForDefaultAudience` est renommé de la même façon : ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience('YOUR_PLACEMENT_ID', 'en'); + const flow = await adapty.getFlowForDefaultAudience('YOUR_PLACEMENT_ID'); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` conserve son nom mais prend désormais un `AdaptyFlow` : ```diff showLineNumbers - const products = await adapty.getPaywallProducts(paywall); + const products = await adapty.getPaywallProducts(flow); ``` ### Fichiers de secours \{#fallback-files\} Le format des fichiers de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le à votre application. ## Modèle de données \{#data-model\} `getFlow` renvoie un `AdaptyFlow` au lieu d'un `AdaptyPaywall`, et la structure de l'objet a changé : | Champ v3 `AdaptyPaywall` | Champ v4 `AdaptyFlow` | Action | |---|---|---| | `remoteConfig?` (unique) | `remoteConfigs?: AdaptyRemoteConfig[]` (tableau) | Un flow contient un Remote Config par langue configurée. Lisez celui qui correspond à l'utilisateur : `flow.remoteConfigs?.find((c) => c.lang === 'en')`. | | `products` | `flow.paywalls[i].productIdentifiers` | Les identifiants de produits se trouvent désormais sur chaque variante du flow, pas sur le flow lui-même. | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Déplacé du flow vers chaque variante de paywall. | | `version?: number` | `flowVersionId?: string` | Renommé, et le type a changé de `number` à `string`. | | `hasViewConfiguration` | supprimé | Supprimez tout contrôle `hasViewConfiguration` de votre code. | | `requestLocale` | supprimé | La locale ne fait plus partie du modèle. | | _(nouveau)_ | `paywalls: AdaptyFlowPaywall[]` | Chaque entrée correspond à une variante de paywall dans le flow. | | _(nouveau)_ | `responseCreatedAt: number` | Horodatage de la réponse serveur, en millisecondes. | Product identifiers moved from the flow to each variation: ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Méthodes de paywall web \{#web-paywall-methods\} `openWebPaywall` et `createWebPaywallUrl` conservent leurs noms, mais le premier argument est désormais un `AdaptyFlowPaywall` (une variante de flow) au lieu d'un `AdaptyPaywall`. Vous pouvez toujours passer un `AdaptyPaywallProduct`. ```diff showLineNumbers const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); - await adapty.openWebPaywall(paywall); + await adapty.openWebPaywall(flow.paywalls[0]); ``` ## Suivi des vues de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` est renommé en `logShowFlow` et prend désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord. ```diff showLineNumbers - await adapty.logShowPaywall(paywall); + await adapty.logShowFlow(flow); ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage de flows ou de paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit automatiquement ces vues. ## Afficher des flows \{#displaying-flows\} ### createPaywallView → createFlowView Renommez la fonction factory et passez l'`AdaptyFlow`. Les méthodes du contrôleur retourné (`present`, `dismiss`, `setEventHandlers`, `showDialog`) restent inchangées : ```diff showLineNumbers - import { createPaywallView } from 'react-native-adapty'; + import { createFlowView } from 'react-native-adapty'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` ### AdaptyPaywallView → AdaptyFlowView Si vous effectuez le rendu avec le composant React, renommez-le et passez la prop `flow` : ```diff showLineNumbers - import { AdaptyPaywallView } from 'react-native-adapty'; + import { AdaptyFlowView } from 'react-native-adapty'; - <AdaptyPaywallView paywall={paywall} /* … */ /> + <AdaptyFlowView flow={flow} /* … */ /> ``` :::note Un flow view créé avec `createFlowView` est à usage unique : après avoir appelé `dismiss()`, la vue est détruite. Appelez donc à nouveau `createFlowView` pour afficher le flow une nouvelle fois. Un `AdaptyFlowView` intégré est fermé en le démontant — retourner `true` depuis un gestionnaire ne ferme pas une vue intégrée, modifiez donc votre propre état à la place, par exemple dans `onCloseButtonPress`. ::: ## Gestion des événements \{#handling-events\} L'interface du gestionnaire d'événements est renommée de `EventHandlers` en `FlowEventHandlers`, et trois callbacks sont renommés. Les corps des gestionnaires existants n'ont pas besoin de modification — il suffit de les renommer : ```diff showLineNumbers - onPaywallShown: () => { /* … */ }, + onAppeared: () => { /* … */ }, - onPaywallClosed: () => { /* … */ }, + onDisappeared: () => { /* … */ }, - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` Tous les autres gestionnaires d'événements conservent leur nom. Deux d'entre eux reçoivent également un second argument : `onPurchaseCompleted` devient `(purchaseResult, product)` et `onPurchaseFailed` devient `(error, product)`, où `product` est l'`AdaptyPaywallProduct` concerné. Consultez [Gérer les événements de flow et de paywall](react-native-handling-events-1) pour la liste complète. :::note `onDisappeared` se déclenche uniquement pour un flow présenté de façon modale avec `createFlowView().present()`. Le composant `AdaptyFlowView` n'expose pas cet événement en tant que prop — pour fermer une vue intégrée, il suffit de la démonter. ::: v4 ajoute également quelques fonctionnalités auxquelles vous pouvez adhérer : - Les méthodes `adapty.openWebUrl(url, openIn?)` et `adapty.requestAppReview()` — elles alimentent les handlers par défaut `onUrlPress` et `onRequestAppReview`, donc les URLs et les invites d'avis applicatif sont gérés nativement sans configuration. Ne les appelez directement que si vous surchargez ces handlers. - Gestion des achats en mode observateur dans les flows via les nouveaux handlers `onObserverPurchaseInitiated` / `onObserverRestoreInitiated`. Voir [Gérer les achats en mode observateur](react-native-handling-events-1#handle-purchases-in-observer-mode). ## APIs supprimées et dépréciées \{#removed-and-deprecated-apis\} ### setFallbackPaywalls → setFallback `setFallbackPaywalls` est supprimé. Utilisez `setFallback`, qui prend le même argument : ```diff showLineNumbers - await adapty.setFallbackPaywalls(fileLocation); + await adapty.setFallback(fileLocation); ``` ### Exports supprimés \{#removed-exports\} Ces symboles ne sont plus exportés depuis `react-native-adapty`. Supprimez leurs imports : - **`AdaptyPaywall`** : Utilisez `AdaptyFlow` à la place. - **`ProductReference`** : Utilisez `AdaptyProductIdentifier`, accessible via `flow.paywalls[i].productIdentifiers`. - **`AdaptyPaywallBuilder`** : Supprimé. Les flows et les paywalls s'affichent nativement. - **`AdaptyAndroidSubscriptionUpdateParameters`** : Utilisez la structure imbriquée `subscriptionUpdateParams` (voir ci-dessous). ### activate: lockMethodsUntilReady `lockMethodsUntilReady` est supprimé et ce comportement est désormais toujours actif. Retirez-le de votre appel `activate` — le conserver empêche la compilation : ```diff showLineNumbers - await adapty.activate('PUBLIC_SDK_KEY', { lockMethodsUntilReady: true }); + await adapty.activate('PUBLIC_SDK_KEY'); ``` ### makePurchase : mise à jour des abonnements Android \{#makepurchase-android-subscription-update\} La structure plate de mise à jour d'abonnement Android est supprimée. Déplacez `oldSubVendorProductId` et `prorationMode` dans un objet `subscriptionUpdateParams` imbriqué, et conservez `isOfferPersonalized` au niveau supérieur. Consultez [Effectuer des achats](react-native-making-purchases) pour l'exemple complet. ### Android : marges de zone de sécurité \{#android-safe-area-paddings\} La ressource booléenne Android `<bool name="adapty_paywall_enable_safe_area_paddings">…</bool>` est supprimée. Retirez-la de `res/values/bools.xml` et contrôlez les marges de zone de sécurité au moment de l'exécution avec le paramètre `android.enableSafeArea` lors de la création de la vue du flow. Par défaut, cette valeur est `true` pour la présentation modale et `false` pour le composant intégré : ```typescript showLineNumbers const view = await createFlowView(flow, { android: { enableSafeArea: false, }, }); ``` ### Mode mock \{#mock-mode\} Si vous exécutez le SDK en mode mock (Expo Go ou prévisualisation web), renommez la clé de configuration mock `paywalls` en `flows`. ## Changements de comportement par défaut \{#default-behavior-changes\} Ces changements ne causent pas d'erreurs de compilation ; testez-les à l'exécution : - **`onAndroidSystemBack`** : Le comportement par défaut a changé : la vue reste ouverte au lieu de se fermer. Pour rétablir l'ancien comportement, retournez `true` depuis le handler. - **`onPurchaseCompleted`** : Le comportement par défaut a changé : la vue reste toujours ouverte au lieu de se fermer (sauf en cas d'annulation par l'utilisateur). Pour rétablir l'ancien comportement, retournez `purchaseResult.type !== 'user_cancelled'` depuis le handler. - **`onRestoreCompleted`** : Le comportement par défaut a changé : la vue reste ouverte au lieu de se fermer après une restauration réussie. Pour rétablir l'ancien comportement, retournez `true` depuis le handler. - **`onUrlPress`** : Par défaut, l'URL s'ouvre désormais via la couche native, en respectant le paramètre de navigateur intégré ou externe défini dans le tableau de bord. Remplacez le handler pour gérer vous-même l'ouverture des URL. ## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\} L'ancienne API onboarding est dépréciée dans la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, mais sera supprimée dans une version future — prévoyez donc la migration de vos onboardings vers le Flow Builder. Symboles dépréciés : `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView` et `AdaptyOnboardingView`. --- # File: migration-react-native-314 --- --- title: "Migrer le SDK Adapty React Native vers la v3.14" description: "Migrez vers le SDK Adapty React Native v3.14 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty React Native 3.14.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté : - La méthode `registerEventHandlers` a été remplacée par la méthode `setEventHandlers`. - Dans `AdaptyOnboardingView`, les gestionnaires d'événements sont désormais passés en tant que props individuelles plutôt que sous forme d'objet `eventHandlers` - Un nouveau style d'import simplifié a été introduit pour les composants UI - La méthode `logShowOnboarding` a été supprimée - La version minimale de React Native a été mise à jour vers 0.73.0 - Le style de présentation iOS par défaut pour les paywalls et les onboardings est passé de page sheet à plein écran ## Remplacer `registerEventHandlers` par `setEventHandlers` \{#replace-registereventhandlers-with-seteventhandlers\} La méthode `registerEventHandlers` utilisée pour travailler avec Adapty Paywall et Onboarding Builder a été remplacée par la méthode `setEventHandlers`. Si vous utilisez l'Adapty Paywall Builder et/ou l'Adapty Onboarding Builder, trouvez `registerEventHandlers` dans le code de votre application et remplacez-le par `setEventHandlers`. Ce changement a été introduit pour clarifier le comportement de la méthode : les gestionnaires fonctionnent désormais un à la fois car chacun retourne `true`/`false`, et avoir plusieurs gestionnaires pour un même événement rendait le comportement résultant peu clair. Notez que lors de l'utilisation de composants React comme `AdaptyOnboardingView` ou `AdaptyPaywallView`, vous n'avez pas besoin de retourner `true`/`false` depuis les gestionnaires d'événements puisque vous contrôlez la visibilité du composant via votre propre gestion d'état. Les valeurs de retour ne sont nécessaires que pour la présentation d'écrans modaux où le SDK gère le cycle de vie de la vue. :::important 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. ::: ```diff showLineNumbers - const unsubscribe = view.registerEventHandlers({ - // your event handlers - }) const unsubscribe = view.setEventHandlers({ // your event handlers }) ``` ## Mettre à jour les chemins d'import pour les composants UI \{#update-import-paths-for-ui-components\} Le SDK Adapty 3.14.0 introduit un style d'import simplifié pour les composants UI. Au lieu d'importer depuis `react-native-adapty/dist/ui`, vous pouvez désormais importer directement depuis `react-native-adapty`. Le nouveau style d'import est plus cohérent avec les pratiques standard de React Native et rend les instructions d'import plus lisibles. Si vous utilisez des composants UI comme `AdaptyPaywallView` ou `AdaptyOnboardingView`, mettez à jour vos imports comme indiqué ci-dessous : ```diff showLineNumbers - import { AdaptyPaywallView } from 'react-native-adapty/dist/ui'; + import { AdaptyPaywallView } from 'react-native-adapty'; - import { AdaptyOnboardingView } from 'react-native-adapty/dist/ui'; + import { AdaptyOnboardingView } from 'react-native-adapty'; - import { createPaywallView } from 'react-native-adapty/dist/ui'; + import { createPaywallView } from 'react-native-adapty'; - import { createOnboardingView } from 'react-native-adapty/dist/ui'; + import { createOnboardingView } from 'react-native-adapty'; ``` :::note Pour la compatibilité ascendante, l'ancien style d'import (`react-native-adapty/dist/ui`) est toujours pris en charge. Cependant, nous recommandons d'utiliser le nouveau style d'import pour plus de cohérence et de clarté. ::: ## Mettre à jour les gestionnaires d'événements d'onboarding dans le composant React \{#update-onboarding-event-handlers-in-the-react-component\} Les gestionnaires d'événements pour les onboardings ont été déplacés en dehors de l'objet `eventHandlers` dans `AdaptyOnboardingView`. Si vous affichez des onboardings avec `AdaptyOnboardingView`, mettez à jour la structure de gestion des événements. :::important Notez la façon dont nous recommandons d'implémenter les gestionnaires d'événements. Pour éviter de recréer des objets à chaque rendu, utilisez `useCallback` pour les fonctions qui gèrent les événements. ::: ```diff showLineNumbers import React, { useCallback } from 'react'; - import { AdaptyOnboardingView } from 'react-native-adapty/dist/ui'; + import { AdaptyOnboardingView } from 'react-native-adapty'; + import type { OnboardingEventHandlers } from 'react-native-adapty'; + + function MyOnboarding({ onboarding }) { + const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); + const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); + const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); + const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); + const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); + const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); + const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); + return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} - eventHandlers={{ - onAnalytics(event, meta) { /* ... */ }, - onClose(actionId, meta) { /* ... */ }, - onCustom(actionId, meta) { /* ... */ }, - onPaywall(actionId, meta) { /* ... */ }, - onStateUpdated(action, meta) { /* ... */ }, - onFinishedLoading(meta) { /* ... */ }, - onError(error) { /* ... */ }, - }} + onAnalytics={onAnalytics} + onClose={onClose} + onCustom={onCustom} + onPaywall={onPaywall} + onStateUpdated={onStateUpdated} + onFinishedLoading={onFinishedLoading} + onError={onError} /> ); + } ``` :::note Pour la compatibilité ascendante, la prop `eventHandlers` est toujours prise en charge mais est dépréciée. Nous recommandons de migrer vers les props individuelles de gestionnaires d'événements comme indiqué ci-dessus. ::: ## Supprimer `logShowOnboarding` \{#delete-logshowonboarding\} Dans le SDK Adapty 3.14.0, nous avons supprimé la méthode `logShowOnboarding` du SDK. Si vous utilisiez cette méthode, elle ne sera plus disponible lorsque vous mettrez à jour le SDK vers la version 3.14 ou ultérieure. À la place, vous pouvez [créer des onboardings dans le builder d'onboarding no-code d'Adapty](onboardings). Les analytics pour ces onboardings sont suivies automatiquement, et vous disposez de nombreuses options de personnalisation. ## Mettre à jour React Native \{#update-react-native\} À partir du SDK Adapty 3.14.0, la version minimale prise en charge de React Native est 0.73.0. Si vous utilisez une version antérieure, mettez à jour React Native vers la version 0.73.0 ou ultérieure afin que votre expérience avec le SDK Adapty soit cohérente et fiable. ## Mettre à jour le style de présentation iOS pour les paywalls et onboardings modaux \{#update-ios-presentation-style-for-modal-paywalls-and-onboardings\} Dans le SDK Adapty 3.14.0, le style de présentation iOS par défaut pour les paywalls et les onboardings affichés avec la méthode `view.present()` est passé de page sheet à plein écran. Si vous souhaitez conserver l'ancien style de présentation en page sheet, passez le paramètre `iosPresentationStyle` à la méthode `present()` : ```typescript showLineNumbers title="React Native (TSX)" try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` --- # File: react-native-migration-guide-380 --- --- title: "Migrer le SDK Adapty React Native vers v3.8" description: "Migrez vers le SDK Adapty React Native v3.8 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.8.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part. ## Mettre à jour le type d'entrée pour obtenir les paramètres de placement \{#update-input-type-for-getting-placement-params\} `GetPaywallParamsInput` a été renommé en `GetPlacementParamsInput` : ```diff showLineNumbers - type GetPaywallParamsInput = { + type GetPlacementParamsInput = { placementId: string; locale?: string; fetchPolicy?: AdaptyPlacementFetchPolicy; loadTimeoutMs?: number; } ``` ## Mettre à jour la méthode de secours \{#update-fallback-method\} La méthode de définition des paywalls de secours a été mise à jour, et le type permettant de spécifier les emplacements de secours a été renommé : ```diff showLineNumbers - adapty.setFallbackPaywalls(paywallsLocation: Input.FallbackPaywallsLocation); + adapty.setFallback(fileLocation: Input.FileLocation); ``` ## Mettre à jour l'accès aux propriétés du paywall \{#update-paywall-property-access\} Les propriétés suivantes ont été déplacées de `AdaptyPaywall` vers `AdaptyPlacement` : ```diff showLineNumbers - paywall.abTestName - paywall.audienceName - paywall.revision - paywall.placementId + paywall.placement.abTestName + paywall.placement.audienceName + paywall.placement.revision + paywall.placement.id ``` --- # File: migration-to-react-native-sdk-34 --- --- title: "Migrer le SDK Adapty React Native vers la v3.4" description: "Migrez vers le SDK Adapty React Native v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté. ## Mettre à jour les fichiers de paywall de secours \{#update-fallback-paywall-files\} Mettez à jour vos fichiers de paywall de secours pour garantir la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](react-native-use-fallback-paywalls) par les nouveaux fichiers. ## Mettre à jour l'implémentation du mode Observateur \{#update-implementation-of-observer-mode\} Si vous utilisez le mode Observateur, assurez-vous de mettre à jour son implémentation. Auparavant, différentes méthodes étaient utilisées pour signaler les transactions à Adapty. Dans la nouvelle version, la méthode `reportTransaction` doit être utilisée de manière cohérente sur Android et iOS. Cette méthode signale explicitement chaque transaction à Adapty, garantissant qu'elle est bien reconnue. Si un paywall a été utilisé, passez l'ID de variation pour lier la transaction à celui-ci. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: ```diff showLineNumbers - if (Platform.OS === 'android') { - try { - await adapty.restorePurchases(); - } catch (error) { - // handle the error - } - } const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` --- # File: migration-to-react-native330 --- --- title: "Migrer le SDK Adapty React Native vers la v3.3" description: "Migrez vers le SDK Adapty React Native v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.3.1 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part. 1. Mettre à niveau vers le SDK Adapty v3.3.x. 2. Mettre à jour les modèles. 3. Supprimer la méthode `getProductsIntroductoryOfferEligibility`. 4. Mettre à jour la création d'achat. 5. Mettre à jour la présentation des paywalls du Paywall Builder. 6. Revoir l'implémentation des timers définis par le développeur. 7. Mettre à jour la gestion des événements d'achat du Paywall Builder. 8. Mettre à jour la gestion des événements d'action personnalisée du Paywall Builder. 9. Modifier le callback `onProductSelected`. 10. Supprimer les paramètres d'intégration tiers de la méthode `updateProfile`. 11. Mettre à jour les configurations d'intégration pour Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase et Google Analytics, Mixpanel, OneSignal et Pushwoosh. 12. Mettre à jour l'implémentation du mode Observer. ## Mettre à niveau le SDK Adapty React Native vers la 3.3.x \{#upgrade-adapty-react-native-sdk-to-33x\} Avant la version 3.3.1, le SDK `react-native-adapty` était le SDK principal et obligatoire pour qu'Adapty fonctionne correctement dans votre application. Le SDK `@adapty/react-native-ui` était optionnel et nécessaire uniquement si vous utilisiez le Paywall Builder d'Adapty. À partir de la version 3.3.1, le SDK `@adapty/react-native-ui` est déprécié et ses fonctionnalités ont été intégrées dans le SDK `react-native-adapty`. Pour mettre à niveau vers la version 3.3.1, suivez ces étapes : 1. Mettez à jour le package `react-native-adapty` vers la version 3.3.1. 2. Supprimez le package `@adapty/react-native-ui` des dépendances de votre projet. 3. Synchronisez les dépendances de votre projet pour appliquer les modifications. ## Modifications des modèles \{#changes-in-models\} ### Nouveaux modèles \{#new-models\} 1. [AdaptySubscriptionOffer](https://react-native.adapty.io/interfaces/adaptysubscriptionoffer) : ```typescript showLineNumbers export interface AdaptySubscriptionOffer { readonly identifier: AdaptySubscriptionOfferId; phases: AdaptyDiscountPhase[]; android?: { offerTags?: string[]; }; } ``` 2. [AdaptySubscriptionOfferId](https://react-native.adapty.io/types/adaptysubscriptionofferid) : ```typescript showLineNumbers export type AdaptySubscriptionOfferId = | { id?: string; type: 'introductory'; } | { id: string; type: 'promotional' | 'win_back'; }; ``` ### Modèles modifiés \{#changed-models\} 1. [AdaptyPaywallProduct](https://react-native.adapty.io/interfaces/adaptypaywallproduct) : - La propriété `subscriptionDetails` a été renommée en `subscription`. <p> </p> ```diff showLineNumbers - subscriptionDetails?: AdaptySubscriptionDetails; + subscription?: AdaptySubscriptionDetails; ``` 2. [AdaptySubscriptionDetails](https://react-native.adapty.io/interfaces/adaptysubscriptiondetails) : - `promotionalOffer` est supprimé. L'offre promotionnelle est désormais transmise via la propriété `offer` uniquement si elle est disponible. Dans ce cas, `offer?.identifier?.type` sera `'promotional'`. - `introductoryOfferEligibility` est supprimé (les offres ne sont retournées que si l'utilisateur est éligible). - `offerId` est supprimé. L'identifiant de l'offre est désormais stocké dans `AdaptySubscriptionOffer.identifier`. - `offerTags` est déplacé vers `AdaptySubscriptionOffer.android`. <p> </p> ```diff showLineNumbers - introductoryOffers?: AdaptyDiscountPhase[]; + offer?: AdaptySubscriptionOffer; ios?: { - promotionalOffer?: AdaptyDiscountPhase; subscriptionGroupIdentifier?: string; }; android?: { - offerId?: string; basePlanId: string; - introductoryOfferEligibility: OfferEligibility; - offerTags?: string[]; renewalType?: 'prepaid' | 'autorenewable'; }; } ``` 3. [AdaptyDiscountPhase](https://react-native.adapty.io/interfaces/adaptydiscountphase) : - Le champ `identifier` est supprimé du modèle `AdaptyDiscountPhase`. L'identifiant de l'offre est désormais stocké dans `AdaptySubscriptionOffer.identifier`. <p> </p> ```diff showLineNumbers - ios?: { - readonly identifier?: string; - }; ``` ### Modèles supprimés \{#remove-models\} 1. `AttributionSource` : - Une chaîne de caractères est désormais utilisée aux endroits où `AttributionSource` était précédemment utilisé. 2. `OfferEligibility` : - Ce modèle a été supprimé car il n'est plus nécessaire. Désormais, une offre n'est retournée que si l'utilisateur est éligible. ## Supprimer la méthode `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\} Avant le SDK Adapty 3.3.1, les objets produit incluaient toujours les offres, même si l'utilisateur n'était pas éligible. Vous deviez donc vérifier manuellement l'éligibilité avant d'utiliser l'offre. À partir de la version 3.3.1, l'objet produit n'inclut les offres que si l'utilisateur est éligible. Cela simplifie le processus, car vous pouvez supposer que l'utilisateur est éligible si une offre est présente. ## Mettre à jour la création d'achat \{#update-making-purchase\} Dans les versions précédentes, les achats annulés et en attente étaient traités comme des erreurs et retournaient les codes `2: 'paymentCancelled'` et `25: 'pendingPurchase'` respectivement. À partir de la version 3.3.1, les achats annulés et en attente sont désormais considérés comme des résultats réussis et doivent être gérés en conséquence : ```typescript showLineNumbers 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 } ``` ## Mettre à jour la présentation des paywalls du Paywall Builder \{#update-paywall-builder-paywall-presentation\} Pour des exemples mis à jour, consultez la documentation [Présenter les nouveaux paywalls du Paywall Builder dans React Native](react-native-present-paywalls). ```diff showLineNumbers - 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 } ``` ## Mettre à jour l'implémentation des timers définis par le développeur \{#update-developer-defined-timer-implementation\} Renommez le paramètre `timerInfo` en `customTimers` : ```diff showLineNumbers - 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 }) ``` ## Modifier les événements d'achat du Paywall Builder \{#modify-paywall-builder-purchase-events\} Précédemment : - Les achats annulés déclenchaient le callback `onPurchaseCancelled`. - Les achats en attente retournaient le code d'erreur `25: 'pendingPurchase'`. Maintenant : - Les deux sont gérés par le callback `onPurchaseCompleted`. #### Étapes de migration : \{#steps-to-migrate\} 1. Supprimez le callback `onPurchaseCancelled`. 2. Supprimez la gestion du code d'erreur `25: 'pendingPurchase'`. 3. Mettez à jour le callback `onPurchaseCompleted` : ```typescript showLineNumbers 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; // highlight-start 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; // highlight-end } // highlight-start return purchaseResult.type !== 'user_cancelled'; // highlight-end }, }); ``` ## Modifier les événements d'action personnalisée du Paywall Builder \{#modify-paywall-builder-custom-action-events\} Callbacks supprimés : - `onAction` - `onCustomEvent` Callback ajouté : - Nouveau callback `onCustomAction(actionId)`. Utilisez-le pour les actions personnalisées. ## Modifier le callback `onProductSelected` \{#modify-onproductselected-callback\} Précédemment, `onProductSelected` nécessitait l'objet `product`. Il requiert maintenant `productId` sous forme de chaîne de caractères. ## Supprimer les paramètres d'intégration tiers de la méthode `updateProfile` \{#remove-third-party-integration-parameters-from-updateprofile-method\} Les identifiants d'intégration tiers sont désormais définis via la méthode `setIntegrationIdentifier`. La méthode `updateProfile` ne les accepte plus. ## Mettre à jour la configuration des SDK d'intégration tiers \{#update-third-party-integration-sdk-configuration\} Pour garantir le bon fonctionnement des intégrations avec le SDK Adapty React Native 3.3.1 et versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes comme décrit dans les sections ci-dessous. De plus, si vous utilisiez `AttributionSource` pour obtenir l'identifiant d'attribution, modifiez votre code pour fournir l'identifiant requis sous forme de chaîne de caractères. ### Adjust \{#adjust\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers 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 \{#airbridge\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers 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 \{#amplitude\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers 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 \{#appmetrica\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers 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 \{#appsflyer\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers 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 \{#branch\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers 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 \{#facebook-ads\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads). ```diff showLineNumbers 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 et Google Analytics \{#firebase-and-google-analytics\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Firebase et Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers 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 \{#mixpanel\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers 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 \{#onesignal\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration OneSignal](onesignal#sdk-configuration). <Tabs groupId="current-os" queryString> <TabItem value="v5+" label="OneSignal SDK v5+ (current)" default> ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import OneSignal from 'react-native-onesignal'; OneSignal.User.pushSubscription.addEventListener('change', (subscription) => { const subscriptionId = subscription.current.id; if (subscriptionId) { - adapty.updateProfile({ - oneSignalSubscriptionId: subscriptionId, - }); + adapty.setIntegrationIdentifier("one_signal_subscription_id", subscriptionId); } }); ``` </TabItem> <TabItem value="pre-v5" label="OneSignal SDK v. up to 4.x (legacy)" default> ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import OneSignal from 'react-native-onesignal'; OneSignal.addSubscriptionObserver(event => { const playerId = event.to.userId; - adapty.updateProfile({ - oneSignalPlayerId: playerId, - }); + adapty.setIntegrationIdentifier("one_signal_player_id", playerId); }); ``` </TabItem> </Tabs> ### Pushwoosh \{#pushwoosh\} Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour l'exemple de code complet, consultez la [configuration SDK pour l'intégration Pushwoosh](pushwoosh#sdk-configuration). ```diff showLineNumbers 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` } ``` ## Mettre à jour l'implémentation du mode Observer \{#update-observer-mode-implementation\} Mettez à jour la façon dont vous associez les paywalls aux transactions. Précédemment, vous utilisiez la méthode `setVariationId` pour assigner le `variationId`. Désormais, vous pouvez inclure le `variationId` directement lors de l'enregistrement de la transaction en utilisant la nouvelle méthode `reportTransaction`. Consultez l'exemple de code final dans [Associer les paywalls aux transactions d'achat en mode Observer](report-transactions-observer-mode-react-native). :::warning N'oubliez pas d'enregistrer la transaction avec la méthode `reportTransaction`. Si vous omettez cette étape, Adapty ne reconnaîtra pas la transaction, n'accordera pas les niveaux d'accès, ne l'inclura pas dans les analyses et ne l'enverra pas aux intégrations. Cette étape est indispensable ! ::: :::note Veuillez noter que l'ordre des paramètres de la méthode `reportTransaction` diffère de celui de la méthode `setVariationId`. ::: ```diff showLineNumbers const variationId = paywall.variationId; try { - await adapty.setVariationId(variationId, transactionId); + await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` --- # File: migration-to-react-native-sdk-v3 --- --- title: "Migrer le SDK Adapty React Native vers la v3.0" description: "Migrez vers le SDK Adapty React Native v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Paywall Builder Adapty](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et à ses riches capacités de design, vos paywalls deviendront plus efficaces et rentables. ## Passer à la version 3.0.1 \{#upgrade-to-version-301\} 1. Passez à la version 3.0.1 normalement. 2. Remplacez les fichiers de paywall de secours : 1. [Téléchargez la dernière version](fallback-paywalls) depuis l'Adapty Dashboard. 2. Stockez-les sur l'appareil de l'utilisateur et transmettez-les à la méthode `.setFallbackPaywalls` comme décrit [ici](react-native-use-fallback-paywalls). --- # End of Documentation _Generated on: 2026-08-04T15:08:26.119Z_ _Successfully processed: 57/57 files_ # TUTORIAL - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:26.121Z Total files: 319 --- # File: what-is-adapty --- --- title: "Bienvenue sur Adapty" description: "Découvrez ce qu'est Adapty et comment il vous aide à gérer vos abonnements." --- <Homepage /> For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. #### Adapty s'adresse aux développeurs, aux marketeurs et aux dirigeants \{#adapty-works-for-developers-marketers-and-executives\} Les marketeurs peuvent engager directement les utilisateurs avec des offres promotionnelles pour les faire revenir sur le service ou leur proposer de nouveaux produits. Avec Adapty, plus besoin que les développeurs et les analystes extraient manuellement des segments. Pour les chefs de produit et les dirigeants, Adapty propose un tableau de bord avec des métriques d'abonnement pertinentes, accompagnées de rapports quotidiens, hebdomadaires et mensuels envoyés sur Slack et par e-mail. --- # File: is-adapty-right-for-me --- --- title: "Adapty est-il fait pour moi ?" description: "Découvrez comment Adapty correspond à votre cas d'usage. Que vous lanciez une nouvelle application, optimisiez vos revenus ou migriez depuis un autre outil — voici par où commencer." --- Adapty est une plateforme d'achats intégrés pour les applications mobiles. Elle gère les abonnements, les achats uniques et les consommables — du traitement des achats et de la validation des reçus à l'analyse, aux tests A/B et aux intégrations. Voici comment Adapty fonctionne selon les différents scénarios. ## Je lance une nouvelle application avec des achats intégrés \{#im-launching-a-new-app-with-in-app-purchases\} Que vous vendiez des abonnements, des achats uniques ou des consommables, Adapty couvre l'ensemble du stack : - **SDK pour 7 plateformes** : iOS, Android, React Native, Flutter, Unity, Kotlin Multiplatform et Capacitor. - **Gestion des achats** : abonnements avec renouvellements et logique de relance, achats uniques, consommables et validation des reçus — tout est géré pour vous. - **Éditeur de paywall sans code** : concevez et publiez des paywalls sans écrire de code UI. - **Analytics dès le premier jour** : suivez les revenus, les essais, les conversions et bien plus dès l'arrivée de vos premiers utilisateurs. Prêt à démarrer ? Suivez le [guide de démarrage rapide](quickstart). ## Je veux des tests A/B, de l'analytics et des intégrations \{#i-want-ab-tests-analytics-and-integrations\} Adapty vous aide à optimiser ce qui fonctionne déjà : - **Tests A/B** : testez différents prix, designs de paywall, durées d'essai et offres promotionnelles pour trouver ce qui convertit le mieux. Utilisez [AI Growth Advisor](autopilot) pour obtenir des recommandations de tests A/B adaptées à votre application, basées sur les données de 20 000 applications par abonnement. - **Graphiques analytics** : suivez le MRR, le LTV, le churn, la rétention et des dizaines d'autres métriques. - **Segmentation d'audience** : ciblez des groupes d'utilisateurs spécifiques avec des paywalls et des offres personnalisées. - **Configuration de paywall à distance** : itérez sur vos paywalls sans publier de nouvelle version de l'application. - **Intégrations tierces** : envoyez les événements d'achat vers Amplitude, AppsFlyer, Adjust, Mixpanel et les autres outils déjà utilisés par votre équipe. Explorez les [tests A/B](ab-tests), l'[Analytics](analytics), les [intégrations de services analytics](analytics-integration) ou les [intégrations de services d'attribution](attribution-integration). ## Je veux implémenter des achats intégrés avec un LLM \{#i-want-to-implement-in-app-purchases-with-an-llm\} La documentation d'Adapty est optimisée pour être utilisée avec des assistants de code IA comme Cursor, Claude, ChatGPT et d'autres. Chaque page est disponible en Markdown brut, et nous fournissons des guides d'implémentation assistés par LLM, étape par étape, pour chaque plateforme : - **Guides prêts à copier-coller** : envoyez le guide à votre LLM et laissez-le vous accompagner à travers chaque étape d'implémentation. - **Accès Markdown** : ajoutez `.md` à l'URL de n'importe quelle page de documentation ou cliquez sur **Copy for LLM** pour obtenir une version texte propre. - **Support MCP Context7** : connectez la documentation Adapty directement à votre IDE propulsé par LLM. Choisissez votre plateforme et démarrez : [Intégrer Adapty avec l'aide de l'IA](adapty-cursor). ## Je veux gérer et optimiser mes campagnes Apple Ads \{#i-want-to-run-and-optimize-apple-ads-campaigns\} Si vous diffusez des Apple Search Ads, Adapty Ads Manager connecte directement les performances de vos campagnes aux métriques de revenus — sans MMP requis : - **Données de performance en temps réel** : suivez les campagnes, groupes d'annonces et mots-clés. - **Suivi des revenus de bout en bout** : suivez la chaîne de la recherche à l'installation, de l'essai à l'abonnement jusqu'au LTV. - **Prédictions et recommandations IA** : anticipez les retours et obtenez des suggestions de mise à l'échelle. - **Agent IA** : posez des questions en langage naturel sur votre compte et obtenez des réponses et recommandations sur l'ensemble du funnel. - **Automatisations basées sur des règles** : maintenez vos objectifs de CPA et de ROAS stables. Démarrez avec [Adapty Ads Manager](adapty-ads-manager). ## Je veux savoir d'où viennent mes utilisateurs \{#i-want-to-track-where-my-users-come-from\} Adapty Attribution est une solution d'attribution intégrée qui relie les dépenses publicitaires aux installations d'applications et aux revenus des abonnements : - **Tableau de bord marketing unifié** : consultez le ROAS, les installations et les revenus sur tous vos canaux en un seul endroit. - **Attribution intégrée** : connectez les campagnes publicitaires aux installations et aux revenus sans dépendre d'MMPs externes. - **Liens de suivi** : générez des liens dans Adapty et ajoutez-les à vos campagnes pour une attribution précise. - **Deeplinks différés** : redirigez les utilisateurs vers le bon contenu après l'installation, même s'ils n'avaient pas l'application au moment du clic. - **Analyse de cohorte** : analysez les performances d'acquisition et le comportement des utilisateurs dans le temps. En savoir plus sur [Adapty Attribution](adapty-user-acquisition). ## Je veux convertir les utilisateurs en essai et récupérer les abonnés perdus par e-mail \{#i-want-to-convert-trial-users-and-recover-churned-subscribers-via-email\} Adapty Mail transforme les données utilisateurs d'Adapty en campagnes e-mail générées par IA qui ciblent les utilisateurs en essai, les abonnés perdus et d'autres événements du cycle de vie : - **Campagnes générées par IA** : Adapty génère le texte et le design de chaque campagne à partir de votre profil de marque. - **Déclencheurs de cycle de vie** : envoyez des campagnes automatiquement en fonction d'événements clés du cycle de vie. - **Paiement sur paywall web** : liens de paiement personnalisés adaptés à chaque destinataire — achats attribués à l'e-mail qui les a générés. - **Envoi depuis votre propre domaine** : tous les e-mails sont envoyés depuis votre domaine vérifié — aucune plateforme e-mail distincte requise. En savoir plus sur [Adapty Mail](adapty-mail). ## Je veux itérer rapidement sans publier de nouvelles versions \{#i-want-to-iterate-fast-without-app-releases\} Une fois Adapty intégré, la majeure partie du travail quotidien se fait dans le tableau de bord — sans nouvelles versions d'application requises : - **Flows** : concevez des paywalls et des onboardings dans un éditeur visuel et publiez les modifications instantanément. - **Tests A/B depuis le tableau de bord** : lancez des expériences, ajustez les prix et changez les offres sans toucher au code. - **Analytics dans le tableau de bord** : surveillez les revenus, le churn, les essais et les conversions en temps réel. - **Rapports Slack et e-mail** : recevez des mises à jour automatisées sur les métriques importantes pour votre équipe. Explorez les [Flows](adapty-flow-builder) ou consultez l'[Analytics](charts). ## Je vends sur le web et j'ai besoin d'une application mobile \{#i-sell-on-the-web-and-need-a-mobile-app\} Si vos utilisateurs paient déjà via un site web et que vous ajoutez une application mobile, Adapty synchronise les achats entre les plateformes : - **Intégration Stripe et Paddle** : synchronisez automatiquement les achats web dans Adapty. - **Synchronisation web vers mobile** : les utilisateurs qui ont payé sur le web obtiennent l'accès dans votre application, et vice versa. - **Analytics cross-plateformes unifiées** : consultez les revenus web et mobile dans un seul tableau de bord. Configurez l'[intégration Stripe](stripe), l'[intégration Paddle](paddle), ou apprenez à [synchroniser les abonnés web et mobile](sync-subscribers-from-web). ## Je migre depuis un autre outil \{#im-migrating-from-another-tool\} Adapty simplifie la migration depuis d'autres plateformes d'abonnement : - **Guides de migration** : instructions étape par étape pour migrer depuis d'autres plateformes d'abonnement. - **Mode Observateur** : conservez votre code de facturation existant et adoptez Adapty progressivement avec le [mode Observateur](observer-vs-full-mode) — commencez par l'analytics et les tests A/B, puis étendez quand vous êtes prêt. - **Import de données historiques** : importez votre historique de transactions existant dans Adapty pour que vos analytics restent complets. Renseignez-vous sur la [migration vers Adapty](migrate-to-adapty-from-another-solutions) et l'[import de données historiques](importing-historical-data-to-adapty). --- Vous explorez encore ? Le [guide de démarrage rapide](quickstart) est toujours un bon point de départ. --- # File: quickstart --- --- title: "Guide de démarrage rapide" description: "Intégrez Adapty avec l'App Store, Google Play, des stores personnalisés, Stripe et Paddle." --- Bienvenue sur Adapty ! Vous êtes sur le point de franchir la première étape vers la croissance de vos achats intégrés avec la meilleure solution pour booster les revenus de votre application. L'intégration est simple, et ce guide de démarrage rapide vous accompagnera tout au long du processus. Une fois ce guide terminé : - Adapty gérera les achats intégrés avec toute la logique associée. - Vous aurez la flexibilité d'afficher le bon paywall au bon moment pour des utilisateurs spécifiques. - Vous accéderez à des analyses détaillées des achats intégrés. - Vous pourrez lancer des tests A/B et envoyer des événements d'abonnement à des outils d'analyse tiers. Démarrez avec Adapty en cinq étapes simples : 1. [**Intégrer avec les stores ou les plateformes de paiement**](integrate-payments) : Connectez Adapty à l'App Store, Google Play, Stripe, Paddle ou d'autres stores où vous vendez vos produits. 2. [**Ajouter des produits**](quickstart-products) : Ajoutez vos produits ou abonnements intégrés à Adapty et liez-les aux stores ou plateformes de paiement. 3. [**Ajouter un paywall pour activer les achats**](quickstart-paywalls) : Ajoutez un paywall pour activer les achats intégrés avec Adapty. Nous vous montrerons la façon la plus simple de le faire. 4. [**Intégrer le SDK Adapty dans le code de votre application**](quickstart-sdk) : Le SDK Adapty gère les achats, la gestion des abonnements et l'identification des utilisateurs. 5. [**Tester votre intégration avec Adapty**](quickstart-test) : Assurez-vous que votre intégration fonctionne comme prévu et que vous pouvez voir vos achats dans l'Adapty Dashboard. --- # File: integrate-payments --- --- title: "Intégration avec les stores ou les plateformes de paiement" description: "Intégrez Adapty avec l'App Store, Google Play, des stores personnalisés, Stripe et Paddle." --- Pour démarrer avec Adapty, commencez par intégrer les stores où vos utilisateurs achètent des produits. Adapty se connecte à divers app stores et plateformes de paiement web, centralisant tous vos achats intégrés et vos analyses en un seul endroit. ## Intégration avec les stores et les paiements web \{#integrate-with-stores-and-web-payments\} Choisissez votre store ci-dessous pour accéder aux étapes d'intégration détaillées : - [App Store](initial_ios) - [Google Play](initial-android) - Paiements web : - [Stripe](stripe) - [Paddle](paddle) - [Autres stores](custom-store) ## Étapes suivantes \{#next-steps\} Une fois votre store ou votre plateforme de paiement connecté, vous pouvez passer à l'[ajout de produits](quickstart-products). --- # File: quickstart-products --- --- title: "Ajouter des produits" description: "Ajoutez des achats intégrés ou des abonnements à Adapty et reliez-les à vos fiches App Store, Google Play, Stripe, Paddle ou store personnalisé." --- :::tip Vous configurez Adapty par programmation ? Vous pouvez effectuer cette étape via le [Developer CLI](developer-cli-quickstart). ::: Avant de pouvoir utiliser les fonctionnalités principales d'Adapty, vous devez ajouter chaque produit que vous vendez et le relier à chaque store ou plateforme de paiement que vous prenez en charge. Cette configuration vous permet de proposer des produits aux appareils des utilisateurs et de les suivre dans les analytics par la suite. Dans Adapty, tout ce que votre application vend est un **produit**. Si un même article existe sur l'App Store, Google Play ou Stripe, vous pouvez les regrouper en un seul produit dans Adapty. Configurez-le une fois et gérez-le sur toutes les plateformes depuis un seul endroit. Ajoutons votre premier produit. <Tabs groupId="products" queryString> <TabItem value="no-products" label="Pas encore de produits dans les stores" default> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/qUpC2XG-r5E?si=7Komyv4_PUQ4FaEH" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> <TabItem value="products-in-stores" label="Produits déjà présents dans les stores"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/nlkdKCF0SwY?si=VVigzHcpv3waKJmI" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> </Tabs> ## Ajouter votre premier produit \{#add-your-first-product\} :::tip Ce guide de démarrage rapide couvre les bases pour créer un produit. Pour plus de détails, consultez le guide sur la [création de produits](create-product). ::: Imaginons que vous souhaitez ajouter un abonnement mensuel comme produit. 1. Accédez à [Products](https://app.adapty.io/products) depuis le menu principal d'Adapty. 2. Cliquez sur **Create product** en haut à droite. <img src={require('./img/products-tab.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important **Les étapes suivantes dépendent de si vous avez déjà des produits sur l'App Store et/ou Google Play :** ::: <Tabs groupId="products" queryString> <TabItem value="no-products" label="Pas encore de produits dans les stores" default> :::important Avant de commencer, assurez-vous d'avoir configuré l'intégration avec [App Store](initial_ios) et/ou [Google Play](initial-android). Pour l'App Store, vérifiez que vous avez [ajouté la clé API App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key), afin qu'Adapty puisse envoyer les produits. ::: 3. Sélectionnez **Create a new product and push to stores**. 4. Renseignez les détails du produit : - **Product name** : Le nom visible uniquement par vous dans le tableau de bord Adapty. - **Access Level** : L'identifiant unique qui détermine quelles fonctionnalités sont débloquées après l'achat. Si tous les utilisateurs payants de votre application ont accès aux mêmes fonctionnalités, vous pouvez utiliser le niveau d'accès par défaut : `premium`. Pour des configurations plus complexes, créez des [niveaux d'accès](access-level) supplémentaires. - **Subscription duration** : Sélectionnez la durée de l'abonnement dans la liste. - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual** : La durée de l'abonnement. - **Lifetime** : Utilisez une période à vie pour les produits qui débloquent définitivement les fonctionnalités premium de l'application. - **Non-Subscriptions** : Pour les produits qui ne sont pas des abonnements et n'ont donc pas de durée, utilisez les non-abonnements. Ils peuvent servir à débloquer des fonctionnalités supplémentaires, des produits consommables, etc. - **Consumables** : Les articles consommables peuvent être achetés plusieurs fois. Ils peuvent être utilisés au cours de la vie de l'application. Les exemples incluent la monnaie du jeu et les extras. Notez que les produits consommables n'affectent pas les niveaux d'accès. - **Price (USD)** : Le prix du produit en USD. Ce prix sera utilisé comme base pour calculer et définir automatiquement les prix dans tous les pays. Vous pourrez [personnaliser le prix pour différents pays et régions](edit-product#set-country-specific-prices) ultérieurement. <img src={require('./img/create-product-push.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Save & Continue** et passez à l'onglet **App Store** ou **Google Play** pour renseigner les détails du produit pour le store. <Tabs> <TabItem value="App Store" label="App Store" default> - **Product ID** : Créez un identifiant unique permanent pour le produit. - **Product group** : Sélectionnez un groupe de produits existant que vous avez créé dans App Store Connect, ou cliquez sur **Create new Product Group** et définissez son nom et son identifiant. Une fois qu'Adapty l'a créé, vous pouvez le sélectionner dans le menu déroulant. - **Screenshot** : Téléchargez une capture d'écran de l'achat intégré montrant clairement l'article ou le service proposé. Cette capture d'écran est utilisée uniquement pour la révision App Store et n'est pas affichée sur l'App Store. Consultez les exigences de taille et de format des captures d'écran [ici](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/). :::warning S'il s'agit de votre premier produit pour cette application, vous devez le soumettre manuellement pour révision dans App Store Connect. Cela ne sera plus nécessaire par la suite. Une fois la révision terminée, le statut du produit dans Adapty se mettra à jour automatiquement. ::: </TabItem> <TabItem value="Google Play" label="Google Play" default> - **Base Product ID** : Créez un identifiant unique permanent pour le produit. - **Subscription** : Sélectionnez un groupe d'abonnements existant que vous avez créé dans Google Play Console, ou cliquez sur **Create new Product Group** et définissez son nom et son identifiant. Une fois qu'Adapty l'a créé, vous pouvez le sélectionner dans le menu déroulant. </TabItem> </Tabs> 6. Pour iOS, configurez l'offre de lancement — essai gratuit — en sélectionnant sa **Free duration** dans le menu déroulant. Pour cette configuration initiale, vous pouvez ajouter un essai gratuit de lancement. Une fois le produit principal approuvé par les stores, vous pourrez [ajouter d'autres offres](offers) (par exemple, promotionnelles, de reconquête) en reliant leurs identifiants existants depuis votre console de store. :::important Les offres de lancement ne se synchronisent pas automatiquement avec Google Play. Contrairement à l'App Store, Google Play ne propose pas de type « offre de lancement » distinct — les essais gratuits et les offres à prix réduit sont tous configurés comme des **offres** sur un plan de base. [Créez l'offre dans Google Play Console et reliez-la à votre produit Adapty](google-play-offers). ::: </TabItem> <TabItem value="products-in-stores" label="Produits déjà présents dans les stores"> 3. Sélectionnez **Connect an existing store product**. 4. Renseignez les détails du produit : - **Product name** : Le nom visible uniquement par vous dans le tableau de bord Adapty. - **Access level ID** : L'identifiant unique qui détermine quelles fonctionnalités sont débloquées après l'achat. Si tous les utilisateurs payants de votre application ont accès aux mêmes fonctionnalités, vous pouvez utiliser le niveau d'accès par défaut : `premium`. Pour des configurations plus complexes, créez des [niveaux d'accès](access-level) supplémentaires. - **Subscription duration** : Sélectionnez la durée de l'abonnement dans la liste. - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual** : La durée de l'abonnement. - **Lifetime** : Utilisez une période à vie pour les produits qui débloquent définitivement les fonctionnalités premium de l'application. - **Non-Subscriptions** : Pour les produits qui ne sont pas des abonnements et n'ont donc pas de durée, utilisez les non-abonnements. Ils peuvent servir à débloquer des fonctionnalités supplémentaires, des produits consommables, etc. - **Consumables** : Les articles consommables peuvent être achetés plusieurs fois. Ils peuvent être utilisés au cours de la vie de l'application. Les exemples incluent la monnaie du jeu et les extras. Notez que les produits consommables n'affectent pas les niveaux d'accès. - **Price (USD)** : Le prix du produit en USD. Si votre produit est déjà dans le store, cette valeur n'affectera pas son prix réel dans le store ; vous pouvez sélectionner n'importe quelle valeur dans la liste. Vous pourrez ensuite [personnaliser les prix pour différentes régions](edit-product#set-country-specific-prices) directement dans le tableau de bord Adapty. <img src={require('./img/product-info.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <br /> 5. Ajoutez les détails du store. Choisissez votre store : <Tabs> <TabItem value="App Store" label="App Store" default> - **App Store Product ID** : L'identifiant unique utilisé pour accéder à votre produit sur les appareils. Si vous ne le trouvez pas, vérifiez que l'identifiant est correct et appartient à la bonne application. </TabItem> <TabItem value="Google Play" label="Google Play" default> - **Google Play Product ID** : L'identifiant du produit sur le Play Store. Sélectionnez-le dans la liste des identifiants de produits existants. Si vous ne le trouvez pas, vérifiez que l'identifiant est correct et appartient à la bonne application. - **Base plan ID** : L'identifiant qui définit le plan de base du produit dans le Play Store. - **Legacy fallback product** : Un produit de secours utilisé exclusivement pour les applications utilisant des versions plus anciennes du SDK Adapty (versions 2.5 et inférieures). Indiquez la valeur au format suivant : `<subscription_id>:<base_plan_id>`. :::important Les offres de lancement ne se synchronisent pas automatiquement avec Google Play. Contrairement à l'App Store, Google Play ne propose pas de type « offre de lancement » distinct — les essais gratuits et les offres à prix réduit sont tous configurés comme des **offres** sur un plan de base. [Créez l'offre dans Google Play Console et reliez-la à votre produit Adapty](google-play-offers). ::: <details> <summary>Cliquez ici pour savoir où trouver les identifiants de produit et de plan de base Google Play.</summary> 1. Accédez à **Monetize with Play > Products > Subscriptions** dans votre compte [Google Play Console](https://play.google.com/console/developers/android/app). 2. Ouvrez l'**abonnement** correspondant à l'achat. 3. Vous verrez l'identifiant du produit dans la section **Subscription details** et l'identifiant du plan de base dans la colonne **ID and duration** de la section **Base plans and offers**. <img src={require('./img/play-store-id.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Stripe" label="Stripe" default> - **Stripe Product ID** : L'identifiant unique du produit dans Stripe. - **Stripe Price ID** : L'identifiant unique dans Stripe pour le prix associé au produit. <details> <summary>Cliquez ici pour savoir où trouver les identifiants de produit et de prix Stripe.</summary> 1. Accédez à votre [catalogue de produits](https://dashboard.stripe.com/products?active=true) dans Stripe. 2. Ouvrez le produit souhaité. 3. Vous verrez : - L'identifiant du produit Stripe (de la forme `prod_...`) dans le coin supérieur droit. - L'identifiant du prix Stripe (de la forme `price_...`) dans la colonne **API ID** de la section **Pricing**. <img src={require('./img/product-stripe.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Paddle" label="Paddle" default> - **Paddle Product ID** : L'identifiant unique du produit dans Paddle. - **Paddle Price ID** : L'identifiant unique dans Paddle pour le prix associé au produit. <details> <summary>Cliquez ici pour savoir où trouver les identifiants de produit et de prix Paddle.</summary> 1. Accédez à votre [catalogue de produits](https://vendors.paddle.com/products-v2) dans Paddle. 2. Ouvrez le produit souhaité. 3. Vous verrez : - L'identifiant du produit Paddle (de la forme `pro_...`) dans la section **Additional details**. - L'identifiant du prix Paddle (de la forme `pri_...`) dans la colonne **ID** de la section **Prices**. <img src={require('./img/paddle-product-price.webp').default} style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Custom" label="Store personnalisé" default> Vous pouvez sélectionner un store personnalisé existant ou en ajouter un nouveau et y associer un produit. Gardez à l'esprit qu'Adapty ne suit que les transactions provenant de l'App Store, Google Play et Stripe. Pour les stores personnalisés, vous devrez soumettre les transactions via l'API server-side d'Adapty avec la méthode [Set transaction](api-adapty/operations/setTransaction). </TabItem> </Tabs> 6. Vous pouvez [créer des offres](create-offer) pour le produit si nécessaire. Pour ajouter des offres, cliquez sur **Yes, add offers**. Sinon, cliquez sur **No, thanks**. Votre produit apparaîtra dans la liste des produits. <img src={require('./img/created-product.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </TabItem> </Tabs> ## Étapes suivantes \{#next-steps\} Une fois vos produits ajoutés à Adapty, vous pouvez passer à la [configuration des paywalls](quickstart-paywalls), car c'est le seul moyen de commencer à les vendre. --- # File: quickstart-paywalls --- --- title: "Activer les achats" description: "Ajoutez un flow ou un paywall dans Adapty pour présenter vos produits, puis attachez-le à un placement." --- :::info Pour suivre ce guide, assurez-vous d'avoir terminé l'[intégration au store](integrate-payments) et créé au moins un produit comme décrit dans le [guide précédent sur l'ajout de produits](quickstart-products). ::: Maintenant que vous avez des produits, vous devez trouver un moyen de les présenter aux utilisateurs. Adapty vous propose trois options : - **Flow Builder (recommandé)** : éditeur visuel no-code pour tout le parcours d'achat. Le SDK Adapty affiche le résultat nativement, sans code UI à écrire. - **Paywall manuel** : vous créez un paywall, y attachez des produits et affichez l'interface vous-même dans le code de votre app. - **Adapty Paywall Builder (Legacy)** : éditeur de paywall no-code. Les deux options aboutissent au même résultat : vous attachez ce que vous avez créé à un [placement](placements). C'est le placement que votre app appelle au runtime pour récupérer le bon contenu pour le bon utilisateur. <Tabs groupId="purchase-setup" queryString> <TabItem value="flow-builder" label="Use the Flow Builder" default> :::important Le Flow Builder prend actuellement en charge iOS, Android, React Native, Flutter et Capacitor SDK v4 et versions ultérieures. La prise en charge d'autres plateformes est à venir. ::: Un flow est un ou plusieurs écrans avec des produits intégrés directement. Vous le concevez dans le [Flow Builder](adapty-flow-builder) — aucun code requis. Le SDK Adapty affiche les flows nativement sur chaque plateforme. Votre app appelle `getFlow`, et le SDK présente les écrans, gère les achats et remonte les événements. Pas de code UI séparé, pas de paywall à maintenir en parallèle. ## 1. Créer le flow \{#1-build-the-flow\} 1. Rendez-vous dans [**Flows**](https://app.adapty.io/flows) dans le menu principal d'Adapty. 2. Cliquez sur **Create flow** et concevez votre flow. En savoir plus sur le [Adapty Flow Builder](adapty-flow-builder). Les guides de modèles ci-dessous décrivent étape par étape les schémas les plus courants : <CustomDocCardList ids={['basic-paywall-screen', 'show-plans-bottom-sheet', 'paywall-with-tabs', 'paywall-features-per-product', 'onboarding-flow-tutorial']} /> Une fois votre flow sauvegardé et publié, passez à son intégration dans un placement. :::warning N'oubliez pas de publier le flow ! Si vous ne le publiez pas, vous ne pourrez pas l'ajouter à un placement. ::: ### 2. Ajouter le flow à un placement \{#2-add-the-flow-to-a-placement\} Créez un <InlineTooltip tooltip="placement">Un placement est un point précis de votre app où vous affichez un flow, un paywall, un onboarding ou un test A/B. Les placements vous permettent de cibler des [audiences](audience) spécifiques avec votre contenu. En savoir plus sur les [placements](placements).</InlineTooltip> pour que votre app puisse demander le flow au runtime. Commençons par le plus essentiel — le placement d'onboarding. Vous pourrez ensuite ajouter d'autres [placements pertinents](choose-meaningful-placements) tout au long du parcours utilisateur. 1. Rendez-vous dans [**Placements**](https://app.adapty.io/placements) dans le menu principal d'Adapty et passez à l'onglet **Flows**. 2. Cliquez sur **Create placement**. 3. Saisissez un **Placement name** (ex. : `main` ou `onboarding`). Il s'agit d'un identifiant interne dans l'Adapty Dashboard. 4. Saisissez un **Placement ID**. Vous utiliserez cet ID dans le SDK Adapty pour charger le flow du placement. 5. Cliquez sur **Run flow** et choisissez le flow que vous venez de créer. 6. Cliquez sur **Save & publish**. Dans le code de votre app, vous n'écrivez en dur que les IDs de placement. Tout le reste — quel flow s'exécute, quels produits il vend, comment il se présente — est configuré dans l'Adapty Dashboard et peut être modifié à tout moment sans mise à jour de l'app. :::tip Adapty vous permet d'afficher différents flows à différents groupes d'utilisateurs et d'analyser les performances. En savoir plus sur les [audiences](audience) et les [tests A/B](ab-tests). ::: </TabItem> <TabItem value="manual-paywall" label="Implement paywall manually"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/e4o7Z2tUGL8?si=ipwbW3VVN0fIg0R0" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Un paywall est un conteneur configuré à distance pour un ou plusieurs produits. Adapty fournit la liste des produits et un payload JSON de [Remote Config](customize-paywall-with-remote-config) optionnel — votre code d'app les lit et affiche l'interface. :::tip Vous configurez Adapty de manière programmatique ? Vous pouvez effectuer cette étape via la [CLI développeur](developer-cli-quickstart). ::: ### 1. Créer un paywall \{#1-create-a-paywall\} 1. Rendez-vous dans [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. 2. Cliquez sur **Create paywall**. 3. Saisissez un **Paywall name**. Il s'agit d'un identifiant interne dans l'Adapty Dashboard. 4. Cliquez sur **Add product** et choisissez les produits à afficher sur le paywall. 5. (Optionnel) Ouvrez l'onglet **Remote config** et ajoutez le payload JSON dont votre app a besoin (titres, textes, feature flags). Voir [Personnaliser le paywall avec le Remote Config](customize-paywall-with-remote-config) pour plus de détails. 6. Cliquez sur **Create as a draft**, puis publiez quand vous êtes prêt. <img src="/assets/shared/img/quickstart-paywall.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous afficherez ce paywall dans le code de votre app. <InlineTooltip tooltip="implémenter les paywalls manuellement">Suivez le guide pour votre plateforme : [iOS](ios-implement-paywalls-manually), [Android](android-implement-paywalls-manually), [React Native](react-native-implement-paywalls-manually), [Flutter](flutter-implement-paywalls-manually), [Unity](unity-implement-paywalls-manually).</InlineTooltip> ### 2. Ajouter le paywall à un placement \{#2-add-the-paywall-to-a-placement\} Créez un <InlineTooltip tooltip="placement">Un placement est un point précis de votre app où vous affichez un flow, un paywall, un onboarding ou un test A/B. Les placements vous permettent de cibler des [audiences](audience) spécifiques avec votre contenu. En savoir plus sur les [placements](placements).</InlineTooltip> pour que votre app puisse demander le paywall au runtime. Commençons par le plus essentiel — le placement d'onboarding. Vous pourrez ensuite ajouter d'autres [placements pertinents](choose-meaningful-placements) tout au long du parcours utilisateur. 1. Rendez-vous dans [**Placements**](https://app.adapty.io/placements) dans le menu principal d'Adapty et passez à l'onglet **Paywalls**. 2. Cliquez sur **Create placement**. 3. Saisissez un **Placement name** (ex. : `main` ou `onboarding`). Il s'agit d'un identifiant interne dans l'Adapty Dashboard. 4. Saisissez un **Placement ID**. Vous utiliserez cet ID dans le SDK Adapty pour charger le paywall du placement. 5. Cliquez sur **Run paywall** et choisissez le paywall que vous venez de créer. 6. Cliquez sur **Save & publish**. <img src="/assets/shared/img/add-placement.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans le code de votre app, vous n'écrivez en dur que les IDs de placement. Tout le reste — quel paywall s'exécute, quels produits il vend, le Remote Config — est configuré dans l'Adapty Dashboard et peut être modifié à tout moment sans mise à jour de l'app. :::tip Adapty vous permet d'afficher différents paywalls à différents groupes d'utilisateurs et d'analyser les performances. En savoir plus sur les [audiences](audience) et les [tests A/B](ab-tests). ::: </TabItem> <TabItem value="paywall-builder" label="Adapty Paywall Builder (Legacy)"> Un paywall créé dans le [Paywall Builder](adapty-paywall-builder) est un écran no-code avec des produits intégrés directement. Le SDK Adapty l'affiche nativement, sans code UI à écrire. :::warning Le Paywall Builder est entièrement fonctionnel, mais Adapty n'y ajoute plus de fonctionnalités ni de mises à jour. Pour les nouveaux projets, utilisez plutôt le [Flow Builder](adapty-flow-builder). ::: ### 1. Créer le paywall \{#1-build-the-paywall\} 1. Rendez-vous dans [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. 2. Cliquez sur **Create paywall**. 3. Saisissez un **Paywall name**. Il s'agit d'un identifiant interne dans l'Adapty Dashboard. 4. Cliquez sur **Add product** et choisissez les produits à afficher sur le paywall. 5. Ouvrez l'onglet **Builder & Generator**. Créez un paywall à partir d'un modèle ou générez-le avec l'IA. 6. Activez le toggle **Show on device** pour que le SDK puisse l'afficher. ### 2. Ajouter le paywall à un placement \{#2-add-the-paywall-to-a-placement-1\} Créez un <InlineTooltip tooltip="placement">Un placement est un point précis de votre app où vous affichez un flow, un paywall, un onboarding ou un test A/B. Les placements vous permettent de cibler des [audiences](audience) spécifiques avec votre contenu. En savoir plus sur les [placements](placements).</InlineTooltip> pour que votre app puisse demander le paywall au runtime. 1. Rendez-vous dans [**Placements**](https://app.adapty.io/placements) dans le menu principal d'Adapty et passez à l'onglet **Paywalls**. 2. Cliquez sur **Create placement**. 3. Saisissez un **Placement name** (ex. : `main` ou `onboarding`). Il s'agit d'un identifiant interne dans l'Adapty Dashboard. 4. Saisissez un **Placement ID**. Vous utiliserez cet ID dans le SDK Adapty pour charger le paywall du placement. 5. Cliquez sur **Run paywall** et choisissez le paywall que vous avez créé. 6. Cliquez sur **Save & publish**. Dans le code de votre app, vous n'écrivez en dur que les IDs de placement. Tout le reste — quel paywall s'exécute, quels produits il vend, comment il se présente — est configuré dans l'Adapty Dashboard et peut être modifié à tout moment sans mise à jour de l'app. </TabItem> </Tabs> ## Prochaines étapes \{#next-steps\} Vous avez maintenant quelque chose à livrer par le SDK. Ensuite, [intégrez le SDK Adapty](quickstart-sdk) dans votre app et commencez à récupérer le placement. --- # File: quickstart-sdk --- --- title: "Intégrer le SDK Adapty dans votre code d'application" description: "Intégrez Adapty avec App Store, Google Play, les stores personnalisés, Stripe et Paddle." --- Intégrez le SDK Adapty dans votre application pour : - Gérer les achats, la validation des reçus et la gestion des abonnements sans configuration supplémentaire - Créer et tester des paywalls sans mise à jour de l'application - Obtenir des analyses d'achats détaillées sans configuration — cohortes, LTV, taux de désabonnement et analyse d'entonnoir inclus - Maintenir le statut d'abonnement de l'utilisateur toujours à jour entre les sessions et les appareils - Intégrer votre application aux services d'attribution marketing et d'analyse en une seule ligne de code ## Comment ça fonctionne \{#how-does-it-work\} Pour une implémentation de base du SDK Adapty, il vous suffit de vous occuper de trois choses : 1. Installer et initialiser le SDK. 2. Déléguer la gestion des achats intégrés à Adapty. 3. Surveiller le statut d'abonnement dans le profil. Adapty détermine le statut d'abonnement, le type et l'expiration — le SDK consomme simplement ces informations. L'ordre et les détails peuvent varier d'une application à l'autre, mais c'est l'essentiel. ## Premiers pas \{#get-started\} Choisissez votre plateforme et lancez-vous : **iOS** - **[Démarrage rapide avec le SDK](ios-sdk-overview)** - **[Exemples d'applications](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)** **Android** - **[Démarrage rapide avec le SDK](android-sdk-overview)** - **[Exemple d'application](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)** **React Native** - **[Démarrage rapide avec le SDK](react-native-sdk-overview)** - **[Exemples d'applications](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/)** **Flutter** - **[Démarrage rapide avec le SDK](flutter-sdk-overview)** - **[Exemple d'application](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)** **Unity** - **[Démarrage rapide avec le SDK](unity-sdk-overview)** - **[Exemple d'application](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)** **Capacitor** - **[Démarrage rapide avec le SDK](capacitor-sdk-overview)** - **[Exemples d'applications](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples)** **Kotlin Multiplatform** : - **[Démarrage rapide avec le SDK](kmp-sdk-overview)** - **[Exemple d'application](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)** ## Prochaines étapes \{#next-steps\} Une fois le SDK Adapty configuré dans le code de votre application, vous pouvez passer à [tester l'implémentation](quickstart-test). --- # File: quickstart-test --- --- title: "Testez votre intégration avec Adapty" description: "Vérifiez rapidement votre intégration Adapty en testant l'activation du SDK, la récupération des paywalls et les achats intégrés sur l'App Store, Google Play, Stripe et Paddle." --- Tout est prêt ! Vérifiez maintenant que votre intégration fonctionne comme prévu et que vos achats apparaissent bien dans l'Adapty Dashboard. Effectuer un achat test est le meilleur moyen de vérifier que votre intégration fonctionne de bout en bout. Commencez par un achat intégré, puis validez vos résultats. ## 1. Tester les achats intégrés \{#1-test-in-app-purchases\} Suivez le guide correspondant à votre store ou plateforme de paiement. ### App store \{#app-store\} Nous recommandons d'utiliser un compte de test (Sandbox Apple ID) et d'effectuer les tests sur un appareil réel. Pour en savoir plus sur toutes les étapes de test, consultez l'article détaillé sur les [tests Sandbox de l'App Store](test-purchases-in-sandbox). :::warning Testez sur un appareil réel pour des résultats plus fiables. Vous pouvez éventuellement utiliser le simulateur, mais nous le déconseillons car il est moins fiable. ::: ### Google Play Store \{#google-play-store\} Créez un utilisateur de test et testez votre application sur un appareil réel. Pour en savoir plus sur toutes les étapes de test, consultez l'article détaillé sur les [tests Google Play Store](testing-on-android). :::note Google [recommande](https://support.google.com/googleplay/android-developer/answer/14316361) d'utiliser un appareil réel pour les tests. Si vous utilisez un émulateur, assurez-vous qu'il dispose de Google Play installé pour garantir le bon fonctionnement de votre application. ::: ### Stripe \{#stripe\} Pour tester des achats sur Stripe, vous devez connecter Stripe à Adapty en utilisant la clé API du mode Test de Stripe. Les transactions effectuées depuis le mode Test de Stripe seront considérées comme Sandbox dans Adapty. Pour en savoir plus sur toutes les étapes de connexion, consultez l'[article sur l'intégration Stripe](stripe#6-test-your-integration). ### Paddle \{#paddle\} Pour tester des achats sur Paddle, vous devez connecter Paddle à Adapty en utilisant la clé API de l'environnement de test Paddle. Les transactions effectuées depuis l'environnement de test Paddle seront considérées comme Test dans Adapty. Pour en savoir plus sur toutes les étapes de connexion, consultez l'[article sur l'intégration Paddle](paddle#4-test-your-integration). ## 2. Valider les achats tests \{#2-validate-test-purchases\} Après avoir effectué un achat test, vérifiez la transaction correspondante dans le [**Event Feed**](https://app.adapty.io/event-feed) de l'Adapty Dashboard. Si l'achat n'apparaît pas dans l'**Event Feed**, Adapty ne le suit pas. Consultez le guide détaillé sur la [validation des achats tests](validate-test-purchases) pour en savoir plus. <img src="/assets/shared/img/test-event-feed.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Prochaines étapes \{#next-steps\} Félicitations pour votre intégration réussie d'Adapty ! Vous êtes maintenant prêt à développer vos achats intégrés. Préparez votre mise en production : <Button id="release-checklist"> Liste de vérification avant publication </Button> Ou continuez avec ce qui suit : - **[Tests A/B](ab-tests)** : Expérimentez avec différents prix, durées d'abonnement, périodes d'essai et éléments visuels pour identifier les combinaisons les plus efficaces. - **[Analytics](how-adapty-analytics-works)** : Plongez dans des métriques de monétisation détaillées pour comprendre le comportement des utilisateurs et optimiser les performances de revenus. - **Intégrations** : Adapty envoie des [événements d'abonnement](events) à des outils d'analytics et d'attribution tiers, tels que [Amplitude](amplitude), [AppsFlyer](appsflyer), [Adjust](adjust), [Branch](branch), [Mixpanel](mixpanel), [Facebook Ads](facebook-ads), [AppMetrica](appmetrica), et un [Webhook](webhook) personnalisé. :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: --- # File: release-checklist --- --- title: "Release checklist" description: "Suivez la checklist de publication d'Adapty pour garantir une mise à jour fluide de votre application." --- Nous sommes ravis que vous ayez choisi d'utiliser Adapty ! Nous espérons que l'intégration s'est bien passée. Ce guide vous accompagne étape par étape pour vous assurer que votre application est prête à être publiée sur les stores et que le flux de monétisation fonctionne correctement. ## Prérequis avant de commencer \{#pre-flight-essentials\} Ce dont vous avez besoin avant de démarrer la validation : - Un vrai appareil avec un compte sandbox - Accès à l'Adapty Dashboard - Accès à App Store Connect / Google Play Console :::note Bien que les achats sandbox puissent fonctionner sur des simulateurs, les vrais appareils sont nécessaires pour tester tous les flux, notamment les fenêtres de paiement et les invites biométriques. ::: <Button id="test-purchases-in-sandbox"> Guide de test pour App Store </Button> <Button id="testing-on-android"> Guide de test pour Google Play </Button> ## Validations universelles \{#universal-validations\} - [ ] **Connexion au store** : Assurez-vous d'avoir connecté Adapty à l'App Store et/ou Google Play : - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **Livraison des événements d'abonnement** : Confirmez que les notifications serveur sont configurées : - [ ] [Notifications serveur App Store](enable-app-store-server-notifications) - [ ] [Notifications développeur en temps réel (RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **Identification du profil** : Validez la logique d'identification des utilisateurs et assurez-vous que les achats sont associés au bon profil : - [ ] [Vérifiez que la logique d'identification dans le code de votre application correspond à votre cas d'usage](ios-quickstart-identify) - [ ] [Assurez-vous de comprendre la logique parent/héritier pour le partage d'accès payant entre les profils utilisateurs](sharing-paid-access-between-user-accounts) - [ ] **Offres** : Si vous avez des offres promotionnelles App Store dans l'application, assurez-vous d'avoir [ajouté votre clé d'achat intégré](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) à la fois dans le champ principal et dans la section **App Store promotional offers**. - [ ] **Collecte de données** : Assurez-vous de respecter la confidentialité : - [ ] Si vous devez vous conformer à des réglementations sur la vie privée comme le RGPD ou le CCPA, ou si votre application est destinée aux enfants, contrôlez si vous [activez la collecte et le partage de l'IDFA et de l'IP](sdk-installation-ios#data-policies). - [ ] Si votre application utilise AppTrackingTransparency, assurez-vous d'[envoyer le statut d'autorisation à Adapty](ios-deal-with-att). - [ ] **Labels de confidentialité** : [En savoir plus](apple-app-privacy) sur les données collectées par Adapty et les indicateurs à définir pour la revue. ## Validations des achats \{#purchase-validations\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Avant le lancement, assurez-vous que les achats intégrés fonctionnent correctement dans votre application et que votre paywall est prêt pour la revue du store. La façon dont vous validez les achats intégrés dépend de la manière dont vous les implémentez : - Vous affichez un paywall créé avec le Paywall Builder d'Adapty - Vous avez implémenté votre propre paywall et utilisez la méthode `makePurchase` pour gérer les achats - Vous utilisez Adapty en mode observateur (avec le Paywall Builder d'Adapty ou votre propre paywall) <Tabs groupId="paywall" queryString> <TabItem value="builder" label="Adapty Paywall Builder" default> **Objectif** : Adapty affiche le paywall, les utilisateurs peuvent acheter des produits, l'accès se déverrouille et le flux de restauration fonctionne. - [ ] Votre application [affiche le paywall](ios-present-paywalls) depuis le même placement que celui que vous allez déployer. - [ ] Le paywall s'affiche à l'écran. Si le chargement prend trop de temps (par exemple, si vous ou vos utilisateurs avez une connexion instable), envisagez d'[ajuster votre politique de récupération](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). - [ ] Le paywall correspond à la variante attendue (audience/langue si applicable). Vous pouvez [modifier la priorité de l'audience](change-audience-priority) si nécessaire. - [ ] Les produits et les prix s'affichent sur le paywall. Notez que l'API d'Apple peut occasionnellement fournir des prix inexacts lors des tests (notamment avec différentes configurations de région), donc privilégiez le test du fonctionnement du flux d'achat plutôt que la précision des prix, car Adapty n'a pas d'influence sur les prix du store. - [ ] L'achat sandbox se termine avec succès. Le callback d'achat réussi est bien reçu. - [ ] L'accès se déverrouille et persiste. Confirmez que [l'accès payant est accordé en fonction du profil Adapty actuel](ios-check-subscription-status#connect-profile-with-paywall-logic). - [ ] Après l'achat, le profil Adapty a un niveau d'accès actif. - [ ] Les fonctionnalités payantes se déverrouillent quand le profil contient ce niveau d'accès (pas seulement au moment du callback d'achat). - [ ] La restauration des achats fonctionne. Quand vous réinstallez l'application ou l'installez sur un nouvel appareil, la restauration automatique des achats fonctionne conformément au paramètre [Partage d'accès payant](sharing-paid-access-between-user-accounts). Si vous n'avez pas d'authentification backend, les achats sont restaurés automatiquement quel que soit le paramètre. Dans les autres cas, assurez-vous que les utilisateurs peuvent restaurer leurs achats après avoir réinstallé l'application. - [ ] Exigences pour la revue du store : - [ ] Le bouton **Restore purchases** est présent sur le paywall. Vous pouvez l'ajouter dans le Paywall Builder, et il traitera automatiquement les restaurations d'achats lorsqu'il est tapé. - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis l'écran du paywall, et cliquer sur ces liens les ouvre dans un navigateur. </TabItem> <TabItem value="makepurchase" label="Custom paywall (makePurchase)" default> **Objectif** : Vous affichez l'interface ; Adapty gère les achats, les mises à jour de profil et les restaurations. - [ ] Les identifiants de produits ne sont pas codés en dur dans votre code. Vous ne codez en dur que les identifiants de [placement](placements). - [ ] Votre application [récupère les produits](fetch-paywalls-and-products) depuis le même placement que celui que vous allez déployer. - [ ] La liste des produits se charge correctement. Si le chargement prend trop de temps (par exemple, si vous ou vos utilisateurs avez une connexion instable), envisagez d'[ajuster votre politique de récupération](fetch-paywalls-and-products#fetch-paywall-information). - [ ] Les produits récupérés correspondent à la variante attendue (audience/langue si applicable). Vous pouvez [modifier la priorité de l'audience](change-audience-priority) si nécessaire. - [ ] Les produits et les prix s'affichent sur le paywall. Notez que l'API d'Apple peut occasionnellement fournir des prix inexacts lors des tests (notamment avec différentes configurations de région), donc privilégiez le test du fonctionnement du flux d'achat plutôt que la précision des prix, car Adapty n'a pas d'influence sur les prix du store. - [ ] L'achat sandbox avec [makePurchase](making-purchases) se termine avec succès : - [ ] Le résultat d'achat réussi est bien géré. - [ ] Les résultats en attente/échoués/annulés sont gérés correctement. - [ ] Si vous [utilisez un Remote Config](present-remote-config-paywalls), ses valeurs sont correctement transmises à votre paywall. - [ ] Quand un paywall est affiché, la méthode [`logShowFlow` (iOS SDK v4+) / `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) est appelée. - [ ] L'achat sandbox se termine avec succès. Le callback d'achat réussi est bien reçu. - [ ] L'accès se déverrouille et persiste. Confirmez que [l'accès payant est accordé en fonction du profil Adapty actuel](ios-check-subscription-status#connect-profile-with-paywall-logic). - [ ] Après l'achat, le profil Adapty a un niveau d'accès actif. - [ ] Les fonctionnalités payantes se déverrouillent quand le profil contient ce niveau d'accès (pas seulement au moment du callback d'achat). - [ ] La restauration des achats fonctionne. Quand vous réinstallez l'application ou l'installez sur un nouvel appareil, la restauration automatique des achats fonctionne conformément au paramètre [Partage d'accès payant](sharing-paid-access-between-user-accounts). Si vous n'avez pas d'authentification backend, les achats sont restaurés automatiquement quel que soit le paramètre. Dans les autres cas, assurez-vous que les utilisateurs peuvent restaurer leurs achats après avoir réinstallé l'application. - [ ] Exigences pour la revue du store : - [ ] Le bouton **Restore purchases** est accessible et [gère les restaurations](restore-purchase). - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis l'écran du paywall, et cliquer sur ces liens les ouvre dans un navigateur. </TabItem> <TabItem value="observer" label="Observer mode"> **Objectif** : Vous gérez les achats, les mises à jour de profil et les restaurations vous-même ; Adapty reçoit les rapports de transactions. - [ ] **Votre application effectue les achats via votre propre flux d'achat** (StoreKit / BillingClient / backend) : - [ ] L'achat sandbox réussit dans l'interface du store. - [ ] Les résultats en attente/échoués/annulés sont gérés correctement dans votre application. - [ ] **Les transactions sont signalées à Adapty**. - [ ] Le mode observateur est [activé dans le code de votre application](implement-observer-mode). - [ ] L'achat apparaît dans le fil d'événements Adapty. - [ ] Les renouvellements, annulations et remboursements sont reflétés au fil du temps (le cas échéant). - [ ] **Les vues de paywall sont suivies**. La méthode [`logShowFlow` (iOS SDK v4+) / `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) est appelée lorsqu'un paywall est affiché. - [ ] **La restauration des achats fonctionne pour votre implémentation**. La réinstallation de l'application ou le changement d'appareil restaure correctement l'accès. - [ ] **Exigences pour la revue du store** : - [ ] L'action **Restore purchases** est accessible et déclenche votre flux de restauration. - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis le paywall ou l'écran d'achat et s'ouvrent dans un navigateur. </TabItem> </Tabs> Si vous avez des questions sur l'intégration du SDK Adapty, utilisez le chatbot IA en bas à droite ou contactez-nous à [support@adapty.io](mailto:support@adapty.io). --- # File: migrate-to-adapty-from-another-solutions --- --- title: "Migrer vers Adapty" description: "Migrez vers Adapty depuis d'autres solutions de gestion des abonnements facilement." --- La migration se déroule en trois étapes : 1. Passer au SDK Adapty. 2. Modifier le webhook des notifications serveur-à-serveur [Apple](enable-app-store-server-notifications) / [Google](enable-real-time-developer-notifications-rtdn). 3. (Optionnel) [Importer les données historiques dans Adapty](importing-historical-data-to-adapty) pour obtenir des statistiques immédiatement. Passons rapidement en revue chaque étape. :::info Vos abonnés migreront automatiquement Tous les utilisateurs ayant déjà activé un abonnement seront migrés dès qu'ils ouvriront une nouvelle version intégrant le SDK Adapty. La validation du statut d'abonnement et l'accès premium seront restaurés automatiquement. ::: ### Installer le SDK Adapty \{#installing-adapty-sdk\} Installez le SDK Adapty pour votre plateforme ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) dans votre application et remplacez votre logique existante par les méthodes appropriées du SDK Adapty. Les éléments essentiels à remplacer : - Vérifier un [niveau d'accès](access-level) pour accéder à du contenu restreint ; - Effectuer un achat ; - Restaurer un achat ; - Récupérer/définir les informations concernant votre utilisateur. :::tip Vous migrez depuis un autre fournisseur d'abonnements ? Suivez notre guide pour un accompagnement détaillé : - [Migration depuis RevenueCat](migration-from-revenuecat) (20 minutes) ::: ### Modifier les notifications serveur Apple \{#changing-apple-server-notifications\} Apple et Google nous envoient des événements liés aux abonnements des utilisateurs en dehors de l'application (renouvellement, annulation, mise en pause, remboursement, etc.) via les [notifications serveur App Store](enable-app-store-server-notifications). Adapty peut fonctionner sans cette URL, mais vous disposerez alors d'un ensemble de fonctionnalités limité. Par exemple, les [intégrations](events) avec des services tiers seront retardées, les analyses d'abonnements ne seront pas en temps réel et les métriques des tests A/B de paywall ne seront pas précises. Lors de la transition depuis un système existant, il peut être utile de faire fonctionner les deux systèmes en parallèle pendant un certain temps. Dans ce cas, vous pouvez utiliser notre [transfert d'événements bruts](enable-app-store-server-notifications#raw-events-forwarding), où Adapty joue le rôle de serveur proxy pour votre ancien système. <img src="/assets/shared/img/c7d4fd0-Seamless_migrat_a.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Transférer les données historiques vers Adapty \{#move-historical-data-to-adapty\} Le transfert des données historiques est optionnel et n'affectera pas l'état de vos abonnés. Cependant, il y a plusieurs bonnes raisons de le faire : 1. **Les analyses fonctionneront correctement immédiatement**. Adapty identifie les abonnés par leur identifiant de transaction d'origine, et nous ne comptabilisons pas les événements provenant du webhook Apple sans les avoir exposés au SDK Adapty (ce n'est techniquement pas possible). 2. **Les données utilisées seront disponibles**. Vous aurez tous les profils Adapty avec les propriétés utilisateur et pourrez les utiliser dans les [Segments](segments) et [Profils/CRM](profiles-crm). Suivez notre [tutoriel](importing-historical-data-to-adapty) pour nous envoyer vos données historiques. --- # File: observer-vs-full-mode --- --- title: "Mode Observateur" description: "Comparez le Mode Observateur et le Mode Complet dans Adapty pour les abonnements." --- Adapty est une plateforme d'achats intégrés puissante et flexible, conçue pour booster vos revenus et votre base d'abonnés. Grâce à des paywalls personnalisables ciblant des segments d'utilisateurs spécifiques, des tests A/B sur les prix, les durées, les périodes d'essai et les éléments visuels, ainsi que des outils analytiques complets pour la monétisation et les intégrations tierces, Adapty renforce votre stratégie de croissance. Cependant, si vous disposez déjà de votre propre infrastructure d'achat et que vous n'êtes pas prêt à passer au système d'Adapty, vous pouvez explorer le mode Observateur d'Adapty. Ce mode limité n'utilise pas les paywalls Adapty, ne les cible pas vers des audiences d'utilisateurs, ne gère pas les abonnements (y compris les renouvellements et les relances de facturation) et se concentre uniquement sur l'analyse. Malgré ses limitations, le mode Observateur offre tout de même de solides capacités analytiques, notamment l'intégration avec les systèmes d'attribution, l'analyse avancée, la messagerie et les profils CRM. Les deux modes sont proposés au même prix et nécessitent une mise à jour de votre application mobile. Le choix se résume donc à soit basculer vers l'infrastructure d'Adapty pour bénéficier de toutes les fonctionnalités, soit conserver votre infrastructure actuelle tout en accédant uniquement aux intégrations tierces et aux capacités analytiques. | Fonctionnalité | Mode Observateur | Mode Complet | |-------------|-------------|---------| | **Analyse complète** | ✅ | ✅ | | **Intégrations tierces** | ✅ | ✅ | | **Réponse aux événements d'achat pour accorder/restreindre l'accès payant à vos utilisateurs** | ❌ | ✅ | | **Gestionnaire de l'infrastructure d'achats** | Vous | Adapty | | **Tests A/B** | <p>Réalisable, mais nécessite beaucoup de code et de configuration supplémentaires, plus qu'en Mode Complet.</p> | ✅ | | **Temps de mise en œuvre** | <p>Pour l'analyse et les intégrations : moins d'une heure</p><p>Avec des tests A/B : jusqu'à une semaine avec des tests approfondis</p> | Quelques heures | ## Fonctionnement du mode Observateur \{#how-observer-mode-works\} En mode Observateur, vous signalez les nouvelles transactions Apple/Google au SDK Adapty, qui les transmet ensuite au backend Adapty. Vous êtes responsable de la gestion de l'accès au contenu payant dans votre application, de la finalisation des transactions, du traitement des renouvellements, de la résolution des problèmes de facturation, etc. ## Comment configurer le mode Observateur \{#how-to-set-up-observer-mode\} 1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios). 2. Activez-le lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk), [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk) et [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 3. [Signalez les transactions](report-transactions-observer-mode) depuis votre infrastructure d'achat existante vers Adapty pour iOS et les frameworks multiplateformes basés sur iOS. 4. (optionnel) Si vous souhaitez utiliser des intégrations tierces, configurez-les comme décrit dans la rubrique [Configurer une intégration tierce](configuration). :::warning En mode Observateur, le SDK Adapty ne finalise pas les transactions : assurez-vous de gérer cet aspect vous-même. ::: ## Comment utiliser les paywalls et les tests A/B en mode Observateur \{#how-to-use-paywalls-and-ab-tests-in-observer-mode\} En mode Observateur, le SDK Adapty ne peut pas déterminer la source des achats, car vous les effectuez dans votre propre infrastructure. Par conséquent, si vous souhaitez utiliser des paywalls et/ou des tests A/B en mode Observateur, vous devez associer dans le code de votre application mobile la transaction provenant de votre store à la paywall correspondante lorsque vous signalez une transaction. De plus, les paywalls conçues avec le Paywall Builder doivent être affichées d'une manière spéciale lorsque vous utilisez le mode Observateur : - Affichez les paywalls en mode Observateur pour [iOS](implement-observer-mode) ou [Android](android-present-paywall-builder-paywalls-in-observer-mode). - [Associez les paywalls aux transactions d'achat](report-transactions-observer-mode) lors du signalement des transactions en mode Observateur. --- # File: migration-from-revenuecat --- --- title: "Migration depuis RevenueCat" description: "Migrez de RevenueCat vers Adapty grâce à notre guide étape par étape." --- Votre plan de migration comporte 5 étapes logiques et prend en moyenne 2 heures. 90 % des migrations prennent moins d'une journée de travail. 1. Découvrez les différences essentielles ; créez et configurez un compte Adapty _(5 minutes)_ ; 2. Installez le SDK Adapty pour votre plateforme ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) à la place du SDK RevenueCat _(1 heure)_ ; 3. Configurez les [notifications serveur de l'Apple App Store](enable-app-store-server-notifications) vers Adapty et (optionnellement) le [transfert des événements bruts](enable-app-store-server-notifications#raw-events-forwarding) _(5 minutes)_ ; 4. Testez et publiez les mises à jour de votre application _(30 minutes)_ ; 5. (Optionnel) Demandez à l'assistance RevenueCat les données historiques au format CSV _(5 minutes)_ ; 6. (Optionnel) Importez les données historiques via l'assistance Adapty _(30 minutes)_. :::info Vos abonnés migrent automatiquement Tous les utilisateurs ayant déjà activé un abonnement passeront instantanément sur Adapty dès qu'ils ouvriront la nouvelle version de votre application avec le SDK Adapty. La validation du statut d'abonnement et l'accès premium seront restaurés automatiquement. ::: Avant de publier une nouvelle version de votre application avec le SDK Adapty, consultez notre [checklist de publication](release-checklist). ## Découvrez les différences essentielles ; créez et configurez un compte Adapty \{#learn-the-core-differences-create-and-prepare-an-adapty-account\} Les SDK Adapty et RevenueCat sont conçus de façon similaire. La principale différence porte sur l'utilisation du réseau et la vitesse : le SDK Adapty est conçu pour vous fournir les informations à la demande aussi rapidement que possible. Par exemple, lors d'une requête de paywall, vous obtenez d'abord le [Remote Config](customize-paywall-with-remote-config) pour pré-construire votre onboarding ou votre paywall, puis vous demandez les produits dans une requête dédiée. La terminologie diffère légèrement : | RevenueCat | Adapty | | :---------- | :-------------- | | Package | Produit | | Offering | Paywall | | Paywall | Paywall Builder | | Entitlement | Niveau d'accès | Adapty repose sur la notion de [placement](placements). Il s'agit d'un endroit logique dans votre application où l'utilisateur peut effectuer un achat. Dans la plupart des cas, vous avez un ou deux placements : - Onboarding (car 80 % de tous les achats y ont lieu) ; - Général (affiché dans les paramètres ou dans l'application après l'onboarding). <img src="/assets/shared/img/2406d97-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Installez le SDK Adapty et remplacez le SDK RevenueCat \{#install-adapty-sdk-and-replace-revenuecat-sdk\} Installez le SDK Adapty pour votre plateforme ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) dans votre application. Vous devez remplacer quelques méthodes SDK côté application. Voici les fonctions les plus courantes et comment les remplacer par celles du SDK Adapty. ### Activation du SDK \{#sdk-activation\} Remplacez `Purchases.configure` par `Adapty.activate`. ### Récupération des paywalls (offerings) \{#getting-paywalls-offerings\} Remplacez `Purchases.shared.getOfferings` par [`Adapty.getPaywall`](fetch-paywalls-and-products#fetch-paywall-information). Dans Adapty, vous demandez toujours le paywall via un [identifiant de placement](placements). En pratique, vous ne récupérez jamais plus d'un ou deux paywalls, ce choix délibéré vise à accélérer le SDK et à réduire l'utilisation du réseau. ### Récupération d'un utilisateur (profil client) \{#getting-a-user-customer-profile\} Remplacez `Purchases.shared.getCustomerInfo` par `Adapty.getProfile`. ### Récupération des produits \{#getting-products\} Dans RevenueCat, vous utilisez la structure suivante : `Purchases.shared.getOfferings` puis `self.offering?.availablePackages`. Dans Adapty, vous demandez d'abord un paywall (voir ci-dessus) pour accéder immédiatement au [Remote Config](customize-paywall-with-remote-config) d'Adapty, puis vous appelez les produits avec [`Adapty.getPaywallProducts`](fetch-paywalls-and-products#fetch-products). ### Effectuer un achat \{#making-a-purchase\} Remplacez `Purchases.shared.purchase` par [`Adapty.makePurchase`](making-purchases#make-purchase). ### Vérifier le niveau d'accès (entitlement) \{#checking-access-level-entitlement\} Récupérez un profil client (voir ci-dessus) puis remplacez `customerInfo?.entitlements["premium"]?.isActive == true` par [`profile.accessLevels["premium"]?.isActive == true`](subscription-status#retrieving-the-access-level-from-the-server). ### Restaurer un achat \{#restore-purchase\} Remplacez `Purchases.shared.restorePurchases` par [`Adapty.restorePurchases`](restore-purchase). ### Vérifier si l'utilisateur est connecté \{#check-if-the-user-is-logged-in\} Remplacez `Purchases.shared.isAnonymous` par `if profile.customerUserId == nil`. ### Connecter un utilisateur \{#log-in-user\} Remplacez `Purchases.shared.logIn` par [`Adapty.identify`](identifying-users#set-customer-user-id-after-configuration). ### Déconnecter un utilisateur \{#log-out-user\} Remplacez `Purchases.shared.logOut` par [`Adapty.logout`](identifying-users#logging-out-and-logging-in). ## Redirigez les notifications serveur de l'App Store vers Adapty \{#switch-app-store-server-side-notifications-to-adapty\} Découvrez comment procéder [ici](migrate-to-adapty-from-another-solutions#changing-apple-server-notifications). ## Testez et publiez une nouvelle version de votre application \{#test-and-release-a-new-version-of-your-app\} Si vous lisez ceci, vous avez déjà : - [x] Configuré l'Adapty Dashboard - [x] Installé le SDK Adapty - [x] Remplacé la logique SDK par les fonctions Adapty - [x] Redirigé les notifications serveur de l'App Store vers Adapty et, optionnellement, activé le transfert des événements bruts vers RevenueCat - [ ] Effectué un achat sandbox - [ ] Publié une nouvelle version de l'application Si vous avez coché les points ci-dessus, effectuez simplement un achat test en Sandbox, puis publiez l'application. :::info Parcourez la [checklist de publication](release-checklist). Effectuez la vérification finale à l'aide de notre liste pour valider l'intégration existante ou ajouter des fonctionnalités supplémentaires telles que les intégrations [attribution](attribution-integration) ou [analytics](analytics-integration). ::: ## (Optionnel) Exportez vos données historiques RevenueCat au format CSV \{#optional-export-your-revenuecat-historical-data--in-csv-format\} :::warning Ne vous précipitez pas pour importer les données historiques Attendez au moins une semaine après la publication avec le SDK avant d'importer les données historiques. Durant cette période, nous récupérerons toutes les informations sur les prix d'achat via le SDK, ce qui rendra les données importées plus pertinentes. ::: Exportez vos données historiques depuis RevenueCat au format CSV en suivant les instructions de la [documentation officielle de RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports). ## (Optionnel) Demandez à l'assistance RevenueCat les Google Purchase Tokens \{#optional-ask-revenuecat-support-for-google-purchase-tokens\} Si vous devez importer des transactions Google Play, contactez l'assistance RevenueCat pour obtenir un fichier CSV contenant les Google Purchase Tokens via leur [page d'assistance](https://app.revenuecat.com/settings/support). Le Google Purchase Token est un identifiant unique fourni par Google Play pour chaque transaction, indispensable pour suivre et vérifier avec précision les achats dans Adapty. Cette information n'est pas incluse dans le fichier d'export standard. Le fichier contient les trois colonnes suivantes : - `user_id` - `google_purchase_token` - `google_product_id` ## Contactez-nous pour importer vos données historiques \{#write-us-to-import-your-historical-data\} Contactez-nous via le chat du site ou par e-mail à [support@adapty.io](mailto:support@adapty.io) avec vos fichiers CSV. 1. Envoyez directement le fichier CSV exporté depuis RevenueCat à notre équipe d'assistance. 2. Si vous importez des transactions Google Play, joignez le fichier CSV contenant les Google Purchase Tokens reçu de l'assistance RevenueCat. 3. Indiquez-nous quel identifiant utilisateur doit être utilisé comme Customer User ID (identifiant principal de l'utilisateur dans Adapty) : `rc_original_app_user_id` ou `rc_last_seen_app_user_id_alias`. Notre équipe d'assistance importera vos transactions dans Adapty. Les données suivantes seront importées pour chaque transaction : | Paramètre | Description | | ----------------------------- | ------------------------------------------------------------ | | user_id | Customer User ID, l'identifiant principal de votre utilisateur dans Adapty et votre système. | | apple_original_transaction_id | Pour les chaînes d'abonnements, il s'agit de la date d'achat de la transaction d'origine, liée par `store_original_transaction_id`. | | google_product_id | L'identifiant du produit dans le Google Play Store. | | google_purchase_token | Un identifiant unique fourni par Google Play pour chaque transaction, requis pour la validation. | | country | Le pays de l'utilisateur. | | created_at | La date et l'heure de création de l'utilisateur. | | subscription_expiration_date | La date et l'heure d'expiration de l'abonnement. | | email | L'adresse e-mail de l'utilisateur final. | | phone_number | Le numéro de téléphone de l'utilisateur final. | | idfa | L'Identifier for Advertisers (IDFA), attribué par Apple à l'appareil d'un utilisateur. | | idfv | L'Identifier for Vendors (IDFV), un code attribué à toutes les applications d'un même développeur et partagé entre ces applications sur un appareil. | | advertising_id | Un identifiant unique fourni par l'OS Android que les annonceurs peuvent utiliser pour le suivi. | | attribution_channel | Le nom du canal marketing. | | attribution_campaign | Le nom de la campagne marketing. | | attribution_ad_group | Le groupe d'annonces d'attribution. | | attribution_ad_set | L'ensemble d'annonces d'attribution. | | attribution_creative | Le mot-clé créatif d'attribution. | En outre, les identifiants d'intégration pour les intégrations suivantes seront importés : Amplitude, Mixpanel, AppsFlyer, Adjust et FacebookAds. ## FAQ \{#faq\} ### J'ai installé le SDK Adapty avec succès et publié une nouvelle version de l'application. Que se passera-t-il pour mes abonnés existants qui n'ont pas mis à jour vers la version avec le SDK Adapty ? \{#i-successfully-installed-adapty-sdk-and-released-a-new-app-version-with-it-what-will-happen-to-my-legacy-subscribers-who-did-not-update-to-a-version-with-adapty-sdk\} La plupart des utilisateurs chargent leur téléphone la nuit, c'est généralement à ce moment-là que l'App Store met automatiquement à jour toutes leurs applications, donc cela ne devrait pas poser de problème. Il peut subsister un petit nombre d'abonnés payants qui n'ont pas effectué la mise à jour, mais ils auront toujours accès au contenu premium. Vous n'avez pas à vous en préoccuper ni à les forcer à mettre à jour. ### Dois-je exporter mes données historiques de RevenueCat le plus vite possible, ou vais-je les perdre ? \{#do-i-need-to-export-my-historical-data-from-revenuecat-as-quickly-as-possible-or-will-i-lose-it\} Pas besoin de vous précipiter ; publiez d'abord une version avec le SDK Adapty, puis transmettez-nous vos données historiques. Nous restaurerons l'historique des paiements de vos utilisateurs et alimenterons les [profils](profiles-crm) et les [graphiques](charts). ### J'utilise un MMP (AppsFlyer, Adjust, etc.) et des outils d'analytics (Mixpanel, Amplitude, etc.). Comment m'assurer que tout fonctionnera correctement ? \{#i-use-mmp-appsflyer-adjust-etc-and-analytics-mixpanel-amplitude-etc-how-do-i-make-sure-that-everything-will-work\} Vous devez d'abord nous transmettre les identifiants de ces services tiers via notre SDK pour que nous puissions leur envoyer des données. Consultez le guide d'[intégration attribution](attribution-integration) et d'[intégration analytics](analytics-integration). Pour les données historiques et les utilisateurs existants, **assurez-vous de nous transmettre ces identifiants à partir des données que vous avez exportées depuis RevenueCat.** --- # File: migration-from-superwall --- --- title: "Migration depuis Superwall" description: "Migrez de Superwall vers Adapty grâce à un guide étape par étape qui mappe chaque appel SDK et chaque concept." --- La plupart des migrations de Superwall vers Adapty prennent environ deux heures. Vous remplacez le SDK, pointez vos notifications serveur du store vers Adapty, et publiez une nouvelle version de l'app. Vos abonnés payants conservent leur accès — Adapty le restaure à partir des reçus App Store et Google Play au premier lancement. :::info Vos abonnés migreront automatiquement Tous les utilisateurs ayant activé un abonnement migrent vers Adapty dès qu'ils ouvrent une nouvelle version de votre app avec le SDK Adapty. La validation du statut d'abonnement et l'accès premium sont restaurés automatiquement. ::: ## Organisation de ce guide \{#how-this-guide-is-organized\} La migration comporte six étapes : 1. [Mapper vos concepts Superwall vers Adapty](#map-your-superwall-concepts-to-adapty) 2. [Installer le SDK Adapty](#install-the-adapty-sdk) 3. [Remplacer les appels SDK](#replace-sdk-calls) 4. [Basculer les notifications serveur App Store et Google Play](#switch-app-store-and-google-play-server-notifications) 5. [Tester et publier](#test-and-release) 6. [(Optionnel) Importer les données historiques](#optional-import-historical-data) ## Mapper vos concepts Superwall vers Adapty \{#map-your-superwall-concepts-to-adapty\} La plupart des concepts Superwall ont un équivalent direct dans Adapty : | Superwall | Adapty | Ce qui change | | :------------------- | :------------------------------------------------ | :--------------------------------------------------------------------------- | | Campaign | [Placement](placements) + [Audience](audience) | La logique de campagne se divise en un placement (l'emplacement) et une audience (la règle). | | Placement | [Placement](placements) | Même concept, même nom. | | Audience filter | [Audience](audience) | Les ensembles de règles vivent à l'intérieur d'un placement. | | Entitlement | [Niveau d'accès](access-level) | Identifiant nommé (par exemple, `premium`). | | WebView paywall | [Paywall Paywall Builder](adapty-paywall-builder) | Rendu nativement par le SDK Adapty à la place d'une `WKWebView`. | | `PurchaseController` | Intégré | Aucun protocole à implémenter — Adapty gère les achats. | | Feature gating | Vérification du [niveau d'accès](access-level) | Vérifiez `profile.accessLevels["premium"]?.isActive`. | Deux changements de logique méritent d'être notés avant de toucher au code : - **Récupération et présentation sont deux étapes distinctes** : le `register` de Superwall récupère le paywall, évalue la campagne et affiche l'interface en un seul appel. Adapty sépare ces étapes — vous récupérez le paywall, obtenez sa configuration, puis le présentez. Ce découpage ajoute quelques lignes, mais vous permet de précharger les configurations, d'afficher un état de chargement personnalisé ou d'annuler la présentation selon votre propre logique. - **Le statut d'abonnement est par niveau d'accès** : Superwall expose une propriété publiée `subscriptionStatus` unique. Adapty retourne un [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile) avec des niveaux d'accès nommés, de sorte qu'un utilisateur peut détenir les niveaux d'accès `sports` et `science` indépendamment. Pour les lectures synchrones, mettez en cache le profil depuis l'`AdaptyDelegate` plutôt que d'appeler `getProfile()` à chaque chargement de vue. ## Installer le SDK Adapty \{#install-the-adapty-sdk\} Installez le SDK Adapty pour votre plateforme — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) ou [Capacitor](sdk-installation-capacitor) — et supprimez SuperwallKit de votre projet en même temps. ## Remplacer les appels SDK \{#replace-sdk-calls\} Parcourez chaque partie de votre intégration et remplacez l'appel Superwall par son équivalent Adapty. Les liens en fin de chaque sous-section couvrent les sept SDK de plateforme — suivez celui qui correspond à votre app. ### Initialiser le SDK \{#initialize-the-sdk\} Remplacez `Superwall.configure` par `Adapty.activate`. Consultez le guide d'installation pour votre plateforme — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) ou [Capacitor](sdk-installation-capacitor). ### Identifier et déconnecter les utilisateurs \{#identify-and-log-out-users\} Remplacez `Superwall.shared.identify` par `Adapty.identify` et `Superwall.shared.reset` par `Adapty.logout`. Les deux SDK génèrent un profil anonyme au premier lancement, donc ces appels ne sont nécessaires que lorsqu'un utilisateur se connecte ou se déconnecte. Récupérez à nouveau les paywalls après identification — le nouvel utilisateur peut correspondre à une audience différente. Consultez le guide d'identification pour votre plateforme — [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Unity](unity-identifying-users) ou [Capacitor](capacitor-identifying-users). ### Récupérer et présenter un paywall \{#fetch-and-present-a-paywall\} Remplacez `Superwall.shared.register` par un flux en deux étapes : récupérez le paywall avec `Adapty.getPaywall`, chargez sa configuration de vue avec `AdaptyUI.getPaywallConfiguration`, puis présentez-le. Deux différences à noter : - **Le feature gating remplace la closure `feature:`** : une fois le paywall fermé, vérifiez le niveau d'accès actif sur le profil retourné (ou via `Adapty.getProfile`) et agissez en conséquence. - **Les paywalls sont rendus par le SDK** : Superwall rend les paywalls dans une `WKWebView`. Adapty rend les paywalls Paywall Builder nativement — les polices, les informations produit et les boutons sont dessinés par le SDK. Consultez le guide de démarrage rapide des paywalls pour votre plateforme — [iOS](ios-quickstart-paywalls), [Android](android-quickstart-paywalls), [React Native](react-native-quickstart-paywalls), [Flutter](flutter-quickstart-paywalls), [Kotlin Multiplatform](kmp-quickstart-paywalls), [Unity](unity-quickstart-paywalls) ou [Capacitor](capacitor-quickstart-paywalls). ### Vérifier le statut d'abonnement \{#check-subscription-status\} Remplacez `Superwall.shared.subscriptionStatus` par une vérification sur le niveau d'accès nommé du profil : `profile.accessLevels["premium"]?.isActive`. Observez les changements via `AdaptyDelegate.didLoadLatestProfile(_:)` plutôt que le pattern `@Published`, et mettez en cache le profil de votre côté pour les lectures synchrones. Consultez le guide du statut d'abonnement pour votre plateforme — [iOS](ios-check-subscription-status), [Android](android-check-subscription-status), [React Native](react-native-check-subscription-status), [Flutter](flutter-check-subscription-status), [Kotlin Multiplatform](kmp-check-subscription-status), [Unity](unity-check-subscription-status) ou [Capacitor](capacitor-check-subscription-status). ### Gérer les achats et les restaurations \{#handle-purchases-and-restores\} Avec le Paywall Builder, les deux SDK traitent les achats automatiquement dans l'interface du paywall — **vous pouvez ignorer cette étape**. Pour les paywalls personnalisés, Superwall requiert une implémentation de `PurchaseController`. Adapty non : remplacez `PurchaseController.purchase` par `Adapty.makePurchase` et `PurchaseController.restorePurchases` par `Adapty.restorePurchases`. Le SDK gère la validation lui-même. Consultez le guide de démarrage rapide des paywalls personnalisés pour votre plateforme — [iOS](ios-quickstart-manual), [Android](android-quickstart-manual), [React Native](react-native-quickstart-manual), [Flutter](flutter-quickstart-manual), [Kotlin Multiplatform](kmp-quickstart-manual), [Unity](unity-quickstart-manual) ou [Capacitor](capacitor-quickstart-manual). ### Définir les attributs utilisateur \{#set-user-attributes\} Remplacez `Superwall.shared.setUserAttributes` par `Adapty.updateProfile`. Consultez le guide des attributs utilisateur pour votre plateforme — [iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes), [Kotlin Multiplatform](kmp-setting-user-attributes), [Unity](unity-setting-user-attributes) ou [Capacitor](capacitor-setting-user-attributes). ## Basculer les notifications serveur App Store et Google Play \{#switch-app-store-and-google-play-server-notifications\} Pointez vos notifications serveur du store vers Adapty. Adapty fonctionne sans elles, mais les analyses, les intégrations tierces et les métriques des tests A/B en dépendent : - **App Store** : Suivez [Activer les notifications serveur App Store](enable-app-store-server-notifications). - **Google Play** : Suivez [Activer les notifications développeur en temps réel](enable-real-time-developer-notifications-rtdn). Si vous souhaitez faire tourner Superwall et Adapty en parallèle pendant le déploiement, utilisez le [transfert d'événements bruts](enable-app-store-server-notifications#raw-events-forwarding) — Adapty relaie les événements du store vers Superwall pendant que vous vérifiez la nouvelle intégration. ## Tester et publier \{#test-and-release\} Avant de publier, vérifiez chaque point : - [x] Configuré l'Adapty Dashboard (produits, paywalls, placements, niveaux d'accès) - [x] Installé le SDK Adapty - [x] Remplacé les appels SDK Superwall par leurs équivalents Adapty - [x] Pointé les notifications serveur App Store et Google Play vers Adapty - [ ] Effectué un achat en sandbox - [ ] Soumis une nouvelle version de l'app Parcourez la [liste de contrôle avant publication](release-checklist) pour une validation finale. ## (Optionnel) Importer les données historiques \{#optional-import-historical-data\} Superwall ne possède pas votre état d'abonnement — l'App Store et Google Play le font. Adapty valide les reçus au premier lancement, donc les utilisateurs payants conservent leur accès sans aucune importation. Si vous souhaitez que les transactions historiques soient importées dans les analyses Adapty, suivez [Importer les données historiques dans Adapty](importing-historical-data-to-adapty). Attendez au moins une semaine après la publication du SDK pour que celui-ci ait le temps de collecter les prix d'achat récents. ## FAQ \{#faq\} ### Que se passe-t-il pour les abonnés qui ne mettent pas à jour l'app ? \{#what-happens-to-subscribers-who-dont-update-the-app\} La plupart des utilisateurs mettent à jour leurs apps automatiquement pendant la nuit, donc la proportion d'utilisateurs sur l'ancienne version diminue rapidement. Les abonnés sur l'ancienne version conservent leur accès directement via l'App Store ou Google Play — vous n'avez pas besoin de forcer une mise à jour. ### Les audiences de mes campagnes Superwall sont-elles transférées ? \{#do-my-superwall-campaign-audiences-carry-over\} Non. Les filtres d'audience Superwall et les audiences Adapty sont configurés dans des tableaux de bord différents et utilisent des identifiants différents. Recréez votre ciblage sous forme d'[audiences](audience) dans les [placements](placements) Adapty. La plupart des apps utilisent un ou deux placements (onboarding et déclencheur général dans l'app), donc la reconstruction est généralement rapide. ### Adapty a-t-il un équivalent à `getPresentationResult` ? \{#does-adapty-have-an-equivalent-to-getpresentationresult\} Pas sous la forme d'un seul appel. Pour vérifier si un placement afficherait un paywall, appelez `Adapty.getPaywall(placementId:)` et agissez selon le résultat. Si l'appel réussit, un paywall est attribué à l'audience de cet utilisateur. S'il échoue parce qu'aucun paywall n'est configuré, ignorez la présentation et exécutez votre logique de secours. --- # File: importing-historical-data-to-adapty --- --- title: "Importation des données historiques dans Adapty" description: "Importez des données historiques dans Adapty pour des analyses détaillées." --- Après avoir installé le SDK Adapty et publié votre application, vous pouvez accéder à vos utilisateurs et abonnés dans la section [Profiles](profiles-crm). Mais que faire si vous disposez d'une infrastructure existante et souhaitez migrer vers Adapty, ou si vous voulez simplement consulter vos données existantes dans Adapty ? :::note L'importation de données n'est pas obligatoire Adapty accordera automatiquement des niveaux d'accès aux utilisateurs historiques et restaurera leurs événements d'achat dès qu'ils ouvriront l'application avec le SDK Adapty intégré. Pour ce cas d'usage, l'importation de données historiques n'est pas nécessaire. Cependant, l'importation de données garantit des analyses précises si vous disposez d'un volume important de transactions historiques, bien qu'elle ne soit généralement pas requise pour la migration. ::: Pour importer des données dans Adapty : 1. Exportez vos transactions dans un fichier CSV (des fichiers séparés doivent être fournis pour iOS, Android et Stripe). Consultez la [section Format du fichier d'importation](importing-historical-data-to-adapty#import-file-format) ci-dessous pour les exigences détaillées. 2. Si un fichier dépasse 1 Go, préparez un échantillon de données d'environ 100 lignes. 3. Téléchargez tous les fichiers sur Google Drive (vous pouvez les compresser, mais gardez-les séparés). 4. Pour les transactions iOS, assurez-vous que la section **In-app purchase API** dans les [**App settings**](https://app.adapty.io/settings/ios-sdk) est renseignée avec l'**Issuer ID**, le **Key ID** et la **Private key** (fichier .P8), même si vous utilisez StoreKit 1. Consultez les sections [Provide Issuer ID and Key ID](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) et [Upload In-App Purchase Key file](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file) pour des instructions détaillées. 5. Partagez les liens avec notre équipe par [e-mail](mailto:support@adapty.io) ou via le chat en ligne dans l'Adapty Dashboard. Ne vous inquiétez pas, l'importation de données historiques ne créera pas de doublons, même si ces données chevauchent des entrées existantes dans Adapty. ## Limitations connues pour Android \{#known-limitations-for-android\} 1. Seuls les abonnements actifs seront restaurés ; les transactions expirées ne le seront pas. 2. Seuls les derniers renouvellements d'un abonnement seront restaurés ; la chaîne complète des achats ne le sera pas. 3. Si le prix du produit a changé depuis l'achat, le prix actuel sera utilisé, ce qui peut entraîner des erreurs de tarification. :::note Si vous avez un grand volume de transactions Android, vous devrez peut-être [demander une augmentation du quota de l'API Google Play Developer](google-play-quota-increase) avant de commencer l'importation afin d'éviter de dépasser la limite par défaut de l'API. ::: ## Format du fichier d'importation \{#import-file-format\} :::tip Si vous migrez depuis RevenueCat, vous pouvez envoyer directement le fichier d'export RevenueCat — aucune conversion n'est nécessaire. Consultez la [documentation de RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports) pour les instructions d'export. ::: Préparez vos données dans un ou plusieurs fichiers respectant les règles suivantes : - [ ] Le format du fichier est .CSV. - [ ] Des fichiers séparés pour les importations Android, iOS et Stripe. - [ ] Chaque fichier d'importation contient toutes les [colonnes requises](importing-historical-data-to-adapty#required-fields). - [ ] Les colonnes des fichiers d'importation ont des en-têtes. - [ ] Les en-têtes de colonnes sont exactement ceux indiqués dans la colonne **Column name** du tableau ci-dessous. Vérifiez les fautes de frappe. - [ ] Les colonnes non requises peuvent être absentes du fichier. N'ajoutez pas de colonnes vides pour les données que vous n'avez pas. - [ ] Les fichiers d'importation ne doivent pas contenir de colonnes supplémentaires non mentionnées dans le tableau. Si c'est le cas, supprimez-les. - [ ] Les valeurs sont séparées par des virgules. - [ ] Les valeurs ne sont pas entourées de guillemets. - [ ] Si un utilisateur possède plusieurs **apple_original_transaction_id**, ajoutez-les tous en lignes séparées pour chaque **apple_original_transaction_id**. Sinon, nous pourrions ne pas être en mesure de restaurer les achats consommables. Utilisez les fichiers suivants comme exemples pour [iOS](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_ios_sample.csv) et [Android](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_android_sample.csv). ### Colonnes disponibles dans le fichier d'importation \{#available-import-file-columns\} | Nom de la colonne | Présence | Description | |-----------|--------|-----------| | **user_id** | requis | ID de votre utilisateur | | **apple_original_transaction_id** | requis pour iOS | <p>L'identifiant de transaction original ou OTID ([en savoir plus](https://developer.apple.com/documentation/appstoreserverapi/originaltransactionid)), utilisé dans le mécanisme d'importation StoreKit 2. Un utilisateur pouvant avoir plusieurs OTID, il suffit d'en fournir au moins un pour réussir l'importation.</p><p></p><p>**Remarque :** Nous exigeons que les identifiants de l'API d'achat intégré soient configurés dans votre Adapty Dashboard pour cette importation. Découvrez comment le faire [ici](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).</p> | | **google_product_id** | requis pour Google | ID du produit dans le Google Play Store. | | **google_purchase_token** | requis pour Google | Identifiant unique représentant l'utilisateur et l'ID du produit pour l'achat intégré effectué | | **google_is_subscription** | requis pour Google | Les valeurs possibles sont `1` \| `0` | | **stripe_token** | requis pour Stripe | Token d'un objet Stripe représentant un achat unique. Peut être un token d'abonnement Stripe (`sub_...`) ou d'intention de paiement (`pi_...`). | | **subscription_expiration_date** | optionnel | La date d'expiration de l'abonnement, c'est-à-dire la prochaine date de facturation, date et heure avec fuseau horaire (2020-12-31T23:59:59-06:00) | | **created_at** | optionnel | Date et heure de création du profil (2019-12-31 23:59:59-06:00) | | **birthday** | optionnel | La date de naissance de l'utilisateur au format 2000-12-31 | | **email** | optionnel | L'adresse e-mail de votre utilisateur | | **gender** | optionnel | Le genre de l'utilisateur | | **phone_number** | optionnel | Le numéro de téléphone de votre utilisateur | | **country** | optionnel | format [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) | | **first_name** | optionnel | Le prénom de votre utilisateur | | **last_name** | optionnel | Le nom de famille de votre utilisateur | | **last_seen** | optionnel | La date et l'heure avec fuseau horaire (2020-12-31T23:59:59-06:00) | | **idfa** | optionnel | L'identifiant pour les annonceurs (IDFA) est un identifiant d'appareil aléatoire attribué par Apple à l'appareil d'un utilisateur. Applicable uniquement aux applications iOS | | **idfv** | optionnel | L'identifiant pour les fournisseurs (IDFV) est un code unique attribué à toutes les applications développées par un même développeur. Applicable uniquement aux applications iOS | | **advertising_id** | optionnel | L'Advertising ID est un code unique attribué par le système d'exploitation Android que les annonceurs peuvent utiliser pour identifier de manière unique l'appareil d'un utilisateur | | **amplitude_user_id** | optionnel | L'ID utilisateur d'Amplitude | | **amplitude_device_id** | optionnel | L'ID d'appareil d'Amplitude | | **mixpanel_user_id** | optionnel | L'ID utilisateur de Mixpanel | | **appmetrica_profile_id** | optionnel | L'ID de profil utilisateur d'AppMetrica | | **appmetrica_device_id** | optionnel | L'ID d'appareil d'AppMetrica | | **appsflyer_id** | optionnel | Identifiant unique d'AppsFlyer | | **adjust_device_id** | optionnel | L'ID d'appareil d'Adjust | | **facebook_anonymous_id** | optionnel | Identifiant unique généré par Facebook pour les utilisateurs qui interagissent avec votre application ou site web de manière anonyme, c'est-à-dire sans être connectés à Facebook | | **branch_id** | optionnel | Identifiant unique de Branch | | **attribution_source** | optionnel | La source d'intégration de l'attribution, par exemple, appsflyer | | **attribution_status** | optionnel | organic | | **attribution_channel** | optionnel | Le canal d'attribution qui a amené la transaction | | **attribution_campaign** | optionnel | La campagne d'attribution qui a amené la transaction | | **attribution_ad_group** | optionnel | Le groupe d'annonces d'attribution qui a amené la transaction | | **attribution_ad_set** | optionnel | L'ensemble d'annonces d'attribution qui a amené la transaction | | **attribution_creative** | optionnel | Les éléments visuels ou textuels spécifiques utilisés dans une publicité ou une campagne marketing, suivis pour déterminer leur efficacité à générer des actions souhaitées telles que des clics, des conversions ou des installations | | **custom_attributes** | optionnel | Définissez jusqu'à 30 attributs personnalisés sous forme de dictionnaire JSON en format clé-valeur : <ul><li>**key** : (chaîne) Le nom de l'attribut personnalisé</li><li> **value** : (chaîne, entier, flottant ou booléen) La valeur de l'attribut personnalisé.</li></ul><p> Format : `"{'string_value': 'some_value', 'float_value': 123.0, 'int_value': 456}"`.</p><p>Notez l'utilisation des guillemets doubles et simples dans le format. Gardez à l'esprit que les booléens et les entiers seront convertis en flottants.</p> | ### Champs requis \{#required-fields\} Il existe 2 groupes de champs requis pour chaque plateforme : **user_id** et les données identifiant les achats spécifiques à la plateforme concernée. Consultez le tableau ci-dessous pour les champs obligatoires par plateforme. | Plateforme | Champs requis | |--------|---------------| | iOS | <p>user_id</p><p>apple_original_transaction_id</p> | | Android | <p>user_id</p><p>google_product_id</p><p>google_purchase_token</p><p>google_is_subscription</p> | | Stripe | <p>user_id</p><p>stripe_token</p> | Sans ces champs, Adapty ne pourra pas récupérer les transactions. Pour des analyses de cohortes précises, veuillez indiquer `created_at`. Si cette valeur n'est pas fournie, nous considérerons que la date d'installation est identique à la date du premier achat. ### Importer des données dans Adapty \{#import-data-to-adapty\} Contactez-nous et partagez vos fichiers d'importation via [support@adapty.io](mailto:support@adapty.io) ou via le chat en ligne dans l'[Adapty Dashboard](https://app.adapty.io/overview). --- # File: migrate-integrations-to-adapty --- --- title: "Migrer les intégrations vers Adapty" description: "Basculez vos intégrations d'analytics et d'attribution d'une solution existante vers Adapty sans dupliquer les événements ni perturber vos campagnes." --- Migrer vers Adapty ne se limite pas à changer de SDK. Vos intégrations tierces d'analytics et d'attribution — des outils comme Amplitude et Adjust — nécessitent également un basculement coordonné. Bien mené, la transition génère peu d'événements en double ou manquants et ne perturbe pas vos campagnes. ## Mapper vos événements \{#map-your-events\} Les noms d'événements sont personnalisables dans la plupart des intégrations Adapty. Vous pouvez les configurer pour qu'ils correspondent aux noms déjà utilisés dans vos tableaux de bord et campagnes. Vos rapports d'analytics et de campagne continueront de fonctionner avec les mêmes noms d'événements après le basculement. Pour consulter la liste complète des événements disponibles dans Adapty, voir [Événements](events). Pour Adjust, l'intégration utilise des identifiants d'événements plutôt que des noms personnalisés. Transférez vos identifiants d'événements existants depuis le tableau de bord Adjust vers la configuration de l'intégration Adapty. Consultez le [guide d'intégration Adjust](adjust) pour plus de détails. ## Comment Adapty crée les événements d'intégration \{#how-adapty-creates-integration-events\} Pour envoyer un événement à une intégration, Adapty doit disposer d'un profil utilisateur. Un profil est créé de deux façons : - **Import historique** : le profil est créé lorsque vous [importez des données de transactions historiques](importing-historical-data-to-adapty) avant la mise en production du SDK. - **Interaction avec le SDK** : le profil est créé automatiquement lorsque l'utilisateur ouvre l'application avec le SDK Adapty pour la première fois. Adapty prend connaissance des achats effectués dans l'ancien système en temps réel. Mais il ne peut envoyer un événement d'intégration qu'une fois que le profil de l'acheteur existe. Ce profil est créé lorsque l'utilisateur ouvre l'application avec le SDK Adapty. Les utilisateurs qui ne mettent pas à jour vers la nouvelle version ne généreront pas d'événements d'intégration. ## Préparer avant le jour de la migration \{#prepare-before-migration-day\} ### Exclure les événements historiques \{#exclude-historical-events\} Activez **Exclude Historical Events** dans vos [paramètres d'intégration](configuration). Cela empêche l'envoi à l'intégration des événements antérieurs à la première session SDK Adapty de l'utilisateur. Ce paramètre est particulièrement important lors de l'[import historique](importing-historical-data-to-adapty), quand Adapty traite un grand volume de transactions passées en une seule fois. Sans lui, ces transactions génèreront un volume important d'événements dans votre outil d'analytics. ### Configurer l'intégration à l'avance \{#set-up-the-integration-in-advance\} Adapty vous permet de configurer et tester une intégration tout en la laissant désactivée. Vous pouvez définir les identifiants, le mapping d'événements et les filtres sans activer l'intégration jusqu'à ce que vous soyez prêt. La configuration est conservée lors de l'activation, rien n'est perdu en la laissant désactivée jusqu'au jour J. Pour trouver votre intégration, consultez [Intégrations d'attribution](attribution-integration), [Intégrations d'analytics](analytics-integration), [Intégrations de services de messagerie](messaging) ou [Intégrations Webhook et ETL](webhook-and-etl). ## Basculer le jour de la migration \{#switch-on-migration-day\} Désactivez l'intégration dans votre ancienne solution et activez-la dans Adapty simultanément. Faire tourner les deux en même temps produira des événements en double. Mettez en pause les grandes campagnes d'acquisition le jour de la migration. Cela réduit le risque d'erreurs d'optimisation de campagne causées par des événements dans la fenêtre de chevauchement. ## À quoi s'attendre \{#what-to-expect\} Quelques événements d'intégration manquants ou en double lors de la migration sont inévitables. Lorsque le basculement est effectué correctement, le nombre d'événements concernés est négligeable. La principale source de lacunes est le timing décrit ci-dessus : Adapty ne peut envoyer des événements d'intégration pour un achat qu'une fois que le profil de l'utilisateur existe. Les achats effectués dans l'ancien système ne génèrent pas d'événements d'intégration Adapty tant que l'acheteur n'ouvre pas l'application avec le SDK Adapty. ## Intégrations vs. notifications serveur à serveur \{#integrations-vs-server-to-server-notifications\} Adapty recommande d'utiliser les intégrations plutôt que de transmettre directement les notifications brutes serveur à serveur du store à vos outils d'analytics ou d'attribution. Avec les intégrations : - **Format unifié** : les événements de tous les stores — App Store, Google Play, Stripe — utilisent le même format d'événement. - **Données enrichies** : les événements incluent les données collectées par Adapty, comme l'état de l'abonnement et les attributs utilisateur. Les notifications brutes ne contiennent pas ces informations. --- # File: whats-new --- --- title: "Nouveautés" description: "Restez informé des dernières fonctionnalités et améliorations d'Adapty" --- Découvrez les dernières fonctionnalités, améliorations, mises à jour du SDK et enrichissements de la documentation pour optimiser la stratégie de monétisation de votre application. Cette page présente les sorties les plus importantes chaque mois. :::note Un avis sur les nouvelles fonctionnalités ? Nous serions ravis de vous lire ! Contactez-nous via le [tableau de retours produit](https://adapty.featurebase.app/en?b=69831ba5e82e7a3391632ec2). ::: ## Juillet 2026 \{#july-2026\} - **Monnaies virtuelles** : Définissez des monnaies intégrées comme des jetons, des pièces ou des gemmes, accordez et suivez un solde pour chaque utilisateur, et lisez ces soldes depuis votre serveur via l'API côté serveur. [En savoir plus](virtual-currencies) - **Agent IA dans Apple Ads Manager** : Interrogez un agent de chat consultatif sur vos performances Apple Ads et obtenez des réponses tirées de vos données de campagne, sans créer de rapports manuellement. [En savoir plus](ads-manager-ai-agent) - **Nouvelles automatisations dans Apple Ads Manager** : automatisez les modifications au niveau des campagnes et des groupes d'annonces avec deux nouveaux types de règles, en plus des automatisations de mots-clés et de termes de recherche existantes. [Règles de campagne](ads-manager-automations-campaign-rules) | [Règles de groupe d'annonces](ads-manager-automations-ad-group-rules) - **Profils dans Adapty Mail** : une vue par abonné qui affiche le parcours de chaque utilisateur, son état d'abonnement actuel et son statut de désabonnement au même endroit. [En savoir plus](mail-profiles) - **SDK v4 pour React Native, Flutter, Capacitor et Kotlin Multiplatform** : Les SDK v4 avec support des flows sont disponibles. React Native, Flutter et Capacitor ont atteint la disponibilité générale, et Kotlin Multiplatform v4 a été lancé — chacun avec son propre guide de migration. [React Native](migration-to-react-native-sdk-v4) | [Flutter](migration-to-flutter-sdk-v4) | [Capacitor](migration-to-capacitor-sdk-v4) | [Kotlin Multiplatform](migration-to-kmp-sdk-v4) - **Nouveaux champs webhook** : Les payloads webhook incluent désormais le prix original et la remise pour chaque transaction, ce qui vous permet de suivre les tarifs promotionnels et de lancement en aval. Ces champs sont disponibles uniquement dans les webhooks. [En savoir plus](webhook-event-types-and-fields) - **Prix barrés dans les flows** : Affichez un prix original barré à côté du prix remisé, avec un badge de remise, directement dans le Flow Builder. [En savoir plus](strikethrough-price) - **Galerie de templates de flows** : Démarrez un nouveau flow depuis un template conçu par des professionnels plutôt que d'une page blanche, puis personnalisez-le pour correspondre à votre application. [En savoir plus](paywall-builder-templates) - **Bouton d'installation des outils** : Chaque article de documentation dispose désormais d'un bouton **Install tools** dans l'en-tête. Il ouvre une fenêtre modale avec des commandes prêtes à copier pour installer le skill d'intégration du SDK Adapty dans Claude Code, Copilot CLI, Gemini CLI, Codex et d'autres assistants de développement IA. [En savoir plus](adapty-sdk-integration-skill) - **Nouvelle méthode d'installation du SDK Unity** : Vous pouvez désormais installer le SDK Unity via Swift Package Manager, avec des conseils de dépannage pour les problèmes courants. [En savoir plus](sdk-installation-unity) - **Conteneur footer dans le Flow Builder** : Un panneau bas fixe qui reste ancré pendant que le reste de l'écran défile — idéal pour les boutons CTA, les mentions légales et les liens. [En savoir plus](builder-containers#footer) - **Nouveaux tutoriels vidéo du Flow Builder** : une playlist YouTube en pleine expansion avec des guides pas à pas pour créer des flows, désormais intégrée dans les guides du Flow Builder. [En savoir plus](adapty-flow-builder) ## Juin 2026 \{#june-2026\} - **Les flows sont désormais disponibles sur Android** : Le builder visuel no-code pour les paywalls et les onboardings fonctionne maintenant sur Android SDK v4 et supérieur, ainsi que sur iOS. Les écrans s'affichent nativement, sans web views. [En savoir plus](adapty-flow-builder) - **Tests A/B CPP dans Apple Ads Manager** : Comparez des pages produit personnalisées entre elles directement dans Apple Ads. Sélectionnez 2 à 4 pages — y compris votre page par défaut actuelle — et Apple Ads répartit le trafic entre elles et indique laquelle convertit le mieux. [En savoir plus](ads-manager-cpp-ab-tests) - **Adapty Mail API** : Envoyez des profils utilisateurs et des transactions directement à Adapty Mail depuis votre serveur, sans faire transiter les données par le SDK. Utilisez-la pour alimenter une base d'abonnés, réutiliser des abonnés de vos autres applications, ou conserver votre backend comme source de vérité. [En savoir plus](mail-send-data-via-api) - **Afficher un paywall ciblé Apple Ads au premier lancement** : l'attribution Apple Ads arrive après l'activation du SDK, donc un paywall demandé trop tôt rate votre audience Apple Ads. Utilisez `AdaptyProfile.appliedAttributionSources` pour afficher le paywall ciblé Apple Ads dès que les données d'attribution sont disponibles. [iOS](ios-show-aa-targeted-paywall) | [React Native](react-native-show-aa-targeted-paywall) | [Capacitor](capacitor-show-aa-targeted-paywall) - **Sauvegarde automatique dans le Flow Builder** : Le Flow Builder enregistre maintenant votre progression automatiquement toutes les minutes, vous ne perdez plus votre travail non enregistré lorsque vous quittez la page. Vous pouvez toujours sauvegarder un brouillon manuellement avec **Cmd/Ctrl + S**. [En savoir plus](builder-save-publish) - **Nouveaux tutoriels vidéo pour le Flow Builder** : Deux nouvelles vidéos expliquent comment créer la navigation entre les écrans d'un flow et comment concevoir les états des éléments tels que sélectionné, actif et désactivé. [Navigation dans les flows](onboarding-navigation-branching) | [États des éléments](builder-element-states) - **Documentation en japonais et en vietnamien** : La documentation Adapty est désormais disponible en japonais (日本語) et en vietnamien (Tiếng Việt). Changez de langue via le sélecteur de langue dans la navigation en haut de page. ## Mai 2026 \{#may-2026\} - **Flows (Bêta)** : Créez des séquences d'écrans entières dans un éditeur visuel no-code — paywalls à écran unique, onboardings multi-étapes, et tout ce qui se trouve entre les deux, le tout dans un seul flow. Les écrans s'affichent nativement sans web views, et vous pouvez mettre à jour les textes, le design et la logique sans publier de nouvelle version de l'app. Supporte actuellement iOS, Android, React Native, Flutter et Capacitor SDK v4 et supérieur. [En savoir plus](adapty-flow-builder) - **Autopilot s'adapte désormais à vos résultats de test** : En agissant comme un gestionnaire de croissance IA, il met à jour le plan de croissance après chaque cycle terminé. La prochaine hypothèse tient compte des expériences réalisées, de celles qui ont été concluantes et des directions qui méritent encore d'être explorées — plutôt que de suivre une séquence fixe. [En savoir plus](autopilot-how-it-works#how-ai-growth-advisor-decides-what-to-recommend) - **ARPU d'activation dans Autopilot Market Insights** : Un nouveau graphique compare le revenu moyen par nouvelle installation de votre application à la moyenne de la catégorie. Combinez-le avec le tunnel de conversion — une conversion élevée associée à un faible ARPU d'activation peut indiquer des offres sous-tarifées. [En savoir plus](autopilot-analysis#activation-arpu) - **Analytics dans Adapty Mail** : Comparez les métriques de livraison et les revenus attribués aux e-mails pour chaque campagne en un seul affichage. Groupez, décomposez et filtrez par campagne, segment, variante A/B, message ou déclencheur, puis explorez n'importe quelle ligne en détail. [En savoir plus](mail-analytics) - **Profil de marque dans Adapty Mail** : Un profil centralisé qui pilote le contenu des e-mails, le ton, les visuels et le contenu des paywalls web. Adapty le construit à partir de la fiche de votre app sur les stores, de votre page de destination, de vos pages légales et de vos profils sociaux, et vous pouvez consulter ou affiner chaque section directement en ligne. [En savoir plus](mail-brand) - **Prédictions dans Adapty UA** : Revenu prédit, ROAS, profit publicitaire, ARPU et ARPPU pour chaque cohorte, afin de comparer vos campagnes avant qu'elles n'aient eu le temps de mûrir. Les prédictions sont construites à partir des données historiques de cohortes de votre application, mises à jour quotidiennement, et disponibles pour des périodes de cohorte allant de D0 à D360 ou un jour personnalisé. [En savoir plus](ua-predicted-metrics) - **Nouveaux champs dans l'export S3 personnalisé Adapty UA** : L'export S3 personnalisé inclut désormais `bundle_id`, `device_brand`, `device_model`, `os_version`, `app_version` et `sdk_version`. Segmentez et croisez les données d'attribution par appareil et version d'application en aval. [En savoir plus](ua-custom-s3) - **Audiences de placement dans la CLI** : Les commandes `adapty placements create` et `adapty placements update` acceptent désormais un flag `--audiences` — un tableau JSON d'entrées `{segment_ids, paywall_id, priority}` — afin de cibler différents paywalls vers différents segments depuis le terminal. La nouvelle commande `adapty paywalls placements` liste tous les placements qui utilisent un paywall donné, vous permettant de prévisualiser l'impact avant de le remplacer. [En savoir plus](developer-cli-reference#placements) - **Documentation en espagnol** : La documentation Adapty est désormais disponible en espagnol (Español). Changez de langue via le sélecteur de langue dans la navigation en haut de page. ## Avril 2026 \{#april-2026\} - **Adapty Mail** : campagnes e-mail générées par IA pour convertir les utilisateurs en période d'essai en abonnés payants. Créez, envoyez et attribuez des campagnes depuis votre projet Adapty — aucune plateforme e-mail tierce requise. [En savoir plus](adapty-mail) - **Diagnostic de Paywall avec Autopilot** : Découvrez ce qui doit être amélioré sur votre paywall avant de lancer un test. Importez une capture d'écran et Autopilot vous renvoie des recommandations basées sur les benchmarks des applications les plus performantes de votre catégorie, ainsi que des suggestions de mise en page et de contenu générées par l'IA. Les recommandations issues des benchmarks deviennent des rounds de test A/B dans votre plan de croissance. [En savoir plus](autopilot-analysis#paywall-analysis) - **Des indications plus claires pour chaque suggestion Autopilot** : Chaque hypothèse précise désormais pourquoi elle est importante (une explication basée sur les données montrant comment votre paywall s'écarte des tendances établies), ce qu'il faut modifier et comment configurer le test A/B, ainsi que les métriques à surveiller dans une nouvelle section « Comment interpréter vos résultats ». [En savoir plus](autopilot-execute-plan#step-1-view-the-hypothesis) - **Gardez votre plan de croissance Autopilot à jour** : actualisez l'analyse pour intégrer les dernières données du marché et les nouvelles suggestions, et consultez les suggestions précédentes dans l'historique des versions si les nouvelles ne correspondent pas. Les hypothèses sont regroupées dans les onglets Top priority, All, Pricing, Visual, Geo-pricing et Archived. [En savoir plus](autopilot-growth-plan) - **Distribution des revenus par durée dans Autopilot** : Voyez si vos revenus sont trop concentrés sur une seule durée d'abonnement. Un nouveau graphique Market Insights affiche la répartition de vos revenus par durée, aux côtés de la moyenne du secteur pour votre catégorie et votre pays. [En savoir plus](autopilot-analysis#revenue-distribution-by-duration) - **Prédictions LTV et revenus mises à jour** : Les prédictions de LTV et de revenus utilisent désormais les données de rétention de cohorte de votre propre application lorsque l'historique est suffisant, et des moyennes inter-applications sinon — ainsi, même les applications plus récentes obtiennent des prévisions exploitables dans les analyses et les tests A/B. [En savoir plus](predicted-ltv-and-revenue) - **Envoyer tous les événements dans Adapty UA** : Donnez à Meta et TikTok une image plus complète des conversions pour un modélisation d'audience plus précise. Adapty prend désormais en charge le transfert des installations et des transactions des utilisateurs organiques et non attribués vers votre pixel, pas seulement les utilisateurs associés à une campagne. [Meta](ua-facebook#send-all-events) | [TikTok](ua-tiktok#send-all-events) - **Documentation en russe et en turc** : La documentation Adapty est désormais disponible en russe (Русский) et en turc (Türkçe). Changez de langue à l'aide du sélecteur de langue dans la navigation supérieure. ## Mars 2026 \{#march-2026\} - **CLI développeur** : Gérez votre compte Adapty depuis le terminal sans ouvrir le Dashboard. Le CLI vous permet de créer des applications, de définir des niveaux d'accès, de configurer des produits, de créer des paywalls et de configurer des placements — le tout scriptable pour les environnements automatisés. Une [compétence Adapty CLI](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) est également disponible pour aider les assistants de codage IA à utiliser le CLI. [En savoir plus](developer-cli) - **Page Aperçu dans Apple Ads Manager** : Consultez toutes les métriques clés d'Apple Ads en un seul endroit, chacune accompagnée d'un graphique de tendance. Filtrez par application via le menu déroulant de l'en-tête, personnalisez les métriques affichées et ajustez le type de graphique et l'affichage des revenus. [En savoir plus](ads-manager-overview) - **Market Intelligence dans Apple Ads Manager** : Découvrez sur quels mots-clés vos concurrents diffusent des publicités dans plus de 50 pays, et ajoutez directement les mots-clés les plus performants à vos campagnes. [En savoir plus](ads-manager-market-intelligence) - **Automations complètes de mots-clés dans Apple Ads Manager** : Ajustez automatiquement les enchères, mettez en pause ou activez des mots-clés, et déplacez-les entre des groupes d'annonces selon des règles de performance que vous définissez. [En savoir plus](ads-manager-automations-keyword-rules) - **Historique des enchères dans Apple Ads Manager** : Consultez le journal complet des modifications pour l'enchère CPT de n'importe quel mot-clé — quand chaque modification a eu lieu, les valeurs précédente et nouvelle, et quelle règle d'automatisation l'a déclenchée. [En savoir plus](ads-manager-manage-keywords#bid-history) - **Rounds visuels dans Autopilot** : Les suggestions de design de paywall sont désormais des rounds à part entière dans votre plan de croissance — listés dans la barre latérale aux côtés des rounds de monétisation. Chaque round visuel inclut une maquette de design, une description des cas où le pattern fonctionne le mieux, et les métriques clés qu'il cible. [En savoir plus](autopilot-growth-plan) - **Ajoutez votre propre hypothèse à l'Autopilot** : Complétez votre plan de croissance avec des rounds personnalisés. Ajoutez un titre, une description, un type de round (monétisation ou visuel), des métriques cibles et — pour les rounds de monétisation — les produits concernés. [En savoir plus](autopilot-growth-plan#add-your-own-hypothesis) - **Réorganisez les rounds de l'Autopilot** : Faites glisser et réorganisez les étapes de votre plan de croissance pour lancer les expériences dans l'ordre qui correspond le mieux à votre stratégie. [En savoir plus](autopilot) - **La tarification géographique dans Autopilot** : testez des changements de prix spécifiques à chaque pays sous forme d'un nouveau type de round dans votre plan de croissance. Sur la base des données de Market Insights, Autopilot recommande d'augmenter, de diminuer ou de maintenir les prix dans chaque pays. Ajoutez une recommandation comme round de tarification géographique pour la lancer en test A/B — jusqu'à 5 peuvent être exécutés simultanément. [En savoir plus](autopilot-growth-plan#geo-pricing-hypotheses) - **Automatisations des termes de recherche dans Apple Ads Manager** : Promouvez automatiquement les termes de recherche gagnants en mots-clés à correspondance exacte et négativez-les à la source — sans téléchargement manuel de rapports. Les règles peuvent être créées à partir de modèles ou construites de zéro avec des conditions et des planifications personnalisées. [En savoir plus](ads-manager-automations-search-terms) - **Enchères Maximize Conversions dans Apple Ads Manager** : lors de la création de campagnes, vous pouvez désormais sélectionner Maximize Conversions comme stratégie d'enchères. L'algorithme d'Apple maximise les téléchargements dans les limites de votre budget, guidé par un CPA cible optionnel. [En savoir plus](ads-manager-create-campaign) - **Intégration FunnelFox dans Adapty UA** : une nouvelle intégration avec FunnelFox est désormais disponible dans Adapty UA. [FunnelFox](ua-funnelfox) - **Documentation en chinois** : la documentation Adapty est désormais disponible en chinois (中文). Changez de langue via le sélecteur de langue dans la navigation supérieure. ## Février 2026 \{#february-2026\} - **Tarification des produits par pays** : Définissez des prix différents par pays directement dans l'Adapty Dashboard — Adapty synchronise automatiquement les modifications vers l'App Store Connect et Google Play. Chaque mise à jour de tarification est consignée dans le journal d'audit, afin qu'aucune modification ne passe inaperçue. [En savoir plus](edit-product) - **Tarification des concurrents par pays dans Autopilot** : Comparez vos prix d'abonnement avec ceux de vos concurrents sur vos principaux marchés. [En savoir plus](autopilot-analysis#market-and-competitor-analysis) - **Contrôle de version des onboardings** : Suivez et gérez les versions de vos onboardings avec un historique complet. Consultez les modifications et effectuez des retours en arrière si nécessaire. - **Graphiques de conversion des paywalls dans les analytics** : Deux nouveaux graphiques de conversion — Paywall view → Trial et Paywall view → Paid — montrent comment vos paywalls convertissent les visiteurs en abonnés. [En savoir plus](analytics-conversion) - **Dupliquer des segments** : Copiez un segment existant avec tous ses filtres au lieu de reconstruire un segment similaire de zéro. Utile lorsque vous gérez plusieurs campagnes ou tests A/B avec des audiences qui se recoupent. [En savoir plus](segments#duplicate-segments) - **Notifications push dans l'application mobile Adapty** : Configurez des notifications push pour 14 types d'événements directement dans l'application iOS Adapty pour suivre l'activité des abonnements sans ouvrir le tableau de bord. [En savoir plus](push-notifications) - **Kotlin Multiplatform SDK 3.15** : Ajoute la prise en charge des onboardings, des paywalls web et des améliorations d'API. [En savoir plus](migration-to-kmp-315) - **Capacitor SDK 3.16** : Ajoute la prise en charge de Capacitor 8. Les projets utilisant Capacitor 7 doivent rester sur le SDK v3.15. [En savoir plus](migration-to-capacitor-316) - **Guides d'intégration du SDK assistés par LLM** : Guides pas à pas pour intégrer Adapty avec l'aide d'assistants de code IA. Chaque guide accompagne votre LLM tout au long de l'implémentation, de la configuration du tableau de bord aux achats. [iOS](adapty-cursor) | [Android](adapty-cursor-android) | [React Native](adapty-cursor-react-native) | [Flutter](adapty-cursor-flutter) | [Unity](adapty-cursor-unity) | [Kotlin Multiplatform](adapty-cursor-kmp) | [Capacitor](adapty-cursor-capacitor). Pour un flow entièrement automatisé en une seule commande, essayez le nouveau skill **adapty-sdk-integration** (bêta) : [iOS](adapty-sdk-integration-skill) | [Android](adapty-sdk-integration-skill-android) | [React Native](adapty-sdk-integration-skill-react-native) | [Flutter](adapty-sdk-integration-skill-flutter) | [Unity](adapty-sdk-integration-skill-unity) | [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) | [Capacitor](adapty-sdk-integration-skill-capacitor) ## Janvier 2026 \{#january-2026\} - **SDK Capacitor officiellement disponible** : Le SDK Capacitor est désormais prêt pour la production après des tests approfondis. Créez des applications d'abonnement pour iOS et Android avec Capacitor et une intégration Adapty complète. [En savoir plus](capacitor-sdk-overview) - **Autopilot pour les nouvelles applications** : L'analyse Autopilot est maintenant disponible même si votre application ne dispose pas encore d'un historique de transactions conséquent. Obtenez des recommandations d'optimisation des prix basées sur les données et élaborez votre plan de croissance dès le premier jour. [En savoir plus](autopilot) - **Opportunités de tarification mondiale dans Autopilot** : Identifiez le potentiel de revenus sur vos marchés les plus performants grâce à des recommandations de prix par pays. Autopilot analyse les taux de conversion et le pouvoir d'achat pour vos 5 prochains pays les plus importants, en fournissant des insights basés sur les données pour savoir s'il faut augmenter, diminuer ou maintenir les prix en fonction de l'Adapty Pricing Index. [En savoir plus](autopilot) - **Métriques de conversion pour la récupération de facturation** : De nouveaux graphiques analytiques permettent de suivre les revenus récupérés suite à des problèmes de facturation et des délais de grâce. Surveillez « Billing issue converted », « Billing issue converted revenue », « Grace period converted » et « Grace period converted revenue » pour mesurer vos efforts de rétention. - **Gestion directe des publicités dans Apple Ads Manager** : Créez et gérez vos campagnes Apple Ads directement dans Adapty, sans passer d'une plateforme à l'autre. [En savoir plus](ads-manager-manage-ads) - **Analyse avec Apple Ads Manager** : Accédez à des métriques de performance détaillées au niveau des annonces et à des données d'attribution dans Adapty. Consultez les performances des campagnes, les analyses de groupes d'annonces et les informations d'attribution dans un tableau de bord unifié. [En savoir plus](adapty-ads-manager-analytics) - **Graphiques d'attribution Apple Ads** : Combinez plusieurs métriques d'attribution dans des graphiques personnalisables pour analyser vos performances Apple Ads avec vos données d'abonnement. [En savoir plus](adapty-ads-manager-analytics#charts) - **Segments d'attribution Apple Ads** : Créez des segments d'utilisateurs basés sur les données d'attribution Apple Ads grâce à un processus simplifié en deux clics. Ciblez les utilisateurs par campagne, groupe d'annonces ou mot-clé pour des analyses et des expériences plus précises. [En savoir plus](ads-manager-create-segments) - **Nouvelle plateforme de documentation** : Le site de documentation a été migré vers une nouvelle plateforme, permettant des mises à jour de fonctionnalités plus rapides et une meilleure expérience utilisateur avec une recherche, une navigation et une organisation du contenu améliorées. ## Décembre 2025 \{#december-2025\} - **Documentation Apple Ads Manager** : Combinez les données de vos campagnes Apple Search Ads avec vos métriques de revenus dans un seul tableau de bord d'analyse. La nouvelle documentation couvre la création de campagnes, la gestion des groupes d'annonces et les moyens de suivre le retour sur investissement de vos dépenses publicitaires en parallèle des performances de vos abonnements. [En savoir plus](ads-manager) - **Paywalls web intégrés** : Affichez des paywalls web directement dans votre application via un navigateur intégré, pour une expérience fluide sans redirection externe. [iOS](ios-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Android](android-web-paywall#open-web-paywalls-in-an-in-app-browser) | [React Native](react-native-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Flutter](flutter-web-paywall#open-web-paywalls-in-an-in-app-browser) - **Segments dynamiques** : Créez des segments d'audience dynamiques qui se mettent à jour automatiquement en fonction de fenêtres temporelles glissantes. Par exemple, créez un segment pour « les utilisateurs qui ont installé l'application au cours des 7 derniers jours » qui se rafraîchit en continu pour toujours afficher vos nouveaux clients. [En savoir plus](segments#available-attributes) - **Guides de configuration des campagnes Meta et TikTok** : Documentation pas à pas pour créer et suivre des campagnes sur Meta (Facebook & Instagram) et TikTok, avec le suivi des conversions et l'intégration analytique. [Meta](meta-create-campaign) | [TikTok](tiktok-create-campaign) - **Guides de démarrage rapide pour l'implémentation manuelle des paywalls** : Intégrez les achats intégrés plus rapidement grâce à des guides pas à pas qui vous montrent comment intégrer le SDK Adapty dans votre UI de paywall personnalisée. [iOS](ios-implement-paywalls-manually) | [Android](android-implement-paywalls-manually) | [React Native](react-native-implement-paywalls-manually) | [Flutter](flutter-implement-paywalls-manually) | [Unity](unity-implement-paywalls-manually) | [Kotlin Multiplatform](kmp-quickstart-manual) | [Capacitor](capacitor-quickstart-manual) - **Navigateur intégré pour les liens d'onboarding** : Les liens externes dans les onboardings s'ouvrent désormais dans un navigateur intégré par défaut, ce qui maintient les utilisateurs dans votre application. Vous pouvez personnaliser ce comportement pour utiliser des navigateurs externes si nécessaire. [iOS](ios-present-onboardings#customize-how-links-open-in-onboardings) | [Android](android-present-onboardings#customize-how-links-open-in-onboardings) | [React Native](react-native-present-onboardings#customize-how-links-open-in-onboardings) - **Suggestions Autopilot améliorées** : Autopilot fournit désormais de meilleures recommandations d'optimisation des prix grâce à une analyse plus poussée de vos données d'abonnement. [Essayer Autopilot](autopilot) - **Mode sombre pour la documentation** : La documentation prend désormais en charge le mode sombre, avec détection automatique des préférences système ou bascule manuelle en haut à droite. --- # File: adapty-ecosystem --- --- title: "L'écosystème Adapty" description: "Adapty est une plateforme d'achats intégrés pour les applications mobiles. Découvrez ce que fait chaque produit et comment ils s'articulent." --- Adapty est une plateforme d'achats intégrés pour les applications mobiles, construite autour d'une seule mission : rendre les applications rentables. Elle vous donne tout ce qu'il faut pour développer vos revenus : acquérir des utilisateurs, les convertir, les fidéliser, et récupérer ceux qui partent. Une seule inscription vous donne accès à l'ensemble de l'écosystème Adapty dès le premier jour. Cliquez simplement sur le logo Adapty pour passer d'un produit à l'autre : - **Core** — traitez les achats sans toucher à StoreKit ou Google Play Billing, concevez des paywalls sans code, et suivez vos revenus en temps réel. Les autres produits s'appuient sur cette base. - **Adapty Ads Manager** — lancez et optimisez Apple Ads, mesurés par rapport aux revenus d'abonnement réels. - **Adapty Attribution** — identifiez quels canaux publicitaires génèrent vraiment des revenus, sans MMP. - **Adapty Mail** — convertissez les essais et récupérez les utilisateurs perdus grâce à des emails automatisés. Deux autres produits complètent ces quatre principaux : **FunnelFox** (funnels web-to-app et paiement hébergé) et **Adapty Finance** (avances sur vos futurs revenus d'abonnement). ## Comment les produits s'articulent \{#how-the-products-fit-together\} Chaque produit intervient à un moment différent du cycle de vie du client. Survolez n'importe quelle fonctionnalité liée pour une définition rapide, ou cliquez pour accéder à sa documentation. <ProductMap /> :::link Voir aussi : [Adapty est-il fait pour moi ?](is-adapty-right-for-me) ::: ## Conçu pour les workflows IA \{#built-for-ai-workflows\} Pilotez Adapty depuis votre agent de code IA — intégrez, gérez et consultez-le sans quitter votre éditeur. Dirigez l'agent vers la [compétence d'intégration SDK](adapty-sdk-integration-skill) pour votre plateforme et il réalise toute la configuration en une seule commande, ou suivez un [guide LLM étape par étape](adapty-cursor) pour examiner chaque étape vous-même. Votre outil IA peut accéder à la documentation de la manière qui lui convient. Copiez n'importe quelle page en Markdown avec le bouton **Copy for LLM**, ou pointez-le vers [`llms.txt`](https://adapty.io/docs/fr/llms.txt) — une carte de l'ensemble de la documentation. Pour un accès en direct, le serveur MCP [Context7](https://context7.com/adaptyteam/adapty-docs) expose les extraits de code les plus pertinents de la documentation dans Cursor, Claude Code et d'autres IDE. Consultez [Gérer Adapty avec l'IA](manage-adapty-with-ai) pour tous les points d'entrée. ## Core \{#core\} Core est la plateforme Adapty de base. Elle affiche vos paywalls, supervise les achats et mesure ce qui se passe ensuite. ### SDK et stores \{#sdks-and-stores\} Oubliez la plomberie de facturation. Adapty gère les achats, la validation des reçus et les renouvellements à votre place, et maintient le statut de chaque abonné à jour en temps réel — vous savez toujours qui a accès et pourquoi. Dans votre application, les [SDK](installation-of-adapty-sdks) gèrent le flux d'achat de bout en bout, ou [observent votre facturation existante](observer-vs-full-mode) si vous en avez déjà une. Ils couvrent 7 plateformes : [iOS](ios-sdk-overview), [Android](android-sdk-overview), [React Native](react-native-sdk-overview), [Flutter](flutter-sdk-overview), [Unity](unity-sdk-overview), [Kotlin Multiplatform](kmp-sdk-overview) et [Capacitor](capacitor-sdk-overview). Côté serveur, Adapty se connecte directement aux stores, de sorte que chaque renouvellement, remboursement et problème de facturation vous parvient en temps réel — même quand l'application est fermée. Pris en charge : [App Store](initial_ios), [Google Play](initial-android), [Stripe](stripe) et [Paddle](paddle), ainsi qu'une [intégration personnalisée](custom-store) pour tout autre fournisseur. ### Produits, offres et niveaux d'accès \{#products-offers-and-access-levels\} Adapty sépare ce que vous vendez de ce que les utilisateurs débloquent. Grâce à cette séparation, vous pouvez modifier les prix, échanger des produits ou lancer des offres sans publier une mise à jour de l'application. Trois éléments rendent cela possible : - **[Produits](product)** — un produit unifie vos SKU App Store, Play Store et web — abonnements, achats uniques ou consommables — pour que vous gériez le catalogue en un seul endroit. - **[Offres](offers)** — les leviers qui boostent la conversion : offres de lancement, offres promotionnelles et remises de reconquête. - **[Niveaux d'accès](access-level)** — vous permettent de découpler les privilèges d'accès des produits individuels. ### Flows et placements \{#flows-and-placements\} Créez les écrans qui génèrent des revenus — paywalls, onboardings, quiz — sans écrire de code. Les [flows](adapty-flow-builder) s'affichent sur l'appareil via le SDK, vous pouvez donc modifier les textes, le design et les prix à tout moment sans publier de nouvelle version. Partez d'un [modèle](paywall-builder-templates) ou d'un canevas vierge. Associez chaque flow à un [placement](placements), puis ciblez différentes [audiences](audience) construites à partir de [segments](segments). ### Profils et segments \{#profiles-and-segments\} Consultez n'importe quel abonné pour voir son historique complet — les [profils](profiles-crm) contiennent la chronologie des événements, l'état de l'abonnement, les revenus et les attributs personnalisés de chaque utilisateur. Découpez votre base d'utilisateurs en [segments](segments) selon n'importe quel attribut, puis personnalisez ce que les utilisateurs voient, filtrez les analyses et délimitez les tests A/B. Le [flux d'événements](event-feed) diffuse chaque événement d'abonnement au moment où il se produit. ### Tests A/B et AI Growth Advisor \{#ab-tests-and-ai-growth-advisor\} Augmentez vos revenus en trouvant ce qui convertit le mieux : - **[Tests A/B](ab-tests)** — testez différents prix, durées d'essai et designs de flow. - **[AI Growth Advisor](autopilot)** — vous dit exactement quoi tester en A/B ensuite. Compare votre paywall à plus de 20 000 applications avec abonnement et classe les expériences par gain de revenus attendu. Découvrez [comment ça fonctionne](autopilot-how-it-works). ### Analytics et Predictions \{#analytics-and-predictions\} [Analytics](analytics) transforme les données des stores, du SDK et de l'attribution en un tableau de bord de revenus en temps réel avec [des dizaines de métriques](metric-comparison-table) — bien plus que ce que l'App Store et Google Play affichent seuls. Approfondissez avec les analyses [par cohorte](analytics-cohorts), [par entonnoir](analytics-funnels), [de rétention](analytics-retention) et [de conversion](analytics-conversion). [Predictions](predicted-ltv-and-revenue) prévoit la LTV de chaque cohorte des mois à l'avance et désigne les [vainqueurs des tests A/B](predictions-in-ab-tests) avant qu'ils n'atteignent la significativité statistique. Des [rapports](reports) programmés arrivent directement dans votre boîte mail. ### CLI développeur \{#developer-cli\} L'[Adapty Developer CLI](developer-cli-quickstart) configure les produits, les placements et les niveaux d'accès depuis la ligne de commande — une alternative au tableau de bord pour les développeurs qui préfèrent le terminal. ## Adapty Ads Manager \{#adapty-ads-manager\} [Adapty Ads Manager](adapty-ads-manager) est une plateforme Apple Ads. Elle remplace la console Apple Ads native par une optimisation pilotée par l'IA, une attribution des revenus en temps réel et une veille concurrentielle. Comme Core suit déjà chaque installation, essai, abonnement et renouvellement, Ads Manager relie directement les dépenses publicitaires à la LTV. Aucun MMP requis. Fonctionnalités clés : - **[Campagnes et mots-clés](ads-manager)** — créez-les et gérez-les, ainsi que les groupes d'annonces et les enchères, depuis le tableau de bord Adapty. - **[Agent IA](ads-manager-ai-agent)** — requêtes et recommandations en langage naturel sur l'ensemble du funnel. - **[Market Intelligence](ads-manager-market-intelligence)** — stratégies de mots-clés concurrentes dans plus de 50 pays. - **[Tests A/B CPP](ads-manager-cpp-ab-tests)** — pages produit personnalisées comparées en face-à-face. - **[Automations](ads-manager-automations)** — vos campagnes s'optimisent d'elles-mêmes. Les enchères, mots-clés et termes de recherche s'ajustent automatiquement quand vos métriques franchissent les seuils définis. ## Adapty Attribution \{#adapty-attribution\} [Adapty Attribution](adapty-user-acquisition) associe les installations d'applications et les revenus d'abonnement aux campagnes publicitaires qui les ont générés. Il combine les dépenses des plateformes publicitaires, les clics sur les liens de suivi et les événements d'installation du SDK en vues ROAS, LTV et cohortes sur l'ensemble de vos canaux payants. Aucun MMP externe requis. Fonctionnalités clés : - **[Intégrations de plateformes publicitaires](ua-integrations)** — Meta Ads, TikTok for Business, FunnelFox et flux S3/GCS. - **[Liens de suivi](ua-tracking-links)** — générés dans Adapty, ajoutés à vos campagnes, et associés aux installations au premier lancement. - **[Deeplinks différés](ua-deferred-data)** — dirigez les nouveaux utilisateurs vers le bon contenu intégré au premier lancement, même s'ils ont cliqué avant d'installer. - **[Données d'attribution](ua-attribution-data)** — recevez la charge utile d'attribution dans votre application pour une logique personnalisée. ## Adapty Mail \{#adapty-mail\} [Adapty Mail](adapty-mail) transforme les données utilisateur en campagnes email générées par l'IA. Il construit un [profil de marque](mail-brand) à partir de la fiche store de votre application, de votre page de destination et de vos profils sociaux, puis génère une séquence email complète en quelques minutes. Les emails sont envoyés depuis votre domaine vérifié, et chaque achat est attribué à l'email qui l'a déclenché. Aucune plateforme email tierce requise. Fonctionnalités clés : - **[Campagnes](mail-email-campaigns)** — une séquence complète d'emails, générée en une seule passe. L'envoi démarre une fois que vous l'associez à un flow. - **[Flows](mail-flows)** — associez une campagne à un segment et à un déclencheur d'événement d'abonnement comme *jamais acheté* ou *problème de facturation*, pour qu'elle s'envoie automatiquement. - **[Paywall web](mail-checkout)** — pages de paiement personnalisées, une par destinataire, pour que les achats soient attribués à l'email correspondant. - **[Segments](mail-segments)** et **[profils](mail-profiles)** — ciblez les utilisateurs les plus susceptibles de convertir. Construisez un segment à partir de l'état d'achat, du pays ou des revenus, puis déclenchez une campagne ou un flow dessus. Les données viennent d'Adapty Core, limitées aux profils identifiés avec une adresse email. ## Connecter Adapty à votre stack existante \{#connect-adapty-to-your-existing-stack\} Les [intégrations tierces](configuration) transmettent les [événements](events) d'abonnement aux plateformes d'analyse, d'attribution et de messagerie que votre équipe utilise déjà : - **Analytics** : [Amplitude](amplitude), [Mixpanel](mixpanel), [PostHog](posthog), [Firebase / Google Analytics](firebase-and-google-analytics), [AppMetrica](appmetrica), [SplitMetrics Acquire](splitmetrics). - **Attribution** : [AppsFlyer](appsflyer), [Adjust](adjust), [Branch](branch), [Airbridge](airbridge), [Apple Ads](apple-search-ads), [Singular](singular), [Tenjin](tenjin), [Asapty](asapty), [Facebook Ads](facebook-ads). - **Messagerie** : [Braze](braze), [OneSignal](onesignal), [Pushwoosh](pushwoosh), [Slack](slack). - **Webhook et ETL** : [webhooks](webhook) personnalisés, [Amazon S3](s3-exports), [Google Cloud Storage](google-cloud-storage). ## L'écosystème élargi \{#the-wider-ecosystem\} Deux autres produits se connectent à vos données Adapty mais répondent à des besoins hors du cycle de vie principal. ### FunnelFox \{#funnelfox\} [FunnelFox](https://funnelfox.com/docs/integrations/subscription-management/adapty) est un constructeur de funnels web-to-app. Il crée des pages de destination et des quiz qui dirigent les visiteurs vers votre application. Son moteur de [facturation](https://funnelfox.com/docs/billing/integration-billing-funnelfox) collecte leurs paiements sur le web. Connectez FunnelFox à Adapty pour le suivi des abonnements et l'attribution des revenus. ### Adapty Finance \{#adapty-finance\} [Adapty Finance](https://adapty.io/blog/introducing-adapty-finance/) avance vos futurs revenus d'abonnement, pour que vous n'ayez pas à attendre les versements des stores. ## Prochaines étapes \{#next-steps\} - **[Adapty est-il fait pour moi ?](is-adapty-right-for-me)** — une visite de la plateforme centrée sur les cas d'usage. - **[Guide de démarrage rapide](quickstart)** — connectez un store, ajoutez des produits et intégrez le SDK. - **[Gérer Adapty avec l'IA](manage-adapty-with-ai)** — tous les points d'entrée pour utiliser Adapty avec un outil de code IA. --- # File: initial_ios --- --- title: "Intégration initiale avec l'App Store" description: "Démarrez avec Adapty sur iOS pour simplifier la configuration et la gestion des abonnements." --- Nous sommes ravis de vous accueillir sur Adapty ! Notre priorité est de vous aider à démarrer rapidement et à obtenir les meilleurs résultats possibles pour votre app. Ce guide est conçu pour vous aider à démarrer avec Adapty si votre app est disponible sur l'App Store. L'intégration d'Adapty dans votre application mobile consiste à établir des connexions entre votre app et Adapty, à la fois au niveau de l'App Store et au niveau du SDK. Bien que cela puisse paraître complexe à première vue, suivre l'onboarding dans Adapty Dashboard ou ces instructions vous permettra d'y parvenir en 30 minutes maximum. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/VJQbzoTCkqs?si=l7BPX9mIu6GVGZ0Z" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Guide d'intégration initiale \{#guide-for-the-initial-integration\} - [ ] Une fois votre compte Adapty créé et le nom ainsi que la catégorie de votre application mobile renseignés, nous configurons l'app pour vous dans notre plateforme Adapty. - [ ] [Générez une clé d'achat intégré](generate-in-app-purchase-key) dans App Store Connect - [ ] [Configurez l'intégration App Store](app-store-connection-configuration) dans Adapty Dashboard et App Store Connect - [ ] Si votre app propose des essais ou d'autres offres promotionnelles, [configurez les offres promotionnelles App Store](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) dans Adapty Dashboard. - [ ] [Activez les notifications serveur App Store](enable-app-store-server-notifications) dans App Store Connect - [ ] Installez les SDK Adapty pour les frameworks que vous utilisez : - [ ] [Installez le SDK Adapty pour iOS natif](sdk-installation-ios) - [ ] [Installez le SDK Adapty pour React Native](sdk-installation-reactnative) - [ ] [Installez le SDK Adapty pour Flutter](sdk-installation-flutter) - [ ] [Installez le SDK Adapty pour Unity](sdk-installation-unity) - [ ] [Installez le SDK Adapty pour Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [ ] Compilez votre application et exécutez-la en mode sandbox. Une fois l'intégration initiale terminée, vous [pouvez commencer à utiliser les fonctionnalités d'Adapty](product). Gardez à l'esprit que pour que les paywalls et les produits s'affichent dans votre application mobile et que les analytics fonctionnent, vous devez apporter des modifications au code de votre app. Plus précisément, vous devez au minimum [afficher les paywalls](ios-quickstart-paywalls) et, si vous utilisez des paywalls non créés avec le Paywall Builder, [gérer le processus d'achat](making-purchases) au sein de votre app. :::danger Vérifiez la checklist de mise en production avant de publier votre app Avant de publier votre application, assurez-vous de consulter attentivement la [checklist de mise en production](release-checklist). Cela vous garantit d'avoir accompli toutes les étapes nécessaires avant que votre app soit mise en ligne avec le SDK Adapty. ::: --- # File: generate-in-app-purchase-key --- --- title: "Générer une clé d'achat intégré dans App Store Connect" description: "Générez une clé d'achat intégré pour sécuriser les transactions." --- La **clé d'achat intégré** est une clé API spécialisée créée dans App Store Connect pour valider les achats en confirmant leur authenticité. :::note Pour générer des clés API pour l'App Store Server API, vous devez avoir le rôle Admin ou Titulaire du compte dans App Store Connect. Vous pouvez également consulter la procédure de génération de clés API dans la [documentation Apple Developer](https://developer.apple.com/documentation/appstoreserverapi/creating-api-keys-to-authorize-api-requests). ::: 1. Ouvrez **App Store Connect**. Accédez à la section [**Users and Access** → **Integrations** → **In-App Purchase**](https://appstoreconnect.apple.com/access/integrations/api/subs). 2. Cliquez ensuite sur le bouton d'ajout **(+)** à côté du titre **Active**. <img src="/assets/shared/img/6d737db-generate_in-app_key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Generate In-App Purchase Key** qui s'ouvre, saisissez le nom de la clé pour votre référence future. Il ne sera pas utilisé dans Adapty. 4. Cliquez sur le bouton **Generate**. Une fois la fenêtre **Generate in-App Purchase Key** fermée, la clé créée apparaîtra dans la liste **Active**. <img src="/assets/shared/img/fac066b-download_inapp_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Une fois votre clé API générée, cliquez sur le bouton **Download In-App Purchase Key** pour obtenir la clé sous forme de fichier. <img src="/assets/shared/img/d59faff-download_in-app_purchase_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Dans la fenêtre **Download in-App Purchase Key**, cliquez sur le bouton **Download**. Le fichier est enregistré sur votre ordinateur. Il est essentiel de conserver ce fichier en lieu sûr pour le téléverser ultérieurement sur l'Adapty Dashboard. Notez que le fichier généré ne peut être téléchargé qu'une seule fois ; veillez donc à le stocker en sécurité jusqu'au moment du téléversement. La clé .p8 générée depuis la section **In-App Purchase** sera utilisée lors de la [configuration de l'intégration initiale d'Adapty avec l'App Store](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file). **Étapes suivantes :** - [Configurer l'intégration App Store](app-store-connection-configuration) --- # File: app-store-connection-configuration --- --- title: "Configurer l'intégration App Store" description: "Configurez votre connexion App Store pour un suivi fluide des abonnements." --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/VJQbzoTCkqs?si=l7BPX9mIu6GVGZ0Z" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Cette section explique comment établir la connexion entre l'App Store et Adapty pour votre application iOS. C'est nécessaire pour que nous puissions afficher les analytics d'abonnements et valider les achats. Vous pouvez effectuer cette intégration lors de l'onboarding initial ou plus tard dans les **App Settings** de l'Adapty Dashboard. Même si vous avez configuré l'intégration de votre application mobile et d'Adapty lors de l'onboarding, vous pouvez modifier ces paramètres ultérieurement dans les **App settings**. :::danger Les modifications de configuration peuvent être effectuées sans risque pendant la phase Sandbox, tant que votre application mobile n'est pas encore en production avec le SDK Adapty installé. Des modifications après la mise en production peuvent casser le flux d'achat dans votre application. ::: ## Étape 1. Fournir le Bundle ID et l'Apple app ID \{#step-1-provide-bundle-id-and-apple-app-id\} Le **Bundle ID** et l'**Apple app ID** sont tous deux obligatoires. Le **Bundle ID** est l'identifiant unique de votre application dans l'App Store. Il active les fonctionnalités essentielles d'Adapty, comme le traitement des abonnements. L'**Apple app ID** est également requis pour [créer un nouveau produit et le pousser vers les stores](create-product#create-product-and-push-to-store) depuis la page **Products**. :::note Sans l'**Apple app ID**, l'option **Create a new product and push to stores** sur la page **Products** est désactivée, sans que le tableau de bord n'en indique la raison. ::: 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Fournir l'Issuer ID et le Key ID \{#step-2-provide-issuer-id-and-key-id\} L'**In-app purchase Issuer ID**, appelé **Issuer ID** dans App Store Connect, est un identifiant spécial qui identifie l'émetteur ayant créé le jeton d'authentification. L'**In-App Purchase Key ID**, appelé **Key ID** dans App Store Connect, est un identifiant unique associé à une clé cryptographique que vous avez générée dans la section [Générer une clé d'achat intégré dans App Store Connect](generate-in-app-purchase-key). 1. Ouvrez **App Store Connect**. Accédez à la section [**Users and Access** → **Integrations** → **In-App Purchase**](https://appstoreconnect.apple.com/access/integrations/api/subs). 2. Dans la liste **Active**, trouvez la clé que vous avez créée dans la section [Générer une clé d'achat intégré dans App Store Connect](generate-in-app-purchase-key). <img src="/assets/shared/img/19a2868-issuer_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Copiez l'**Issuer ID** et collez-le dans le champ **In-app purchase Issuer ID** de l'Adapty Dashboard. <img src="/assets/shared/img/c2b42e7-issuer_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Copiez le **Key ID** et collez-le dans le champ **In-app purchase Key ID** de l'Adapty Dashboard. ## Étape 3. Téléverser le fichier de clé d'achat intégré \{#step-3-upload-in-app-purchase-key-file\} Téléversez le fichier **In-App Purchase Key** que vous avez téléchargé dans la section [Générer une clé d'achat intégré dans App Store Connect](generate-in-app-purchase-key) <img src="/assets/shared/img/88cdfff-download_inapp_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> dans le champ **Private key (.p8 file)** de l'Adapty Dashboard. <img src="/assets/shared/img/253b840-in-app_file_upload.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Pour les essais et offres spéciales – configurer les offres promotionnelles \{#step-4-for-trials-and-special-offers--set-up-promotional-offers\} :::important Cette étape est obligatoire si votre application propose des [essais ou d'autres offres promotionnelles](offers). ::: 1. Copiez le même Key ID que celui utilisé à l'[Étape 2](#step-2-provide-issuer-id-and-key-id) dans le champ **Subscription key ID** de la section **App Store promotional offers**. 2. Téléversez le même fichier **In-App Purchase Key** que celui utilisé à l'[Étape 3](#step-3-upload-in-app-purchase-key-file) dans la zone **Subscription key (.p8 file)** de la section **App Store promotional offers**. <img src="/assets/shared/img/promo-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Saisir le secret partagé App Store \{#step-5-enter-app-store-shared-secret\} Le **secret partagé App Store**, aussi appelé App Store Connect Shared Secret, est une chaîne hexadécimale de 32 caractères utilisée pour la validation des reçus d'achats intégrés et d'abonnements. 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Faites défiler jusqu'à la sous-section **App-Specific Shared Secret**. <img src="/assets/shared/img/2bd112a-shared_secret_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::info Si la sous-section **App-Specific Shared Secret** est absente, assurez-vous d'avoir le rôle Account Holder ou Admin. Si vous avez le rôle Admin mais ne voyez toujours pas la sous-section **App-Specific Shared Secret**, demandez à l'Account Holder de l'application (la personne qui a créé l'application dans App Store Connect) de générer le secret partagé App Store pour l'application. Après cela, la sous-section sera également visible par les Admins. ::: 3. Cliquez sur le bouton **Manage**. <img src="/assets/shared/img/2d8b4c0-shared_secret_apple_copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la fenêtre **App-Specific Shared Secret** qui s'ouvre, copiez le **Shared Secret**. Si aucun secret partagé n'est visible, cliquez d'abord sur le bouton **Manage** ou **Generate** (selon celui qui est disponible), puis copiez le **Shared Secret**. 5. Collez le **Shared Secret** copié dans le champ **App Store shared secret** de l'Adapty Dashboard. <img src="/assets/shared/img/4f9624d-shared_secret.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Cliquez sur le bouton **Save** dans l'Adapty Dashboard pour confirmer les modifications. ## Étape 6. Ajouter une clé API App Store Connect \{#step-6-add-app-store-connect-api-key\} Générez une clé API App Store Connect et ajoutez-la à Adapty pour pouvoir [gérer vos produits dans l'App Store depuis le tableau de bord Adapty](create-product#create-product-and-push-to-store) : 1. Dans App Store Connect, accédez à [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) et cliquez sur **+**. <img src="/assets/shared/img/app-store-connect-api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la fenêtre **Generate API key**, saisissez un nom pour la clé et accordez-lui l'accès **Admin**. <img src="/assets/shared/img/generate-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Download** à côté de votre clé. Notez que vous ne pouvez la télécharger qu'une seule fois. <img src="/assets/shared/img/download-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans le tableau de bord Adapty, accédez à [**App settings > iOS SDK**](https://app.adapty.io/settings/ios-sdk) et cliquez sur **Connect API key**. <img src="/assets/shared/img/connect-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Remplissez les champs dans la fenêtre : - **Issuer ID** : copiez depuis [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Il se trouve au-dessus du tableau **API keys**. <img src="/assets/shared/img/issuer-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **Key ID** : copiez depuis [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Il se trouve dans le tableau **API keys**, à côté de votre clé. <img src="/assets/shared/img/key-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **API key** : téléversez le fichier de clé API que vous avez téléchargé depuis App Store Connect. <img src="/assets/shared/img/app-store-connect-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Cliquez sur **Connect**. **Étape suivante** - [Activer les notifications serveur App Store](enable-app-store-server-notifications) --- # File: enable-app-store-server-notifications --- --- title: "Activer les notifications serveur de l'App Store" description: "Activez les notifications serveur de l'App Store pour suivre les événements d'abonnement en temps réel." --- La configuration des notifications serveur de l'App Store est essentielle pour garantir la précision des données : elle vous permet de recevoir instantanément les mises à jour de l'App Store, notamment les informations sur les remboursements et d'autres événements. :::important Adapty iOS SDK 2.10.0 ou version ultérieure est requis pour la prise en charge complète des notifications serveur App Store V2. ::: 1. Copiez l'**URL pour les notifications serveur App Store** dans l'Adapty Dashboard. <img src="/assets/shared/img/2901185-app_server_notifications.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**, sous-section **App Store Server Notifications**. 3. Collez l'**URL pour les notifications serveur App Store** copiée dans les champs **Production Server URL** et **Sandbox Server URL**. <img src="/assets/shared/img/86fb3d2-app_server_notifications_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Transfert des événements bruts \{#raw-events-forwarding\} Il peut arriver que vous souhaitiez tout de même recevoir les événements S2S bruts d'Apple. Pour continuer à les recevoir tout en utilisant Adapty, ajoutez simplement votre point de terminaison dans le champ **URL for forwarding raw Apple events** et nous vous transmettrons les événements bruts tels quels depuis Apple. <img src="/assets/shared/img/e9f4bba-CleanShot_2021-03-16_at_19.30.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Étapes suivantes** Configurez le SDK Adapty pour : - [iOS](sdk-installation-ios) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: troubleshoot-app-store-integration --- --- title: "Résoudre les problèmes d'intégration App Store" description: "Résolvez les problèmes courants de configuration Apple App Store — accords en attente, délais de notifications serveur et incohérences de prix." --- Cet article couvre les problèmes courants d'intégration App Store. Chaque section liste les symptômes, la cause racine et la résolution. ## Les produits n'apparaissent pas \{#products-dont-appear\} Deux symptômes différents pointent vers la même cause racine : - La clé API App Store Connect est correctement configurée, mais Adapty ne parvient pas à récupérer les produits. - Les produits existent dans App Store Connect mais n'apparaissent pas dans Adapty, ou moins de produits que prévu s'affichent. Le SDK signale « Product Id not found » lors d'une tentative d'achat. La cause racine la plus fréquente est **des accords Apple non signés** — l'accord payant, les formulaires fiscaux ou bancaires en attente ou non signés. Lorsque des accords sont en attente, l'API App Store Connect renvoie silencieusement une erreur 403 sur les endpoints liés aux produits. Aucune erreur claire ne remonte à Adapty ; les produits sont silencieusement filtrés. Rendez-vous dans **App Store Connect → Agreements, Tax, and Banking** et signez tous les accords en attente. Ensuite, effectuez une nouvelle synchronisation dans **App settings → iOS SDK** d'Adapty. ## Les notifications serveur App Store affichent « Delayed » \{#app-store-server-notifications-show-delayed\} Dans App Store Connect, le statut des App Store Server Notifications peut afficher **Delayed**. Cela signifie qu'Apple prend du retard dans l'envoi des notifications d'événements d'abonnement — les renouvellements, annulations et problèmes de facturation sont mis en file d'attente et arrivent en retard. Les statistiques d'installation ne sont pas affectées. Adapty comptabilise les installations à partir du premier lancement de l'application, pas à partir des notifications côté serveur. Si les données de renouvellement ou d'annulation accusent un retard, le statut Delayed en est très probablement la cause. Ce statut se résorbe généralement automatiquement lorsqu'Apple traite la file d'attente. ## Les prix dans Adapty ne correspondent pas à l'App Store \{#prices-in-adapty-dont-match-app-store\} Le champ **price** sur la page d'édition du produit dans Adapty se comporte différemment selon la façon dont le produit a été ajouté. Si vous créez un produit dans Adapty et que vous le publiez sur le store depuis le tableau de bord, ce prix est utilisé comme prix initial sur le store. Si vous ajoutez un produit qui existe déjà sur le store, ce prix est un espace réservé. Les analyses, intégrations et SDK d'Adapty utilisent les prix réels récupérés depuis l'App Store, quoi qu'il en soit. Les modifications de prix sur l'App Store ne se synchronisent pas pour mettre à jour cet espace réservé, et il n'est pas possible de le modifier depuis le tableau de bord pour l'instant. ## L'export CSV des prix est vide \{#csv-price-export-is-empty\} Si votre export CSV des prix ne contient que les en-têtes de colonnes, c'est que votre clé API App Store Connect n'est pas entièrement configurée. Consultez [Étape 6 — Ajouter la clé API App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key). ## Impossible de publier de nouveaux produits sur l'App Store \{#cant-push-new-products-to-app-store\} Adapty peut publier de nouveaux produits sur App Store Connect lorsque vous les créez dans le tableau de bord. L'option de publication est bloquée si votre intégration App Store n'est pas entièrement configurée. Deux paramètres sont requis : - **Apple app ID** : configurez-le à l'[Étape 1 — Renseigner le Bundle ID et l'Apple app ID](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id). - **App Store Connect API key** : configurez-la à l'[Étape 6 — Ajouter la clé API App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key). --- # File: initial-android --- --- title: "Intégration initiale avec Google Play" description: "Démarrez avec Adapty sur Android et configurez votre application pour une gestion efficace des abonnements." --- Nous sommes ravis de vous accueillir chez Adapty ! Notre priorité est de vous aider à démarrer rapidement et à obtenir les meilleurs résultats possibles. Ce guide est conçu pour vous aider à démarrer avec Adapty si votre application est disponible dans le Google Play Store. L'intégration d'Adapty dans votre application mobile implique d'établir des connexions entre votre application et Adapty, aussi bien au niveau de Google Play qu'au niveau du SDK. Si le processus peut paraître long, suivre le guide intégré dans l'Adapty Dashboard ou les instructions ci-dessous le simplifiera grandement — cela prend en général moins d'une heure. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/7dN50n5bcLc?si=c2znttIb--4VcrRO" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Liste de contrôle pour l'intégration initiale \{#checklist-for-the-initial-integration\} - [ ] Une fois que vous avez créé un compte dans Adapty et renseigné le nom et la catégorie de votre application mobile, nous configurons l'application pour vous dans notre plateforme Adapty. - [ ] [Activer les API développeur](enabling-of-devepoler-api) dans Google Cloud Console - [ ] [Créer un compte de service](create-service-account) dans Google Cloud Console - [ ] [Accorder des autorisations au compte de service](grant-permissions-to-service-account) dans Google Play Console - [ ] [Générer le fichier de clé du compte de service](create-service-account-key-file) dans Google Cloud Console - [ ] [Configurer l'intégration Google Play](google-play-store-connection-configuration) dans l'Adapty Dashboard - [ ] [Activer les notifications en temps réel pour les développeurs (RTDN)](enable-real-time-developer-notifications-rtdn) dans Google Play Console - [ ] Installer et configurer les SDK Adapty (vous pouvez installer les SDK pour un ou plusieurs frameworks, selon vos besoins) - [ ] [Installer les SDK Adapty pour Android](sdk-installation-android) - [ ] [Installer les SDK Adapty pour React Native](sdk-installation-reactnative) - [ ] [Installer les SDK Adapty pour Flutter](sdk-installation-flutter) - [ ] [Installer les SDK Adapty pour Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [ ] [Installer les SDK Adapty pour Unity](sdk-installation-unity) - [ ] Compilez votre application et lancez-la. Une exécution en snapshot ou dans un environnement sandbox est suffisante. :::note Il faut au moins 24 heures pour que les modifications prennent effet, mais il existe une [astuce](https://stackoverflow.com/a/60691844). Dans [Google Play Console](https://play.google.com/apps/publish/), ouvrez n'importe quelle application et dans la section **Monetize**, allez dans **Products** -> **Subscriptions**/**In-app products**. Modifiez la description d'un produit quelconque et enregistrez les modifications. Tout devrait fonctionner désormais, vous pouvez annuler les modifications dans l'application. ::: Une fois l'intégration initiale terminée, vous [pouvez commencer à utiliser les fonctionnalités d'Adapty](product). Gardez à l'esprit que pour que les paywalls et les produits s'affichent dans votre application mobile et que les analyses fonctionnent, vous devez apporter des modifications au code de votre application. Plus précisément, vous devez au minimum [afficher les paywalls](android-quickstart-paywalls) et, si vous utilisez des paywalls non créés avec le Paywall Builder, [gérer le processus d'achat](android-making-purchases) dans votre application. :::danger Consultez la liste de contrôle avant de publier votre application Avant de publier votre application, assurez-vous de consulter attentivement la [liste de contrôle de publication](release-checklist). Cette liste vérifie que vous avez bien effectué toutes les étapes nécessaires et fournit des critères pour évaluer le succès de votre intégration. ::: --- # File: enabling-of-devepoler-api --- --- title: "Activer les API Développeur dans Google Play Console" description: "Activez l'API Développeur d'Adapty pour automatiser et simplifier la gestion des abonnements dans votre application." --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/7dN50n5bcLc?si=c2znttIb--4VcrRO" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Si votre application mobile est disponible sur le Play Store, activer les API Développeur est indispensable pour l'intégrer à Adapty. Cette étape garantit une communication fluide entre votre application et notre plateforme, facilitant les processus automatisés et l'analyse des données en temps réel pour optimiser votre modèle d'abonnement. Les API suivantes doivent être activées : - [Google Play Android Developer API](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com) - [Google Play Developer Reporting API](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com) - [Cloud Pub/Sub API](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com) Si votre application n'est pas distribuée via le Play Store, vous pouvez ignorer cette étape. En revanche, si vous vendez bien via le Play Store, vous pouvez la reporter pour l'instant, mais elle reste indispensable au bon fonctionnement d'Adapty. Une fois l'onboarding terminé, vous pourrez configurer les paramètres du store dans la section **App settings**. Voici comment activer les API Développeur dans Google Play Console : 1. Ouvrez la [Google Cloud Console](https://console.cloud.google.com/). 2. Dans le coin supérieur gauche de la fenêtre Google Cloud, sélectionnez le projet que vous souhaitez utiliser ou créez-en un nouveau. Assurez-vous d'utiliser le même projet Google Cloud jusqu'à ce que vous ayez téléversé le fichier de clé du compte de service dans Adapty. <img src="/assets/shared/img/fd66a11-google_cloud_project.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Ouvrez la page [**Google Play Android Developer API**](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com). <img src="/assets/shared/img/f754f72-google_play_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur le bouton **Enable** et attendez que le statut **Enabled** s'affiche. Cela signifie que l'API Google Android Developer est activée. <img src="/assets/shared/img/d47ed14-google_play_api_create_credentials.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Ouvrez la page [**Google Play Developer Reporting API**](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com). <img src="/assets/shared/img/966cf73-Google_play_developer_reporting_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Cliquez sur le bouton **Enable** et attendez que le statut **Enabled** s'affiche. <img src="/assets/shared/img/e776d77-Google_play_developer_reporting_api_enabled.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Ouvrez la page [**Cloud Pub/Sub API**](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com). <img src="/assets/shared/img/b13f609-enable_Cloud_Pub_Sub_API.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. Cliquez sur le bouton **Enable** et attendez que le statut **Enabled** s'affiche. <img src="/assets/shared/img/3f45602-Cloud_Pub_Sub_API_enabled.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Les API Développeur sont activées. Vous pouvez le vérifier sur la page [**APIs & Services**](https://console.cloud.google.com/apis/dashboard) de la Google Cloud Console. Faites défiler la page vers le bas et vérifiez que le tableau en bas de page contient bien les 3 API : - Google Play Android Developer API - Google Play Developer Reporting API - Cloud Pub/Sub API <img src="/assets/shared/img/b81d174-google_enabled_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Étape suivante** - [Créer un compte de service dans la Google Cloud Console](create-service-account) --- # File: create-service-account --- --- title: "Créer un compte de service dans la Google Cloud Console" description: "Apprenez à créer un compte de service pour un accès API sécurisé dans Adapty." --- Pour qu'Adapty puisse automatiser l'accès aux données, un compte de service est nécessaire dans la Google Play Console. 1. Ouvrez la section [**IAM & Admin** - > **Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) de la Google Cloud Console. Assurez-vous d'utiliser le bon projet. <img src="/assets/shared/img/17bbf45-google_cloud_create_service_account.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la fenêtre **Service accounts**, cliquez sur le bouton **Create service account**. <img src="/assets/shared/img/b93eec1-service_account_details.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la sous-section **Service account details** de la fenêtre **Create service account**, saisissez le **Service Account Name** de votre choix. Nous recommandons d'inclure « Adapty » dans le nom pour indiquer l'objectif de ce compte. Le **Service account ID** sera créé automatiquement. 4. Copiez l'adresse e-mail du compte de service et conservez-la pour une utilisation ultérieure. 5. Cliquez sur le bouton **Create and continue**. <img src="/assets/shared/img/e69d713-grant_access_to_project.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Dans la liste déroulante **Select a role** de la sous-section **Grant this service account access to project**, sélectionnez **Pub/Sub -> Pub/Sub Admin**. Ce rôle est requis pour activer les notifications en temps réel destinées aux développeurs. <img src="/assets/shared/img/976299c-service_account_role.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur le bouton **Add another role**. 8. Dans la nouvelle liste déroulante **Role**, sélectionnez **Monitoring -> Monitoring Viewer**. Ce rôle est requis pour permettre la surveillance de la file d'attente des notifications. 9. Cliquez sur le bouton **Continue**. <img src="/assets/shared/img/ffe8d82-grant_user_access.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 10. Cliquez sur le bouton **Done** sans apporter de modifications. La fenêtre **Service accounts** s'ouvre. **Étape suivante** - [Accorder des permissions au compte de service dans la Google Play Console](grant-permissions-to-service-account) --- # File: grant-permissions-to-service-account --- --- title: "Accorder des permissions au compte de service dans la Google Play Console" description: "Accordez des permissions aux comptes de service pour un accès API sécurisé et efficace." --- Accordez les permissions requises au compte de service qu'Adapty utilisera pour gérer les abonnements et valider les achats. 1. Ouvrez la page [**Users and permissions**](https://play.google.com/console/u/0/developers/8970033217728091060/users-and-permissions) dans la Google Play Console et cliquez sur le bouton **Invite new users**. <img src="/assets/shared/img/7b0e614-users_and_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sur la page **Invite user**, saisissez l'adresse e-mail des utilisateurs de service que vous avez créés. <img src="/assets/shared/img/3afd002-invite_user.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Passez à l'onglet **Account permissions**. <img src="/assets/shared/img/4e2717b-account_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Sélectionnez les permissions suivantes : - View app information and download bulk reports (read-only) - View financial data, orders, and cancellation survey responses - Manage orders and subscriptions - Manage store presence 5. Cliquez sur le bouton **Invite user**. 6. Dans la fenêtre **Send invite?**, cliquez sur le bouton **Send invite**. Le compte de service apparaîtra dans la liste des utilisateurs. **Prochaines étapes** - [Générer le fichier de clé du compte de service dans la Google Play Console](create-service-account-key-file) --- # File: create-service-account-key-file --- --- title: "Générer un fichier de clé de compte de service dans la Google Play Console" description: "Découvrez comment créer un fichier de clé de compte de service pour une intégration fluide avec Adapty." --- Pour relier votre application mobile sur le Play Store à Adapty, vous devez générer des fichiers de clé de compte de service spéciaux dans la Google Play Console et les téléverser dans Adapty. Ces fichiers sécurisent votre application et empêchent les accès non autorisés. :::warning Il faut généralement au moins 24 heures pour que votre nouveau compte de service devienne actif. Il existe cependant une [astuce](https://stackoverflow.com/a/60691844). Après avoir créé le compte de service dans la [Google Play Console](https://play.google.com/apps/publish/), ouvrez n'importe quelle application et accédez à **Monetize** -> **Products** -> **Subscriptions/In-app products**. Modifiez la description d'un produit et enregistrez les modifications. Le compte de service devrait s'activer immédiatement, et vous pourrez annuler les modifications ensuite. ::: 1. Ouvrez la section [**Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) dans la Google Play Console. Assurez-vous d'avoir sélectionné le bon projet. <img src="/assets/shared/img/c3156cb-action_manage_keys.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la fenêtre qui s'ouvre, cliquez sur **Add key** et choisissez **Create new key** dans le menu déroulant. <img src="/assets/shared/img/44b30ee-create_new_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Create private key for [Your_project_name]**, cliquez sur **Create**. Votre clé privée sera enregistrée sur votre ordinateur sous forme de fichier JSON. Vous pouvez la retrouver grâce au nom de fichier indiqué dans la fenêtre **Private key saved to your computer**. <img src="/assets/shared/img/e7b8101-cretae_private_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la fenêtre **Create private key for Your_project_name**, cliquez sur le bouton **Create**. Cette action enregistre votre clé privée sur votre ordinateur sous forme de fichier JSON. Vous pouvez utiliser le nom de fichier indiqué dans la fenêtre **Private key saved to your computer** pour le retrouver si besoin. <img src="/assets/shared/img/187ddc6-Private_key_saved.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous aurez besoin de ce fichier lors de la [configuration de l'intégration Google Play Store](google-play-store-connection-configuration). :::warning Il faut généralement au moins 24 heures pour que votre nouveau compte de service devienne actif. Il existe cependant une [astuce](https://stackoverflow.com/a/60691844). Après avoir créé le compte de service dans la [Google Play Console](https://play.google.com/apps/publish/), ouvrez n'importe quelle application et accédez à **Monetize** -> **Products** -> **Subscriptions/In-app products**. Modifiez la description d'un produit et enregistrez les modifications. Le compte de service devrait s'activer immédiatement, et vous pourrez annuler les modifications ensuite. ::: **Étape suivante** - [Configurer l'intégration Google Play Store](google-play-store-connection-configuration) --- # File: google-play-store-connection-configuration --- --- title: "Configurer l'intégration Google Play Store" description: "Configurez la connexion Google Play Store dans Adapty pour une gestion fluide des achats intégrés." --- Cette section décrit le processus d'intégration de votre application mobile distribuée via Google Play avec Adapty. Vous devrez saisir les données de configuration de votre application depuis le Play Store dans l'Adapty Dashboard. Cette étape est indispensable pour valider les achats et recevoir les mises à jour d'abonnement depuis le Play Store dans Adapty. Vous pouvez effectuer cette démarche lors de l'onboarding initial ou apporter des modifications ultérieurement dans les **App Settings** de l'Adapty Dashboard. :::danger La modification de la configuration n'est acceptable qu'avant la publication de votre application mobile intégrant les paywalls Adapty. Toute modification après la publication cassera l'intégration et les paywalls cesseront de s'afficher dans votre application. ::: ## Étape 1. Renseigner le nom de package \{#step-1-provide-package-name\} Le nom de package est l'identifiant unique de votre application dans le Google Play Store. Il est nécessaire au fonctionnement de base d'Adapty, notamment pour le traitement des abonnements. 1. Ouvrez la [Google Play Developer Console](https://play.google.com/console/u/0/developers). 2. Sélectionnez l'application dont vous avez besoin de l'identifiant. La fenêtre **Dashboard** s'ouvre. <img src="/assets/shared/img/7889edb-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Trouvez l'identifiant produit sous le nom de l'application et copiez-le. 4. Ouvrez les [**App settings**](https://app.adapty.io/settings/android-sdk) depuis le menu supérieur d'Adapty. <img src="/assets/shared/img/b00066c-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Dans l'onglet **Android SDK** de la fenêtre **App settings**, collez le **Package name** copié. ## Étape 2. Importer le fichier de clé de compte \{#step-2-upload-the-account-key-file\} 1. Importez le fichier de clé privée du compte de service au format JSON, que vous avez créé à l'étape [Créer un fichier de clé de compte de service](create-service-account), dans la zone **Service account key file**. <img src="/assets/shared/img/20fdba1-service_key_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> N'oubliez pas de cliquer sur le bouton **Save** pour confirmer les modifications. **Étape suivante** - [Activer les notifications en temps réel pour les développeurs (RTDN) dans la Google Play Console](enable-real-time-developer-notifications-rtdn) --- # File: enable-real-time-developer-notifications-rtdn --- --- title: "Activer les notifications développeur en temps réel (RTDN) dans Google Play Console" description: "Restez informé des événements critiques et maintenez la précision des données en activant les Real-time Developer Notifications (RTDN) dans la Google Play Console pour Adapty. Découvrez comment configurer les RTDN pour recevoir des mises à jour instantanées sur les remboursements et d'autres événements importants depuis le Play Store" --- La configuration des notifications développeur en temps réel (RTDN) est essentielle pour garantir la précision des données : elle vous permet de recevoir instantanément les mises à jour du Play Store, notamment les informations sur les remboursements et d'autres événements. ## Activer les notifications \{#enable-notifications\} 1. Assurez-vous que **Google Cloud Pub/Sub** est activé. Ouvrez [ce lien](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) et sélectionnez votre projet d'application. Si vous n'avez pas encore activé **Google Cloud Pub/Sub**, vous devez le faire ici. <img src="/assets/shared/img/pubsub.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Accédez à [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) depuis le menu supérieur d'Adapty et copiez le contenu du champ **Enable Pub/Sub API** situé à côté du titre **Google Play RTDN topic name**. <img src="/assets/shared/img/a72ff2d-copy_topic.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note Si le contenu du champ **Enable Pub/Sub API** est dans un format incorrect (le format correct commence par `projects/...`), consultez la section [Corriger le format incorrect du champ Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) pour obtenir de l'aide. ::: 3. Ouvrez la [Google Play Console](https://play.google.com/console/), choisissez votre application et accédez à **Monetize with Play** -> **Monetization setup**. Dans la section **Google Play Billing**, cochez la case **Enable real-time notifications**. 4. Collez le contenu du champ **Enable Pub/Sub API** que vous avez copié dans les **App Settings** d'Adapty dans le champ **Topic name**. 5. Cliquez sur **Save changes** dans la Google Play Console. <img src="/assets/shared/img/e55ba0e-paste_topic_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Tester les notifications \{#test-notifications\} Pour vérifier que vous êtes bien abonné aux notifications développeur en temps réel : 1. Enregistrez les modifications dans les paramètres de la Google Play Console. 2. Sous **Topic name** dans la Google Play Console, cliquez sur **Send test notification**. <img src="/assets/shared/img/rtdn-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Accédez à [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) dans Adapty. Si une notification de test a été envoyée, vous verrez son statut au-dessus du nom du sujet. <img src="/assets/shared/img/rtdn-adapty-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Corriger le format incorrect du champ Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\} Si le contenu du champ **Enable Pub/Sub API** est dans un format incorrect (le format correct commence par `projects/...`), suivez ces étapes pour diagnostiquer et résoudre le problème : ### 1. Vérifier l'activation de l'API et les autorisations \{#1-verify-api-enablement-and-permissions\} Assurez-vous soigneusement que toutes les API requises sont activées et que les autorisations sont correctement accordées au compte de service. Même si vous avez déjà effectué ces étapes, il est important de les refaire pour vous assurer qu'aucune sous-étape n'a été manquée. Répétez les étapes des sections suivantes : 1. [Activer les API développeur dans la Google Play Console](enabling-of-devepoler-api) 2. [Créer un compte de service dans la Google Cloud Console](create-service-account) 3. [Accorder des autorisations au compte de service dans la Google Play Console](grant-permissions-to-service-account) 4. [Générer le fichier de clé du compte de service dans la Google Play Console](create-service-account-key-file) 5. [Configurer l'intégration Google Play Store](google-play-store-connection-configuration) ### 2. Ajuster les politiques de domaine \{#2-adjust-domain-policies\} Modifiez les politiques **Domain restricted contacts** et **Domain restricted sharing** : 1. Ouvrez la [Google Cloud Console](https://console.cloud.google.com/) et sélectionnez le projet dans lequel vous avez créé le compte de service pour gérer votre application. 2. Dans la section **Quick Access**, choisissez **IAM & Admin**. <img src="/assets/shared/img/google-cloud-IAM-and-Admin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans le panneau de gauche, choisissez **Organization Policies**. 4. Recherchez la politique **Domain restricted contacts**. <img src="/assets/shared/img/google-cloud-policy-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur le bouton représentant des points de suspension dans la colonne **Actions** et choisissez **Edit policy**. 6. Dans la fenêtre de modification de la politique : 1. Sous **Policy source**, sélectionnez le bouton radio **Override parent's policy**. 2. Sous **Policy enforcement**, sélectionnez le bouton radio **Replace**. 3. Sous **Rules**, cliquez sur le bouton **ADD A RULE**. <img src="/assets/shared/img/google-cloud-edit-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Sous **New rule** -> **Policy values**, choisissez **Allow All**. <img src="/assets/shared/img/google-cloud-allow-all-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **SET POLICY**. 7. Répétez les étapes 4 à 6 pour la politique **Domain restricted sharing**. Ensuite, recréez le contenu du champ **Enable Pub/Sub API** situé à côté du titre **Google Play RTDN topic name**. Le champ aura désormais le format correct. Veillez à remettre **Policy source** sur **Inherit parent's policy** pour les politiques modifiées une fois que vous avez activé avec succès les Real-time Developer Notifications (RTDN). ## Transfert des événements bruts \{#raw-events-forwarding\} Il peut arriver que vous souhaitiez tout de même recevoir les événements S2S bruts de Google. Pour continuer à les recevoir tout en utilisant Adapty, ajoutez simplement votre endpoint dans le champ **URL for forwarding raw Google events** et nous vous transmettrons les événements bruts tels quels depuis Google. <img src="/assets/shared/img/e388892-001774-September-22-GhkjOFbT.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- **Prochaine étape** Configurez le SDK Adapty pour : - [Android](sdk-installation-android) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: payment-integrations --- --- title: "Web" description: "Intégrez les systèmes de paiement web avec Adapty pour une gestion fluide des abonnements sur toutes les plateformes." --- Adapty prend en charge l'intégration avec les systèmes de paiement web pour vous aider à gérer les abonnements et les achats depuis votre application mobile et votre site web en un seul endroit. Cela vous permet de : - Centraliser les données d'abonnement des achats intégrés et des achats effectués sur votre site web dans un seul système - Accorder l'accès aux fonctionnalités payantes de votre application mobile aux utilisateurs ayant acheté sur votre site web - Consulter les analyses et les données d'abonnement de tous les canaux de vente dans un seul tableau de bord Intégrations disponibles : - [Stripe](stripe) - [Paddle](paddle) --- # File: stripe --- --- title: "Intégration initiale avec Stripe" description: "Intégrez Stripe avec Adapty pour un traitement fluide des paiements d'abonnements." --- Adapty prend en charge les flows web2app en suivant les paiements et abonnements web effectués via [Stripe](https://stripe.com/). Cette intégration couvre les achats initiés depuis le web (Stripe Checkout, pages de paiement hébergées ou flows web personnalisés) et les synchronise avec l'accès aux applications mobiles et les analyses. Elle est utile dans les cas suivants : - Accorder automatiquement l'accès aux fonctionnalités payantes aux utilisateurs qui ont acheté sur le web mais ont ensuite installé l'application et s'y sont connectés - Centraliser toutes les analyses d'abonnements dans un seul Adapty Dashboard (cohortes, prédictions et le reste de notre boîte à outils d'analyses) Même si les achats sur le web gagnent en popularité pour les applications, l'Apple App Store n'autorise un système différent des achats intégrés pour les biens numériques qu'aux États-Unis. Assurez-vous de ne pas promouvoir vos abonnements web dans votre application pour les autres pays, sous peine de voir votre application rejetée ou bannie. Les étapes ci-dessous expliquent comment configurer l'intégration Stripe. :::important Cette intégration est axée sur le suivi et la synchronisation des achats Stripe sur le web. Si vous souhaitez envoyer des utilisateurs depuis l'application vers un paiement web, consultez [Web paywalls](web-paywall). ::: ## 1\. Connecter Stripe à Adapty \{#1-connect-stripe-to-adapty\} Cette intégration repose principalement sur la récupération par Adapty des données d'abonnement depuis Stripe via le webhook. Vous devez donc connecter votre compte Adapty à votre compte Stripe en fournissant des clés API et en utilisant l'URL webhook d'Adapty dans Stripe. Pour automatiser la configuration de votre webhook, installez l'application Adapty dans Stripe : :::note Les étapes ci-dessous sont identiques pour les modes Production et Test de Stripe, mais vous devrez utiliser des clés API différentes pour chacun. ::: 0. Déterminez si vous connectez Stripe en mode test ou en mode live. Si vous commencez en mode test, vous devrez répéter les étapes ci-dessous pour le mode live. 1. Rendez-vous sur le [Stripe App Marketplace](https://marketplace.stripe.com/apps/adapty) et installez l'application Adapty. Notez que le mode sandbox ne prend pas en charge l'installation d'applications. Vous ne pouvez le faire qu'en mode production ou test. <img src="/assets/shared/img/stripe1.png"/> 2. Accordez les autorisations requises à l'application. Cela permettra à Adapty d'accéder aux données et à l'historique des abonnements. Cliquez ensuite sur **Continue to app settings** pour continuer. En bas de la fenêtre contextuelle des autorisations, vous pouvez choisir d'installer l'application en mode live ou test. <img src="/assets/shared/img/stripe2.png"/> 3. Dans la fenêtre contextuelle, générez une nouvelle clé restreinte. Vous devrez vérifier votre identité par e-mail, Touch ID ou clé de sécurité. Une fois la clé générée, vous ne pourrez plus la consulter ; conservez-la donc en sécurité dans un gestionnaire de mots de passe ou un coffre-fort. <img src="/assets/shared/img/stripe4.png"/> 4. Copiez la clé générée depuis la fenêtre contextuelle et rendez-vous dans **App Settings → Stripe** d'Adapty [App Settings → Stripe](https://app.adapty.io/settings/stripe). Collez la clé dans la section **Stripe App Restricted API Key** selon votre mode. Notez que vous devez générer des clés différentes pour les modes test et live. <img src="/assets/shared/img/Stripe3.png"/> C'est tout ! Créez maintenant vos produits sur Stripe et ajoutez-les à Adapty. <Details> <summary>Flux d'installation obsolète</summary> 1. Rendez-vous dans [Developers → API Keys](https://dashboard.stripe.com/apikeys) dans Stripe : <img src="/assets/shared/img/6549602-CleanShot_2023-12-06_at_17.29.122x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le bouton **Reveal live (test) key button** à côté du titre **Secret key**, copiez-la et rendez-vous dans [App Settings → Stripe](https://app.adapty.io/settings/stripe) d'Adapty. Collez la clé ici : <img src="/assets/shared/img/2989508-CleanShot_2023-12-07_at_14.59.122x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Copiez ensuite l'URL du webhook en bas de la même page dans Adapty. Rendez-vous dans [**Developers** → **Webhooks**](https://dashboard.stripe.com/webhooks) dans Stripe et cliquez sur le bouton **Add endpoint** : <img src="/assets/shared/img/e7149f5-CleanShot_2023-12-07_at_17.31.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Collez l'URL du webhook d'Adapty dans le champ **Endpoint URL**. Choisissez ensuite **Latest API version** dans le champ **Version** du webhook. Puis sélectionnez les événements suivants : - charge.refunded - customer.subscription.created - customer.subscription.deleted - customer.subscription.paused - customer.subscription.resumed - customer.subscription.updated - invoice.created - invoice.updated - payment_intent.succeeded <img src="/assets/shared/img/cbc5404-CleanShot_2023-12-07_at_17.36.232x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur « Add endpoint », puis sur « Reveal » sous « Signing secret ». C'est la clé utilisée pour décoder les données du webhook côté Adapty ; copiez-la après l'avoir affichée : <img src="/assets/shared/img/0460cbb-CleanShot_2023-12-07_at_17.52.582x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Enfin, collez cette clé dans App Settings → Stripe d'Adapty, sous « Stripe Webhook Secret » : <img src="/assets/shared/img/055db20-CleanShot_2023-12-07_at_14.56.212x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Details> ## 2\. Créer des produits sur Stripe \{#2-create-products-on-stripe\} :::note Si vous configurez cela en mode test, assurez-vous que Stripe est également en mode Test avant de continuer. ::: Rendez-vous dans le [catalogue de produits](https://dashboard.stripe.com/products?active=true) de Stripe et créez les produits que vous souhaitez vendre ainsi que leurs plans tarifaires. Notez que Stripe permet d'avoir plusieurs plans tarifaires par produit, ce qui est utile pour adapter votre offre sans avoir à créer des produits supplémentaires. <img src="/assets/shared/img/b202e2e-CleanShot_2023-12-06_at_15.06.262x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning Adapty ne prend en charge que les tarifications **Flat rate** (9,99 $/mois) ou **Package pricing** (9,99 $/10 unités), car elles fonctionnent de manière similaire aux stores d'applications. Les options **Tiered pricing**, **Usage-based fee** et **Customer chooses price** ne sont pas prises en charge. ::: ## 3\. Ajouter des produits Stripe à Adapty \{#3-add-stripe-products-to-adapty\} :::warning Les produits sont obligatoires ! Assurez-vous de créer vos produits Stripe dans l'Adapty Dashboard. Adapty ne suit les événements que pour les transactions liées à ces produits, alors ne sautez pas cette étape — sinon, aucun événement de transaction ne sera créé. ::: Nous traitons Stripe de la même façon que l'App Store et Google Play : c'est simplement un autre store où vous vendez vos produits numériques. La configuration est donc similaire : ajoutez simplement les produits Stripe (à savoir leur `product_id` et `price_id`) dans la section Produits d'Adapty : <img src="/assets/shared/img/stripe-add-product.webp" style={{ border: 'none', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Les ID de produits dans Stripe ressemblent à `prod_...` et les ID de prix à `price_...`. Ils sont faciles à trouver pour chaque produit dans le [catalogue de produits](https://dashboard.stripe.com/products?active=true) Stripe, en ouvrant n'importe quel produit : <img src="/assets/shared/img/14a72d7-CleanShot_2023-12-06_at_17.32.512x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois tous les produits nécessaires ajoutés, l'étape suivante consiste à indiquer à Stripe quel utilisateur effectue l'achat, afin qu'Adapty puisse l'identifier ! ## 4\. Enrichir les achats web avec votre ID utilisateur \{#4-enrich-purchases-made-on-the-web-with-your-user-id\} Adapty s'appuie sur les webhooks de Stripe comme seule source d'information pour fournir et mettre à jour les niveaux d'accès des utilisateurs. Vous devez donc fournir des informations supplémentaires de votre côté lors de l'utilisation de Stripe pour que cette intégration fonctionne correctement. Pour que les niveaux d'accès soient cohérents sur toutes les plateformes (web ou mobile), vous devez vous assurer qu'il existe un ID utilisateur unique sur lequel Adapty peut s'appuyer depuis les webhooks. Il peut s'agir de l'adresse e-mail, du numéro de téléphone ou de tout autre ID issu du système d'authentification que vous utilisez. Déterminez l'ID que vous souhaitez utiliser pour identifier vos utilisateurs. Ensuite, accédez à la partie de votre code qui initialise le paiement via Stripe — et ajoutez cet ID utilisateur à l'objet `metadata` de l'objet [Stripe Subscription](https://docs.stripe.com/api/subscriptions/object#subscription_object-metadata) (`sub_...`) ou [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-metadata) (`ses_...`) en tant que `customer_user_id` comme suit : ```json showLineNumbers title="Stripe Metadata contents" {'customer_user_id': "YOUR_USER_ID"} ``` Cette simple addition est la seule chose que vous devez faire dans votre code. Ensuite, Adapty analysera tous les webhooks reçus de Stripe, en extraira ce `metadata` et associera correctement les abonnements à vos clients. :::warning L'ID utilisateur est obligatoire Sans lui, nous n'avons aucun moyen d'identifier cet utilisateur et de lui accorder le niveau d'accès sur mobile. Si vous ne fournissez pas `customer_user_id` dans le `metadata`, vous aurez la possibilité de demander à Adapty de chercher `customer_user_id` ailleurs : soit dans le champ `email` de l'objet Customer de Stripe, soit dans `client_reference_id` de la Session Stripe. Pour en savoir plus sur la configuration du comportement de création de profil, consultez la section [ci-dessous](stripe#profile-creation-behavior). ::: :::note Un Customer Stripe est également obligatoire Si vous utilisez des Checkout Sessions, [assurez-vous de créer un Customer Stripe](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer_creation) en définissant `customer_creation` sur `always`. ::: ## 5\. Donner accès aux utilisateurs sur mobile \{#5-provide-access-to-users-on-the-mobile\} Pour vous assurer que vos utilisateurs mobiles venant du web peuvent accéder aux fonctionnalités payantes, appelez simplement `Adapty.activate()` ou `Adapty.identify()` avec le même `customer_user_id` que celui fourni à l'étape précédente (voir <InlineTooltip tooltip="Identification des utilisateurs">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip> pour plus d'informations). ## 6\. Tester votre intégration \{#6-test-your-integration\} Assurez-vous d'avoir effectué les étapes ci-dessus pour le Sandbox ainsi que pour la Production. Les transactions effectuées depuis le mode Test de Stripe seront considérées comme Sandbox dans Adapty. :::info C'est tout ! Vos utilisateurs peuvent désormais effectuer des achats sur le web et accéder aux fonctionnalités payantes dans votre application. Et vous pouvez également consulter toutes vos analyses d'abonnements en un seul endroit. ::: ## Comportement de création de profil \{#profile-creation-behavior\} Adapty doit lier un achat à un [profil client](profiles-crm) pour qu'il soit disponible sur mobile — par défaut, il crée donc des profils à la réception des webhooks de Stripe. Vous pouvez choisir ce qui sera utilisé comme ID utilisateur dans Adapty : 1. **Par défaut et recommandé :** le `customer_user_id` que vous avez fourni dans les métadonnées à [l'étape 4 ci-dessus](stripe#4-enrich-purchases-made-on-the-web-with-your-user-id) 2. `email` dans l'objet Customer de Stripe (voir [la documentation Stripe](https://docs.stripe.com/api/customers/object#customer_object-email)) 3. `client_reference_id` dans l'objet Session de Stripe (voir [la documentation Stripe](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-client_reference_id)) Vous pouvez configurer l'ID à utiliser dans [App Settings → Stripe](https://app.adapty.io/settings/stripe). :::warning **Remarque :** si une transaction particulière de Stripe ne contient pas l'ID spécifié, nous ne créerons pas de profil du tout. Cette transaction restera anonyme jusqu'à ce qu'un profil la prenne en charge (par exemple, si vous utilisez [S2S validate](api-adapty/operations/validateStripePurchase) par la suite et nous informez manuellement de cette transaction). Elle apparaîtra dans Analytics mais pas dans les sections qui reposent sur le comptage des profils (LTV, Cohortes, Conversions, etc.) et vous ne pourrez pas la voir dans le fil d'événements. ::: Vous avez également une quatrième option : ne pas créer de profils du tout, mais cela n'est pas recommandé en raison des limitations analytiques mentionnées ci-dessus. ## Limitations actuelles \{#current-limitations\} ### Mises à niveau, rétrogradations et proratisation \{#upgrading-downgrading-and-proration\} Les changements d'abonnement tels que les mises à niveau ou les rétrogradations peuvent entraîner des frais au prorata. Adapty ne tiendra pas compte de ces frais dans les calculs de revenus. Il est préférable de désactiver ces options manuellement via le tableau de bord Stripe. Vous pouvez également les désactiver en définissant la valeur de l'attribut `proration_behaviour` sur `none` via l'API Stripe. ### Annulations \{#cancellations\} Stripe propose deux options d'annulation d'abonnement : 1. Annulation immédiate : l'abonnement est annulé immédiatement, avec ou sans option de proratisation 2. Annulation en fin de période : l'abonnement est annulé à la fin de la période de facturation en cours (similaire aux abonnements intégrés sur les stores d'applications). Adapty prend en charge les deux options, mais le calcul des revenus pour l'annulation immédiate ne tiendra pas compte de la proratisation. ### Problèmes de facturation et délai de grâce \{#billing-issues-and-grace-period\} Lorsqu'un client rencontre un problème de paiement, Adapty génère un événement de problème de facturation et l'accès est révoqué. Nous ne prenons pas encore en charge le délai de grâce de Stripe — cela fera partie des prochaines versions. ### Remboursements \{#refunds\} Adapty ne suit que les remboursements complets. Les remboursements au prorata ou partiels ne sont actuellement pas pris en charge. ### Unicité des ID de transaction \{#transaction-id-uniqueness\} Adapty fait correspondre les profils et les transactions à l'aide de `store_transaction_id` et `store_original_transaction_id`. Ces valeurs **doivent être uniques** entre les environnements Test et Production. #### Pourquoi c'est important \{#why-this-matters\} Si le même ID de transaction existe dans les deux environnements, Adapty les traite comme une seule transaction, ce qui entraîne : - Des niveaux d'accès et des ID de produits de test hérités par les achats de production - Des ID de produits et des environnements incorrects dans les réponses API - Des perturbations dans la liaison des profils et les événements d'abonnement #### Comment garantir l'unicité \{#how-to-ensure-uniqueness\} Les ID de factures Stripe peuvent se chevaucher entre les environnements Test et Live. Pour éviter les collisions entre environnements, choisissez l'une des approches suivantes. #### Option 1 : numérotation au niveau du compte avec préfixes d'environnement \{#option-1-account-level-numbering-with-environment-prefixes\} Configurez des préfixes séparément pour chaque environnement : 1. Dans le tableau de bord Stripe, passez en mode Test. 2. Rendez-vous dans [Settings → Billing → Invoices](https://dashboard.stripe.com/settings/account/?support_details=true). 3. Définissez **Invoice numbering** sur **Sequentially across your account**. 4. Définissez **Invoice prefix** sur TEST- (ou tout autre préfixe spécifique à l'environnement de test). 5. Passez en mode Live et répétez les étapes 2 à 4, en utilisant LIVE- (ou tout autre préfixe spécifique à l'environnement live) comme préfixe. #### Option 2 : numérotation au niveau du client \{#option-2-customer-level-numbering\} Définissez **Invoice numbering** dans [**Stripe settings** -> **Billing** -> **Invoices** tab](https://dashboard.stripe.com/settings/account/?support_details=true) sur **Sequentially for each customer (customer-level)**. Même avec la configuration ci-dessus, si vous supprimez une facture, Stripe peut réutiliser cet ID pour les nouvelles factures du même client. Il est donc préférable d'éviter de supprimer des factures autant que possible. ### Achats uniques via Stripe Checkout ou Payment Links \{#one-time-purchases-via-stripe-checkout-or-payment-links\} Adapty ne suit les achats uniques (non-abonnements) effectués via Stripe Checkout (`mode=payment`) ou Payment Links que si Stripe génère une facture pour l'achat. Par défaut, Stripe ne crée pas de facture pour les achats Checkout uniques. Dans ce cas, `payment_intent.succeeded` arrive sans données de facture, ce qui n'est pas suffisant pour qu'Adapty enregistre la transaction. Pour suivre les achats Checkout uniques dans Adapty, [activez la création de facture](https://docs.stripe.com/payments/checkout/receipts?payment-ui=stripe-hosted#paid-invoices-hosted) lors de la création de la session. Stripe génère alors une facture et émet les événements `invoice.created` et `invoice.updated` associés, qu'Adapty traite pour enregistrer la transaction. ## Exploiter davantage vos données Stripe \{#get-more-from-your-stripe-data\} Une fois l'intégration avec Stripe effectuée, Adapty est prêt à fournir des insights immédiatement. Pour tirer le meilleur parti de vos données Stripe, vous pouvez configurer des intégrations Adapty supplémentaires pour transférer les événements Stripe — en centralisant toutes vos analyses d'abonnements dans un seul Adapty Dashboard. :::tip Pour des analyses enrichies, vous pouvez inclure un `variation_id` dans vos métadonnées Stripe afin d'attribuer les achats à des instances de paywall spécifiques. C'est particulièrement utile lors de la mise en place de paywalls web maison, où vous souhaitez suivre quel affichage de paywall a conduit à la conversion. Notez que `variation_id` n'est lu que depuis les métadonnées des objets Stripe Subscription (`sub_...`) et Checkout Session (`ses_...`) : ```json showLineNumbers title="Stripe Metadata with variation_id" { 'customer_user_id': "YOUR_USER_ID", 'variation_id': "YOUR_VARIATION_ID" } ``` ::: Intégrations disponibles pour transférer et analyser vos événements Stripe : - [Amplitude](amplitude/) - [Webhook](webhook) - [Firebase](firebase-and-google-analytics) - [Mixpanel](mixpanel) - [Posthog](posthog) ### Événements Stripe pris en charge \{#supported-stripe-events\} Adapty prend en charge les événements Stripe suivants : - charge.refunded - customer.subscription.created - customer.subscription.deleted - customer.subscription.paused - customer.subscription.resumed - customer.subscription.updated - invoice.created - invoice.updated - payment_intent.succeeded --- # File: paddle --- --- title: "Intégration initiale avec Paddle" description: "Intégrez Paddle avec Adapty pour un traitement fluide des paiements d'abonnement." --- Adapty prend en charge les flows web2app en suivant les paiements et abonnements effectués via [Paddle](https://www.paddle.com/). Cette intégration couvre les achats initiés sur le web et les synchronise avec l'accès à l'application mobile et les analytics, aux côtés des achats intégrés depuis les stores. Elle est utile dans les cas suivants : - Centraliser les données d'abonnement des achats intégrés et des achats effectués sur votre site web dans un seul système - Accorder l'accès aux fonctionnalités payantes de votre application mobile aux utilisateurs qui ont acheté sur votre site web - Consulter les analytics et les données d'abonnement de tous vos canaux de vente dans un seul tableau de bord :::note Apple autorise désormais les applications de l'App Store américain à inclure des liens vers des systèmes de paiement externes, même si les applications peuvent encore être tenues de proposer des achats intégrés en parallèle. Consultez les directives App Store en vigueur pour votre région et catégorie d'application. ::: :::note Cette intégration porte sur le suivi et la synchronisation des achats web Paddle. Si vous devez rediriger des utilisateurs depuis l'application vers une page de paiement web, utilisez les [paywalls web](web-paywall) d'Adapty. ::: Pour configurer l'intégration Paddle, suivez ces étapes : ## 1\. Connecter Paddle à Adapty \{#1-connect-paddle-to-adapty\} L'intégration utilise des webhooks pour envoyer les données d'abonnement de Paddle vers Adapty. Pour connecter vos comptes Adapty et Paddle, vous devrez : 1. Fournir vos clés API Paddle. 2. Ajouter l'URL webhook d'Adapty dans Paddle. :::note Les étapes ci-dessous s'appliquent à la fois à la Production et au Test. Vous pouvez configurer les deux simultanément. Les liens fournis correspondent à l'environnement de Production — pour obtenir les liens de l'environnement de Test, ajoutez simplement `sandbox-` au début de chaque URL. Par exemple, utilisez `https://sandbox-vendors.paddle.com/authentication-v2` au lieu de `https://vendors.paddle.com/authentication-v2`. ::: ### 1.1. Obtenir et ajouter les clés API Paddle \{#11-get-and-add-paddle-api-keys\} 1. Dans Paddle, allez dans [Developer Tools → Authentication](https://vendors.paddle.com/authentication-v2) et cliquez sur **New API key**. <img src="/assets/shared/img/paddle-new-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Donnez un nom à la clé et définissez sa date d'expiration. Pour que la clé API fonctionne avec Adapty, vous devez lui accorder la permission **Read** pour toutes les entités. Cliquez sur **Save**. <img src="/assets/shared/img/paddle-key.webp" style={{ border: 'none', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Copy key**. <img src="/assets/shared/img/copy-paddle-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans Adapty, allez dans [App Settings → Paddle](https://app.adapty.io/settings/paddle) et collez la clé dans la section **Paddle API key**. :::warning Si vous avez défini une date d'expiration pour votre clé API Paddle, vous devez générer manuellement une nouvelle clé et la mettre à jour dans Adapty avant son expiration. L'intégration cessera de fonctionner sans avertissement à l'expiration de la clé, et les utilisateurs ne pourront plus effectuer d'achats. ::: <img src="/assets/shared/img/paddle-api-keys-adapty.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 1.2. Ajouter les événements à envoyer à Adapty \{#12-add-events-that-will-be-sent-to-adapty\} 1. Copiez l'**URL Webhook** depuis la même page **Paddle** dans Adapty. 2. Dans Paddle, allez dans [**Developer Tools → Notifications**](https://vendors.paddle.com/notifications-v2) et cliquez sur **New destination** pour ajouter un webhook. <img src="/assets/shared/img/paddle-webhook.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Saisissez un nom descriptif pour le webhook. Nous recommandons d'y inclure « Adapty » afin de le retrouver facilement si nécessaire. 4. Collez l'**URL Webhook** d'Adapty dans le champ **URL**. Veillez à utiliser le webhook correspondant au bon environnement. 5. Définissez le **Notification type** sur **Webhook**. <img src="/assets/shared/img/paddle-create-webhook.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Sélectionnez les événements suivants : - `subscription.created` - `subscription.updated` - `transaction.created` - `transaction.updated` - `adjustment.created` - `adjustment.updated` <img src="/assets/shared/img/paddle_events.png" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur **Save destination** pour finaliser la configuration du webhook. ### 1.3. Récupérer et ajouter la clé secrète du webhook \{#13-retrieve-and-add-the-webhook-secret-key\} 1. Dans la fenêtre **Notifications**, cliquez sur les trois points à côté du webhook que vous venez de créer et sélectionnez **Edit destination**. 2. Un nouveau champ appelé **Secret key** apparaîtra dans le panneau **Edit destination**. Copiez-le. <img src="/assets/shared/img/paddle-webhook-secret-key-copy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans Adapty, allez dans [App Settings → Paddle](https://app.adapty.io/settings/paddle) et collez la clé dans le champ **Notification secret key**. Cette clé est utilisée pour vérifier les données webhook dans Adapty. <img src="/assets/shared/img/paddle-webhook-secret-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 1.4. Associer les clients Paddle aux profils Adapty \{#14-match-paddle-customers-with-adapty-profiles\} Adapty doit lier chaque achat à un [profil client](profiles-crm) pour pouvoir l'utiliser dans votre application. Par défaut, les profils sont créés automatiquement lorsqu'Adapty reçoit des webhooks de Paddle. Vous pouvez choisir quelle valeur utiliser comme `customer_user_id` dans Adapty : 1. **Par défaut et recommandé :** Le `customer_user_id` que vous transmettez dans le champ `custom_data` (voir la [documentation Paddle](https://developer.paddle.com/build/transactions/custom-data)) 2. L'`email` de l'objet Paddle Customer (voir la [documentation Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters)) 3. L'identifiant Paddle Customer au format `ctm-...` (voir la [documentation Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters)) 4. Ne pas créer de profils. Choisissez cette option si vous souhaitez avoir plus de contrôle sur vos profils clients et les gérer vous-même. Vous pouvez configurer la valeur à utiliser dans le champ **Profile creation behavior** dans [App Settings → Paddle](https://app.adapty.io/settings/paddle). <img src="/assets/shared/img/paddle-users.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 2. Ajouter les produits Paddle à Adapty \{#2-add-paddle-products-to-adapty\} :::warning Assurez-vous d'ajouter vos produits Paddle à l'Adapty Dashboard ou d'ajouter un identifiant de produit Paddle à vos produits existants. Adapty ne suit que les événements pour les transactions liées à ces produits. Si vous sautez cette étape, aucun événement de transaction ne sera créé. ::: Paddle fonctionne dans Adapty comme l'App Store et Google Play — c'est une autre plateforme sur laquelle vous vendez des produits numériques. Pour le configurer, ajoutez les valeurs `product_id` et `price_id` correspondantes depuis Paddle dans la section [Products](https://app.adapty.io/products) d'Adapty. <img src="/assets/shared/img/paddle-create-product.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans Paddle, les identifiants de produit ressemblent à `pro_...` et les identifiants de prix à `pri_...`. Vous les trouverez dans votre [catalogue de produits Paddle](https://vendors.paddle.com/products-v2) en ouvrant un produit spécifique : <img src="/assets/shared/img/paddle-product-price.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois vos produits ajoutés, l'étape suivante consiste à s'assurer qu'Adapty peut associer l'achat au bon utilisateur. ## 3\. Accorder l'accès aux utilisateurs sur mobile \{#3-provide-access-to-users-on-the-mobile\} Pour que les utilisateurs qui achètent sur le web bénéficient de l'accès sur mobile, appelez `Adapty.activate()` ou `Adapty.identify()` avec le même `customer_user_id` que celui utilisé lors de l'achat. Consultez [Identification des utilisateurs](identifying-users) pour plus de détails. ## 4\. Tester votre intégration \{#4-test-your-integration\} Une fois tout configuré, vous pouvez tester votre intégration. Les transactions effectuées dans l'environnement de Test de Paddle apparaîtront comme **Test** dans Adapty. Les transactions de l'environnement de Production apparaîtront comme **Production**. Votre intégration est maintenant terminée. Les utilisateurs peuvent souscrire des abonnements sur votre site web et accéder automatiquement aux fonctionnalités premium dans votre application mobile, pendant que vous suivez toutes les analytics d'abonnement depuis votre Adapty Dashboard unifié. ## Considérations importantes \{#important-considerations\} - Dans les analytics d'Adapty, les montants des transactions incluent les taxes et les frais Paddle, ce qui diffère du tableau de bord Paddle où les montants sont affichés après taxes et frais. Les chiffres que vous verrez dans Adapty seront donc plus élevés que ceux de votre tableau de bord Paddle. - Contrairement aux autres stores, les remboursements dans Paddle n'affectent que la transaction spécifique remboursée et n'annulent pas automatiquement l'abonnement. L'abonnement restera actif à moins d'être explicitement annulé. - Vous pouvez également inclure `variation_id` dans le champ `custom_data` pour attribuer les achats à des instances de paywall spécifiques. Adapty traitera ces données depuis les webhooks et les inclura dans les analytics. ### Essais payants \{#paid-trials\} Lorsque vous travaillez avec des essais payants dans Paddle, vous devez créer deux produits dans Adapty : 1. Créez un produit non-abonnement et associez-le au prix Paddle qui facture la période d'essai. 2. Créez ensuite un produit d'abonnement (Mensuel/Hebdomadaire/etc.) et associez-le au prix Paddle qui comporte la composante d'essai gratuit. Du point de vue de Paddle, il s'agit d'un seul produit avec deux prix dans une seule transaction — un prix pour la facturation de l'essai (par exemple, 0,99 $) et un autre pour l'essai gratuit (0,00 $). Du point de vue d'Adapty, cela crée deux événements distincts : un achat unique pour le paiement de l'essai et un événement de démarrage d'essai pour le produit d'abonnement. Par exemple, lorsqu'un utilisateur commence un essai payant à 0,99 $ pour un abonnement à 9,99 $/mois, Paddle crée une transaction avec les deux prix, tandis qu'Adapty traite cela comme un achat unique de 0,99 $ (paiement immédiat) et un événement de démarrage d'essai à 0,00 $ (futur abonnement à 9,99 $/mois). :::note Lorsque des utilisateurs annulent un essai payant, vous recevez les événements **Trial expired** et **Trial renewal canceled**. ::: ## Exploitez davantage vos données Paddle \{#get-more-from-your-paddle-data\} :::important Pour que vos événements Paddle fonctionnent avec les intégrations, vos utilisateurs doivent s'être connectés à l'application avec leur compte App Store/Google Play au moins une fois. ::: Une fois intégré à Paddle, Adapty est prêt à fournir des insights immédiatement. Pour tirer le meilleur parti de vos données Paddle, vous pouvez configurer des intégrations Adapty supplémentaires pour transférer les événements Paddle — en centralisant toutes vos analytics d'abonnement dans un seul Adapty Dashboard. Intégrations disponibles pour transférer et analyser vos événements Paddle : - [AppsFlyer](appsflyer) - [Webhook](webhook) - [Posthog](posthog) ## Limitations actuelles \{#current-limitations\} - **Annulations** : Paddle propose deux options d'annulation d'abonnement : 1. Annulation immédiate : l'abonnement est annulé immédiatement. 2. Annulation en fin de période : l'abonnement est annulé à la fin de la période de facturation en cours (similaire aux abonnements intégrés sur les stores). - **Remboursements** : Adapty suit les remboursements complets et partiels. - **Délai de grâce** : Par défaut, Paddle applique un délai de grâce fixe de 30 jours pour les problèmes de facturation, pendant lequel l'abonnement reste actif. Vous pouvez [personnaliser la durée du délai de grâce et l'action après son expiration (suspension ou annulation de l'abonnement)](https://developer.paddle.com/build/retain/configure-payment-recovery-dunning#prerequisites). **Essais** : Si le prélèvement échoue après la fin d'un essai, le statut de l'abonnement passe à `past_due`. En production, Paddle Retain applique une fenêtre de relance pour tenter de récupérer le paiement avant d'annuler ou de suspendre l'abonnement. En sandbox, Retain n'est pas disponible, donc aucune nouvelle tentative de paiement n'est effectuée et l'abonnement reste `past_due` indéfiniment. --- **Voir aussi :** - [Valider un achat dans Paddle, obtenir un niveau d'accès et importer l'historique des transactions depuis Paddle via l'API server-side](api-adapty/operations/validatePaddlePurchase) --- # File: custom-store --- --- title: "Intégration initiale avec d'autres stores" description: "Intégration initiale d'Adapty avec l'App Store : guide rapide" --- Bienvenue chez Adapty ! Notre priorité est de vous aider à démarrer rapidement et à obtenir les meilleurs résultats possibles pour votre application. L'intégration initiale n'est requise que pour [l'App Store](initial_ios), [Google Play](initial-android), [Stripe](stripe) et [Paddle](paddle), car Adapty vérifie vos applications, produits et offres auprès de ces stores. Adapty ne valide pas les données avec les autres app stores et ne traite pas les achats effectués via ceux-ci. Cependant, vous pouvez tout de même marquer les produits vendus via d'autres stores pour qu'Adapty accorde l'accès au contenu payant après un achat réussi, reflète les transactions dans vos analytiques et les partage via des intégrations. <img src="/assets/shared/img/Adapty-Communication-Scheme.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::important Assurez-vous que votre backend traite l'achat et envoie la transaction à Adapty via l'[API server-side d'Adapty](getting-started-with-server-side-api). Adapty n'accordera l'accès, ne déclenchera un événement de transaction, ne l'enverra aux intégrations et ne le reflétera dans les analytiques qu'après réception de la transaction. ::: Pour marquer un produit comme vendu via un app store personnalisé, sélectionnez l'app store lors de la création du produit. Si le store dont vous avez besoin n'est pas répertorié, voici comment en créer un : 1. Sur la page **Products**, ouvrez le produit que vous souhaitez vendre via un app store personnalisé. 2. Choisissez l'app store par lequel vous souhaitez vendre. S'il n'est pas répertorié, cliquez sur le bouton **Create Custom Store**. <img src="/assets/shared/img/create_custom-appstore.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Saisissez le **Title** et le **Store ID** du store. 4. Cliquez sur le bouton **Create store**. Si votre backend est correctement configuré, Adapty recevra les transactions de produits de ce store personnalisé, les reflétera dans les analytiques, le [**Event Feed**](event-feed) et les [intégrations](https://app.adapty.io/integrations), et accordera l'accès en conséquence. ## Tirer le meilleur parti des données de votre store personnalisé \{#get-more-from-your-custom-store-data\} :::important Pour que les événements de votre store personnalisé fonctionnent avec les intégrations, vos utilisateurs doivent s'être connectés à l'application avec leur compte App Store/Google Play au moins une fois. ::: Une fois votre intégration de store personnalisé configurée, Adapty est prêt à fournir des informations immédiatement. Pour tirer le meilleur parti de vos données, vous pouvez configurer des intégrations Adapty supplémentaires afin de transférer les événements du store personnalisé — centralisant ainsi toutes vos analytiques d'abonnement dans un seul Adapty Dashboard. Intégrations disponibles pour transférer et analyser vos événements de store personnalisé : - [AppsFlyer](appsflyer) - [Webhook](webhook) - [Posthog](posthog) --- # File: transfer-apps --- --- title: "Transférer votre application vers un autre compte" description: "Changer le propriétaire d'une application dans Adapty" --- Transférez votre application vers un autre propriétaire lorsque votre entreprise est rachetée, que vous vendez votre application ou que vous réorganisez vos entités commerciales. Le processus de transfert implique de coordonner les changements dans Adapty, App Store Connect et Google Play Console pour assurer la continuité du service. ## Transférer la propriété de l'application \{#transfer-app-ownership\} Effectuez d'abord le transfert dans le store, puis transférez l'application dans Adapty. Cet ordre garantit que les achats continuent de fonctionner tout au long de la transition. :::note Ne supprimez pas et ne recréez pas de produits pendant le processus de transfert. Ne modifiez pas les identifiants de produits avant d'avoir vérifié que le transfert s'est terminé avec succès. ::: ### Transfert App Store (iOS) \{#app-store-ios-transfer\} :::important Les clés API App Store Connect (Issuer ID, Key ID, fichier .p8) sont liées au compte, pas à l'application. Après le transfert, vous devez générer de nouvelles clés API depuis le compte du nouveau propriétaire et les mettre à jour dans Adapty. Le secret partagé spécifique à l'application continue de valider les reçus pendant la fenêtre de transfert, mais le nouveau propriétaire doit également le régénérer et le mettre à jour dans Adapty une fois le transfert terminé. ::: 1. **Nouveau propriétaire :** Créez un compte Adapty sur [app.adapty.io](https://app.adapty.io) si vous n'en avez pas encore. 2. **Ancien propriétaire :** Initiez le transfert de l'application dans App Store Connect en suivant le [guide de transfert](https://developer.apple.com/help/app-store-connect/transfer-an-app/overview-of-app-transfer) d'Apple. 3. **Nouveau propriétaire :** Acceptez le transfert dans App Store Connect. 4. **Ancien propriétaire :** Envoyez un e-mail à [support@adapty.io](mailto:support@adapty.io) pour transférer l'application dans Adapty. Indiquez le nom de l'application et l'adresse e-mail du nouveau propriétaire. 5. **Nouveau propriétaire :** Après avoir reçu l'application dans Adapty, suivez le [guide d'intégration App Store](initial_ios) pour générer et configurer toutes les informations d'identification sous votre compte. ### Transfert Google Play (Android) \{#google-play-android-transfer\} 1. **Nouveau propriétaire :** Créez un compte Adapty sur [app.adapty.io](https://app.adapty.io) si vous n'en avez pas encore. 2. **Les deux propriétaires :** Assurez-vous que les deux comptes Google Play Developer sont entièrement enregistrés. 3. **Ancien propriétaire :** Soumettez une demande de transfert via Google Play Console ou le support Google Play Developer. Google peut demander des documents supplémentaires tels que des numéros DUNS, des contrats ou des preuves de vente. 4. **Nouveau propriétaire :** Examinez et approuvez la demande de transfert. 5. **Google :** L'équipe de support Google traite le transfert, généralement en quelques jours ouvrables, mais cela peut prendre plus de temps selon la vérification du compte, la complexité des abonnements et la configuration des paiements. 6. **Ancien propriétaire :** Une fois que Google a effectué le transfert, envoyez un e-mail à [support@adapty.io](mailto:support@adapty.io) pour transférer l'application dans Adapty. Indiquez le nom de l'application et l'adresse e-mail du nouveau propriétaire. 7. **Nouveau propriétaire :** Après avoir reçu l'application dans Adapty, suivez le [guide d'intégration Google Play](initial-android) pour générer et configurer toutes les informations d'identification sous votre compte. Le transfert inclut les utilisateurs, les abonnements, les statistiques, les évaluations et la fiche du store. La continuité de facturation est maintenue pour les abonnés existants, mais les versements basculent vers le compte marchand du nouveau propriétaire uniquement une fois le transfert terminé. Les rapports de paiement et les commandes antérieurs au transfert restent dans le compte d'origine. Suivez le [guide de transfert](https://support.google.com/googleplay/android-developer/answer/6230247) de Google pour les exigences détaillées. ## Atténuation des risques et calendrier \{#risk-mitigation-and-timing\} **Ce qui continue de fonctionner pendant le transfert :** - Les achats et renouvellements (le secret partagé spécifique à l'application continue de valider les reçus pendant la fenêtre de transfert) - L'accès des abonnés existants - Le SDK continue de fonctionner **Ce qui s'arrête temporairement :** - Les appels API App Store Connect (jusqu'à la configuration des nouvelles clés) - Les notifications serveur (jusqu'à la reconfiguration du point de terminaison) - Les analyses peuvent présenter des lacunes pendant la transition des informations d'identification **Calendrier recommandé :** - Effectuez les transferts pendant les périodes de faible trafic (3h-6h dans le fuseau horaire principal de vos utilisateurs) - Préparez le nouveau propriétaire à configurer les informations d'identification immédiatement après avoir accepté le transfert dans le store - Prévoyez 15 à 30 minutes entre l'acceptation du transfert et la finalisation de l'intégration Adapty **Après avoir terminé le transfert :** - Testez immédiatement la validation des reçus - Surveillez les taux de succès des renouvellements automatiques pendant 48 heures - Vérifiez que les notifications serveur parviennent bien à vos systèmes - Assurez-vous que les nouveaux achats sont correctement suivis ## Vérifier que le transfert s'est terminé avec succès \{#verify-transfer-completed-successfully\} Après avoir effectué les transferts dans Adapty et dans le store : 1. **Vérifier l'accès au tableau de bord** : Le nouveau propriétaire doit voir l'application dans son Adapty Dashboard. 2. **Vérifier la connexion de la clé API** : Vérifiez que la nouvelle clé API App Store Connect ou le compte de service Google Play se connecte avec succès dans Adapty. 3. **Tester la connexion SDK** : Lancez votre application et vérifiez que le SDK Adapty s'initialise sans erreur. --- # File: installation-of-adapty-sdks --- --- title: "Installation du SDK Adapty" description: "Installez les SDK Adapty pour iOS, Android et les applications multiplateformes." --- Trois options s'offrent à vous pour démarrer selon vos préférences : - **Suivre les guides de démarrage rapide par plateforme** : Ces guides contiennent des extraits de code prêts pour la production, ce qui permet une intégration rapide. - [iOS](ios-sdk-overview) - [Android](android-sdk-overview) - [React Native](react-native-sdk-overview) - [Flutter](flutter-sdk-overview) - [Unity](unity-sdk-overview) - [Kotlin Multiplatform](kmp-sdk-overview) - [Capacitor](capacitor-sdk-overview) - **Utiliser des LLMs** : Notre documentation est compatible avec les LLMs. Consultez notre [guide](adapty-cursor) pour tirer le meilleur parti des LLMs avec la documentation Adapty. - **Explorer les exemples d'applications** : - [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples) - [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app) - [React Native (Exemple basique en RN pur)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample) - [React Native (Exemple avancé – utile pour le développement, car il permet de traiter des cas plus complexes)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools) - [React Native (Build de développement Expo)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) - [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) - [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) - [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) - [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example) - [Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples) --- # File: sample-apps --- --- title: "Applications exemples" description: "" --- Pour vous aider à démarrer avec le SDK Adapty, nous avons préparé des applications exemples qui illustrent comment intégrer et utiliser ses principales fonctionnalités. Ces applications proposent des implémentations prêtes à l'emploi de paywalls, d'achats et du suivi des analytics. <img src="/assets/shared/img/adapty-scheme.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Pourquoi utiliser les applications exemples ? \{#why-use-sample-apps\} - **Intégration rapide :** Découvrez comment le SDK Adapty fonctionne dans une vraie application. - **Bonnes pratiques :** Suivez les patterns d'implémentation recommandés. - **Débogage & tests :** Utilisez les applications exemples pour diagnostiquer et expérimenter avant d'intégrer Adapty dans votre propre projet. ## Applications exemples disponibles \{#available-sample-apps\} - [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples) - [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app) - [React Native (Exemple de base en RN pur)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample) - [React Native (Exemple avancé – utile pour le développement, car il permet de travailler sur des cas plus complexes)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools) - [React Native (Build dev Expo)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) - [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) - [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) - [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) - [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example) - [Capacitor (React)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example) - [Capacitor (Vue.js)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example) - [Capacitor (Angular)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example) - [Capacitor (Outils de développement avancés)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools) --- # File: adapty-flow-builder --- --- title: "Flows (Beta)" description: "Éditeur visuel no-code pour créer des flows interactifs. Mettez à jour les textes, le design et les prix sans publier de nouvelle version." --- :::important Les flows sont actuellement pris en charge sur iOS, Android, React Native, Flutter et Capacitor SDK v4 et supérieur. La prise en charge d'autres plateformes et frameworks arrive prochainement. ::: <CustomDocCardList ids={['builder-ui', 'flow-builder-recipes', 'builder-navigation-actions']} /> Dans Adapty, vous pouvez créer des flows dans un éditeur visuel no-code. - **Créez des paywalls, des onboardings et bien plus** : créez des flows dynamiques à un ou plusieurs écrans. - **Templates de flow complets** : démarrez avec un [template conçu par des professionnels](paywall-builder-templates). - **Design flexible** : recréez des écrans complexes visuellement, sans écrire une ligne de code. - **Rendu natif** : le SDK Adapty rend les flows nativement, sans web views, pour une expérience utilisateur fluide. - **Mise à jour sans redéploiement** : modifiez les textes, le design ou la logique à tout moment. Les changements parviennent à vos utilisateurs sans nouvelle version de l'app. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/8Cby6lVGI0o?si=rYA1HtdayyF1ffWd" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Ce que vous pouvez créer \{#what-you-can-build\} Vous pouvez placer des flows n'importe où dans votre app — au premier lancement, devant une fonctionnalité premium ou après une action clé. Chaque écran est entièrement personnalisable, pour que chaque flow colle à son contexte. Voici quelques-uns des usages les plus populaires : - **Onboarding** : présentez les fonctionnalités de votre app, posez des questions et personnalisez les éléments mis en avant et les CTA en fonction des réponses au quiz. Voir [Créer un flow d'onboarding personnalisé](onboarding-flow-tutorial). - **Écrans de paywall** : bloquez l'accès au contenu premium et présentez vos produits avec des listes de fonctionnalités, les tarifs et un bouton d'achat. Voir [Créer un écran de paywall simple](basic-paywall-screen). - **Offres par niveaux en onglets** : affichez les niveaux d'abonnement côte à côte dans des onglets, en changeant la liste de fonctionnalités et le CTA au fil de la navigation. Voir [Créer un paywall avec des onglets](paywall-with-tabs) et [Afficher différentes fonctionnalités par produit](paywall-features-per-product). - **Listes d'offres dépliables** : mettez en avant une offre principale et révélez la liste complète des produits dans une bottom sheet quand l'utilisateur veut comparer. Voir [Afficher toutes les offres dans une bottom sheet](show-plans-bottom-sheet). - **Sondages et quiz** : collectez les objectifs, préférences ou le niveau d'expérience, puis utilisez les réponses pour brancher le flow ou adapter les écrans suivants. Voir [Formulaires et saisies dans le Flow Builder](builder-inputs-and-forms). - **Preuve sociale** : renforcez la confiance avec des avis, notes et témoignages juste avant la décision d'achat. Voir [Avis et témoignages](builder-reviews-and-testimonials). - **Écrans promo et de reconquête** : proposez des réductions limitées dans le temps, des offres d'essai gratuit ou des écrans de reconquête pour réengager les utilisateurs inactifs. Ce ne sont que les usages les plus courants. Les flows sont construits à partir d'éléments flexibles et réutilisables, que vous pouvez combiner pour créer presque n'importe quel écran dont votre produit a besoin — et le remodeler à tout moment. :::link Vous souhaitez en savoir plus sur la création de flows ? Regardez les tutoriels vidéo étape par étape dans notre [playlist YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM). ::: ## Créer un flow \{#create-a-flow\} [Créez un nouveau flow](paywall-builder-templates) à partir d'un template de la galerie ou d'un canvas vierge. Personnalisez-le ensuite grâce aux fonctionnalités suivantes : - **[Bibliothèque d'éléments](builder-elements)** — blocs prêts à l'emploi pour le texte, les médias, les boutons, les formulaires et autres contenus. - **[Actions](onboarding-actions)** — naviguez entre les écrans, ouvrez des URLs, lancez des achats, et plus encore. - **[Variables](onboarding-variables)** — utilisez des valeurs de variables dans les textes ou pour déclencher une logique conditionnelle dans le flow. - **[Navigation conditionnelle](onboarding-navigation-branching)** — branchez le flow en fonction des saisies utilisateur. - **[Quiz et saisies](builder-inputs-and-forms)** — collectez et traitez les entrées utilisateur. - **[Mode sombre](paywall-dark-mode)** — stylisez les éléments pour correspondre au thème de l'appareil. - **[Localisation](add-flow-remote-config-locale)** — manuelle ou assistée par IA. [Enregistrez et publiez](builder-save-publish) votre brouillon, puis associez-le à un [placement](create-placement). Un placement peut contenir différents flows pour différentes [audiences](add-audience-paywall-ab-test). ## Étapes suivantes \{#next-steps\} <CustomDocCardList /> --- # File: paywall-builder-templates --- --- title: "Créer un flow" description: "Commencez un nouveau flow à partir d'un template de la galerie ou d'un point de départ minimal." --- Vous pouvez créer un flow à partir d'un template ou de zéro. :::link Vous souhaitez en savoir plus sur la création de flows ? Regardez les tutoriels vidéo étape par étape dans notre [playlist YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM). ::: ## Créer un flow \{#create-flow\} 1. Ouvrez la page **Flows**. 2. Cliquez sur **Create flow**. 3. Choisissez une option : - **Browse templates** (ouvre la bibliothèque de templates) - **Start from scratch** (crée un flow vide) 4. Renommez le flow dans l'éditeur. Cliquez sur le nom du flow dans l'en-tête et saisissez un nouveau nom. :::warning Adapty autorise les noms de flows en doublon. Renommez chaque nouveau flow, sinon vous vous retrouverez avec plusieurs flows **Untitled** difficiles à distinguer. ::: ### Utiliser un template \{#use-a-template\} La bibliothèque de templates contient plusieurs templates qui servent de point de départ pour votre flow. Chacun est un flow complet avec plusieurs écrans, des éléments interactifs et une navigation fonctionnelle. Vous pouvez modifier n'importe quel élément pour le personnaliser. Pour appliquer un template : 1. Dans la bibliothèque de templates, parcourez les cartes de templates. Chaque carte affiche des captures d'écran d'aperçu d'un flow. 2. Cliquez sur **Use as template** sur la carte souhaitée. Le template se charge dans le builder. Vous pouvez ensuite modifier n'importe quel élément, écran ou propriété. ### Démarrer de zéro \{#start-from-scratch\} Démarrer de zéro crée un flow avec un seul écran vierge. Concevez l'écran avec les éléments de la [bibliothèque d'éléments](builder-elements). ## Changer de template \{#change-the-template\} Vous pouvez changer de template depuis le builder. Ouvrez le panneau Screens et cliquez sur le bouton **Templates** Templates pour rouvrir la bibliothèque de templates, puis choisissez un nouveau template. :::warning L'application d'un nouveau template remplace le brouillon de votre flow actuel. Adapty vous demande de confirmer — cliquez sur **Use template** pour continuer, ou sur **Cancel** pour conserver votre brouillon. Une fois confirmé, le brouillon précédent ne peut pas être restauré. Le flow publié reste en ligne et n'est pas affecté. ::: ## Polices personnalisées dans les templates \{#custom-fonts-in-templates\} :::link Article principal : [Polices personnalisées dans le Flow Builder](using-custom-fonts-in-flow-builder) ::: Les templates marqués d'un badge **Custom font** utilisent des polices personnalisées. Ces polices ne sont pas incluses dans le SDK. Survolez le badge pour voir quelles polices le template utilise. Pour afficher la typographie prévue sur l'appareil, ajoutez les fichiers de polices à votre bundle d'application. Les versions plus anciennes de l'application qui n'incluent pas la police basculeront sur une police système. Pour changer de police sans affecter les versions plus anciennes, dupliquez le flow, modifiez la police dans la copie, et limitez cette copie aux [utilisateurs disposant des versions de l'application incluant la police](segments). --- # File: builder-ui --- --- title: "Interface du Flow Builder" description: "Présentation de l'interface et de l'espace de travail du Flow Builder." --- L'interface principale du Flow Builder regroupe tous les outils nécessaires pour ajouter des éléments visuels, modifier leurs propriétés et ajuster la logique du flow. Cet article décrit chaque zone de l'interface : son rôle et où la trouver. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/n0uV44q318o?si=sbJwE33yJWxbbEE1" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> :::link Vous souhaitez en savoir plus sur la création de flows ? Regardez les tutoriels vidéo étape par étape dans notre [playlist YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM). ::: ## Contrôles du projet et raccourcis utiles (barre d'outils supérieure) \{#project-controls-and-useful-shortcuts-top-toolbar\} * **Close** Close : Quitter l'éditeur de flow et revenir à la page des flows. * **App name** App : Identifie l'application à laquelle appartient le flow. * **All flows** Flows : Ouvre la liste de tous les flows pour cette application. * **Flow status** : L'icône à gauche du nom du flow indique le [statut du flow](builder-save-publish#flow-status) actuel : - **Draft** Draft - **Publishing** (indicateur de chargement) - **Failed** Failed - ou **Live** Live. * **Rename the flow** : Cliquez sur le nom du flow pour le renommer. Plusieurs flows peuvent avoir le même nom — [donnez à chaque nouveau flow un nom unique](paywall-builder-templates#create-flow). * **View mode toggle** : Basculez entre la vue de conception Cursor et la [vue Remote Config](customize-flow-with-remote-config)Remote Config. * **Undo/Redo** : Cliquez sur les icônes en forme de flèche pour annuler Undo ou rétablir Redo vos modifications. Vous pouvez aussi utiliser ⌘Z / Ctrl+Z pour annuler. * **Save draft / Publish** : Cliquez sur **Save draft** pour enregistrer votre progression sans mettre en ligne (⌘ / Ctrl+S). Ouvrez le menu déroulant Open dropdown pour accéder au bouton [**Publish**](builder-save-publish). Vous ne pouvez ajouter votre flow à un [placement](create-placement) qu'après l'avoir publié. ## Zone de prévisualisation (centre) \{#preview-area-center\} La zone centrale de l'espace de travail simule l'apparence de votre flow sur un appareil mobile. * Pour sélectionner un élément et modifier ses propriétés, cliquez dessus. Pour sélectionner un élément enfant à l'intérieur d'un conteneur, cliquez d'abord sur le conteneur, puis sur l'élément enfant. * Pour modifier les propriétés de l'écran lui-même, cliquez en dehors de tout élément, ou sélectionnez l'écran dans le panneau Screens and Layers. * Pour changer l'ordre d'un élément, faites glisser son entrée vers le haut ou vers le bas dans le panneau Screens and Layers. :::warning L'éditeur de flow est conçu pour créer des mises en page responsives. Par conséquent, vous **ne pouvez pas modifier manuellement la position des éléments** — vous pouvez uniquement changer leur ordre. Les paramètres de mise en page de chaque conteneur déterminent comment les éléments qu'il contient sont répartis. ::: ### Barre d'écran actif (au-dessus de l'aperçu de l'appareil) \{#active-screen-bar-above-the-device-preview\} - **Screen name** — un badge avec le nom de l'écran actuel. - **Toggle animations** Toggle animations — active ou désactive les aperçus d'animation des éléments ; ils s'exécutent en continu jusqu'à ce qu'ils soient désactivés. Visible uniquement lorsque l'écran actif contient au moins une [animation](builder-styling#animation). N'a aucun effet sur la visibilité des animations sur l'appareil réel. - **Add element** Plus — ouvre la [bibliothèque d'éléments](builder-elements) à l'écran actuel. Équivalent au **+** en haut du panneau Screens and Layers — pratique quand le panneau est replié. ### Commandes d'affichage (barre d'outils inférieure) \{#view-controls-bottom-toolbar\} Les outils de la barre d'outils inférieure permettent de contrôler l'aperçu. * **Device** : Sélectionnez l'un des modèles iPhone ou téléphone Android disponibles pour modifier les dimensions de la fenêtre d'affichage et le contour de l'appareil. * **Screen orientation** : Basculez entre les modes portrait Portrait et paysage Landscape pour prévisualiser votre flow dans différentes orientations. * **Color scheme** : Passez du mode clair Light mode au mode sombre Dark mode pour voir comment votre design s'adapte aux différents thèmes. * **Locale** : Sélectionnez une locale pour prévisualiser votre flow avec du contenu localisé. * **View options** : Activez ou désactivez le biseau de l'appareil et les guides de zone de sécurité. ## Propriétés de l'écran et des éléments (panneau de droite) \{#screen-and-element-properties-right-panel\} ### Paramètres et mise en page de l'écran \{#screen-settings-and-layout\} :::link Article principal : [Écrans et calques](paywall-layout-and-products) ::: Lorsqu'aucun élément n'est sélectionné, le panneau de droite vous permet d'ajuster les propriétés de l'écran de [flow](paywall-layout-and-products) actif, notamment : * Les interactions avec l'interface système (par exemple, la visibilité de la barre d'état) * Les règles de mise en page automatique * L'arrière-plan (couleur, image ou vidéo) * La taille des marges internes * Le comportement de défilement vertical Si l'écran contient certains éléments, comme des [quiz interactifs](onboarding-quizzes), cette liste s'étoffera des propriétés correspondantes. ### Propriétés des éléments \{#element-properties\} Lorsque vous sélectionnez un élément, le panneau de droite vous permet de modifier ses propriétés de style et d'interaction. #### Propriétés de design \{#design-properties\} :::link En savoir plus : [Mise en page et positionnement](manage-paywall-ui-elements), [Styles et apparence](builder-styling) ::: L'onglet **Design** vous permet de configurer l'apparence visuelle et la mise en page de l'élément sélectionné : * **Visibility** : Afficher ou masquer l'élément. Activez la visibilité **Conditional** pour définir des règles déterminant quand l'élément doit être visible. * **Position** : Choisir entre le positionnement Relative, Absolute ou Fixed. * **Content** (éléments texte uniquement) : Modifier le contenu textuel de l'élément, insérer des [variables](#variables) et gérer les localisations. * **Typography** (éléments texte uniquement) : Configurer la police, la graisse, la taille, la couleur, l'alignement, la décoration et la troncature. * **Spacing** : Définir les marges et le rembourrage de l'élément. * **Effects** : Ajouter des ombres portées, des ombres intérieures, un flou d'arrière-plan ou un flou de calque. * **Animation** : Ajouter des effets animés (par exemple, Pulse) et configurer leur durée et leur intensité. * **Appearance** : Ajuster l'opacité et la rotation. * **Layout** : Choisir une direction de mise en page (verticale ou horizontale) et déterminer comment les éléments enfants sont répartis. #### Propriétés d'interactions \{#interactions-properties\} :::link En savoir plus : [Actions](onboarding-actions), [Navigation et interaction](onboarding-navigation-branching) ::: L'onglet **Interactions** vous permet de définir ce qui se passe lorsque l'utilisateur interagit avec l'élément sélectionné. Chaque interaction se compose d'un **déclencheur** et d'une ou plusieurs **actions** : * **Les déclencheurs** définissent *quand* quelque chose se produit — par exemple, **On Tap** (l'utilisateur appuie sur l'élément). * **Les actions** définissent *ce qui* se passe — par exemple, naviguer vers un autre écran ou modifier la valeur d'une variable. Ajoutez plusieurs actions à un seul déclencheur pour les enchaîner en séquence. Vous pouvez ajouter plusieurs déclencheurs au même élément pour exécuter plusieurs actions dans l'ordre. ## Panneau gauche \{#left-panel\} Le panneau gauche change de fonctionnalité selon le bouton actif. Vous pouvez choisir entre : * [Écrans et calques](#screens-and-layers) * [Ajouter un élément](#element-selection) * [Produits](#products) * [Styles](#saved-styles) * [Variables](#variables) * [Localisation](#localization) ### Écrans et Couches \{#screens-and-layers\} :::link Article principal : [Écrans et Couches](paywall-layout-and-products) ::: Le bouton Couches Layers ouvre le panneau Écrans et Couches (affiché par défaut à l'ouverture du flow builder). Il affiche chaque écran sous forme d'arborescence de couches. Chaque élément d'un écran est une couche, et les conteneurs ont leurs éléments enfants imbriqués à l'intérieur. Vous pouvez glisser-déposer les couches pour les réorganiser. ### Sélection d'éléments \{#element-selection\} :::link Article principal : [Éléments](builder-elements) ::: Si vous cliquez sur le bouton plus Plus, le panneau gauche affiche la liste des éléments d'interface disponibles et leurs variations. Cliquez sur une entrée pour l'ajouter à l'écran actuel en tant que nouveau calque. ### Produits \{#products\} :::link Article principal : [Produits](paywall-product-block) ::: Le bouton produits Products ouvre la liste des produits. Il indique quels produits sont assignés à chaque écran de votre flow. Cette liste est en lecture seule. Pour assigner des produits à un écran, ajoutez un élément Produit et configurez-le dans le panneau de droite. Pour créer ou modifier des produits, utilisez la page **Products** dans l'Adapty Dashboard. ### Styles enregistrés \{#saved-styles\} :::info En savoir plus : - [Styles et apparence](builder-styling) - [Contenu textuel](onboarding-text) - [Mode sombre](paywall-dark-mode) ::: Le bouton Styles Styles ouvre les styles enregistrés. Ici, vous pouvez modifier et gérer les styles globaux. Si plusieurs éléments de votre flow utilisent la même typographie ou la même couleur, enregistrez ces données comme style global. Vous pourrez ensuite les réutiliser en un seul clic. Actuellement, Flow Builder prend en charge deux types de styles globaux — les styles de police et les styles de couleur. Chaque style de couleur peut optionnellement avoir une valeur distincte pour le mode sombre. ### Variables \{#variables\} :::link Article principal : [Variables](onboarding-variables) ::: Le bouton entre crochets Variables ouvre Variables. Ici, vous pouvez créer et gérer des variables pour votre flow. À l'exécution, le SDK remplace les espaces réservés aux variables par des valeurs réelles — attributs utilisateur, prix des produits, chaînes localisées, etc. Les variables sont regroupées en deux onglets : * **Custom** : Variables que vous créez et contrôlez via des actions. * **Elements** : Valeurs déterminées par l'interaction de l'utilisateur — comme les réponses à un quiz, les états d'un toggle ou la sélection d'un onglet. Les variables de produit — prix, nom et autres données produit — n'apparaissent pas dans ce panneau. Référencez-les directement lors de la modification d'un élément texte. Utilisez les variables pour : * **Lier du texte** : Afficher du contenu dynamique à la place de chaînes statiques. * **Contrôler la visibilité** : Afficher ou masquer des éléments selon des conditions (par exemple, masquer un bouton de mise à niveau pour les utilisateurs premium). * **Interagir avec l'utilisateur** : Accéder aux données saisies dans des champs de formulaire, comme des formulaires ou des quiz. ### Localisation \{#localization\} :::link Article principal : [Localisation](add-flow-remote-config-locale) ::: La vue Localisation vous permet de gérer le contenu traduisible de votre flow. Elle affiche un tableau de toutes les chaînes de texte et éléments multimédias, organisés par écran, avec une colonne par locale. Depuis cette vue, vous pouvez : * Ajoutez de nouvelles langues et modifiez les chaînes localisées directement. * Sélectionnez la langue par défaut de votre flow. * Suivez l'état des traductions — chaque ligne est marquée **Done** ou **Missing**. * Filtrez par écran ou affichez uniquement les traductions manquantes. * **Import** ou **Export** le contenu pour le traduire en masse en dehors d'Adapty. --- # File: flow-builder-recipes --- --- title: "Recettes de flow courantes" description: "Guides étape par étape pour créer les modèles d'écrans les plus courants dans le Flow Builder." --- Cette section explique comment créer les modèles d'écrans les plus courants dans le Flow Builder — élément par élément, des choix de mise en page aux interactions. Chaque guide est autonome et utilise les éléments standard du Flow Builder. <CustomDocCardList /> Suivez cette vidéo de démarrage rapide pour créer un flow personnalisé de base : <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aa-m459VIuY?si=zN_Co6B6qB88UPZP" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> :::link Vous souhaitez en savoir plus sur la création de flows ? Regardez les tutoriels vidéo étape par étape dans notre [playlist YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM). ::: --- # File: basic-paywall-screen --- --- title: "Créer un écran de paywall basique" description: "Guide pas à pas pour créer un écran de paywall standard dans le Flow Builder." --- C'est le template de paywall le plus courant. Utilisez-le comme écran autonome ou placez-le à la fin d'un [flow](adapty-flow-builder) multi-écrans. Un écran de paywall standard contient un titre, une description de la valeur, une liste de fonctionnalités, une liste de produits, un bouton d'achat et des liens en pied de page pour restaurer les achats, les conditions d'utilisation et la politique de confidentialité. ## Avant de commencer \{#before-you-start\} - [Créez des produits](create-product) dans l'Adapty Dashboard. - [Connectez Adapty à l'App Store et Google Play](integrate-payments). ## 1. Configurez les styles réutilisables \{#1-set-up-reusable-styles\} Les styles réutilisables vous permettent d'appliquer les mêmes typographies et couleurs sur tous les écrans en un seul clic. Chaque nouveau flow est livré avec un ensemble de styles de texte par défaut (H1, Body, Button Label, etc.) — ajustez-les pour correspondre à votre design avant d'ajouter des éléments. Ajoutez des styles de couleur pour les couleurs de votre marque que vous utiliserez sur l'ensemble de l'écran. Pour les instructions complètes, consultez [Styles et apparence — Styles réutilisables](builder-styling#reusable-styles). Pour configurer les styles : 1. Dans le panneau gauche, ouvrez le panneau **Styles** Styles. 2. Dans l'onglet **Text**, cliquez sur un style existant pour modifier sa police, sa graisse, sa taille et sa couleur. N'ajoutez de nouveaux styles que si les styles par défaut ne couvrent pas vos besoins. 3. Dans l'onglet **Colors**, cliquez sur **Plus Create style** et ajoutez les couleurs que vous comptez réutiliser sur l'écran. ## 2. Configurez la mise en page de l'écran \{#2-set-up-the-screen-layout\} L'écran lui-même fait office de conteneur pour tout ce que vous ajoutez. Configurez sa mise en page, son arrière-plan et ses marges internes en premier, afin que les éléments ajoutés ensuite se distribuent correctement. Pour la liste complète des propriétés d'écran, consultez [Écrans et calques — Paramètres d'écran](paywall-layout-and-products#screen-settings). Pour configurer l'écran : 1. Cliquez sur une zone vide du canvas pour sélectionner l'écran. Le panneau droit bascule sur les paramètres de l'écran. 2. Sous **System UI**, désactivez **Safe area** pour que le contenu s'étende jusqu'aux bords de l'écran. 3. Sous **Layout**, définissez la direction sur **Vertical** Vertical et la distribution sur **Space evenly**. 4. Sous **Fill**, choisissez un type d'arrière-plan — couleur unie, dégradé ou image. Cet exemple utilise un **Gradient** Gradient avec deux points de couleur. ## 3. Ajoutez le bouton de fermeture \{#3-add-the-close-button\} Le bouton de fermeture ferme le paywall. Le preset **Close** est préconfiguré — aucune configuration d'action n'est nécessaire. 1. Sur le canvas, cliquez sur **+**. 2. Sélectionnez **Buttons** > **Close**. ## 4. Ajoutez le titre et associez-le au bouton de fermeture \{#4-add-the-title-and-pair-it-with-the-close-button\} Le H1 se place à côté du bouton de fermeture en haut de l'écran. Pour les aligner horizontalement, regroupez-les dans un conteneur horizontal. Pour ajouter le titre : 1. Cliquez sur **+** > **Text** > **H1**. 2. Avec le H1 sélectionné, ouvrez l'onglet **Design** dans le panneau droit et modifiez le texte dans le champ **Content**. Pour regrouper le titre avec le bouton de fermeture : 1. Dans le panneau **Layers**, cliquez sur le menu à trois points Context menu du calque du bouton de fermeture et choisissez **Wrap** > **Wrap in Horizontal Container**. 2. Faites glisser le calque H1 dans le nouveau conteneur horizontal. Pour aligner les deux éléments : 1. Ajustez la taille du bouton de fermeture et la taille de police du H1 pour qu'ils tiennent confortablement sur la même ligne. 2. Avec le conteneur horizontal sélectionné, définissez l'alignement et la distribution dans le panneau droit pour que les éléments s'alignent correctement. ## 5. Ajoutez la description de la valeur \{#5-add-the-value-description\} Une courte ligne de corps sous le titre explique ce que l'utilisateur obtient avec l'abonnement. 1. Cliquez sur **+** > **Text** > **Body**. 2. Avec l'élément body sélectionné, modifiez le texte dans le champ **Content** de l'onglet **Design**. ## 6. Ajoutez la liste de fonctionnalités \{#6-add-the-feature-list\} La liste de fonctionnalités met en avant ce qu'inclut le déverrouillage de l'abonnement. Chaque ligne comporte une icône, un titre de fonctionnalité et une courte description. Pour l'ensemble des presets de liste, consultez [Éléments — List](builder-elements#list). Pour ajouter la liste de fonctionnalités : 1. Cliquez sur **+** > **List** et choisissez un preset de liste. Icon List est le plus courant pour les paywalls. 2. Avec chaque ligne sélectionnée, modifiez le titre et la description dans le champ **Content**. 3. Pour ajouter ou supprimer des lignes, sélectionnez la liste et utilisez les contrôles de ligne dans le panneau **Layers**. ## 7. Ajoutez la liste de produits \{#7-add-the-product-list\} La liste de produits affiche les options d'abonnement parmi lesquelles l'utilisateur peut choisir. L'élément Products génère une carte par produit assigné à l'écran, et une carte est automatiquement désignée comme sélection par défaut. Pour en savoir plus sur la gestion des produits, consultez [Configurer les achats](paywall-product-block). Pour ajouter et configurer les produits : 1. Cliquez sur **+** > **Products** et choisissez un preset de mise en page. Vertical List est le plus courant. 2. Sélectionnez chaque carte produit sur le canvas et choisissez un produit dans le menu déroulant de l'onglet **Design**. Le menu déroulant affiche tous les produits configurés dans l'Adapty Dashboard. 3. Pour changer la sélection par défaut, sélectionnez la carte souhaitée et activez **Set as default product** dans l'onglet **Design**. 4. Pour personnaliser le badge de réduction, développez une carte produit dans le panneau **Layers**, sélectionnez le calque du badge et modifiez son texte dans le champ **Content**. Masquez le badge sur les autres cartes en cliquant sur l'icône œil Show à côté de chaque calque de badge. ## 8. Ajoutez le bouton d'achat \{#8-add-the-purchase-button\} Le bouton d'achat lance l'achat intégré pour le produit sélectionné par l'utilisateur. La variable `products.selectedProduct` correspond toujours au produit actuellement sélectionné sur l'écran. Pour ajouter le bouton d'achat : 1. Cliquez sur **+** > **Buttons** et choisissez un preset de bouton. 2. Avec le bouton sélectionné, ouvrez l'onglet **Interactions** dans le panneau droit. 3. Cliquez sur **Add trigger** > **On tap**, puis cliquez sur **Add action**. 4. Définissez **Action** sur **Purchase** et **Product** sur `products.selectedProduct`. ## 9. Ajoutez les liens du pied de page \{#9-add-footer-links\} Le pied de page contient des liens vers les conditions d'utilisation et la politique de confidentialité (requis par les stores) ainsi qu'un bouton pour restaurer les achats précédents. Pour ajouter les liens du pied de page : 1. Cliquez sur **+** > **Buttons** > **Links**. Cela ajoute une ligne avec Restore Purchases, Terms of Use et Privacy Policy. 2. Dans le panneau **Layers**, sélectionnez le bouton **Terms of Use**. Ouvrez l'onglet **Interactions** — l'action **Open URL** est déjà associée. Cliquez sur l'action et saisissez l'URL cible. 3. Répétez l'opération pour le bouton **Privacy Policy** avec votre URL de politique de confidentialité. 4. Laissez le bouton **Restore Purchases** tel quel. Son action est préconfigurée. :::tip Si le positionnement d'un élément vous semble trop haut ou trop bas, ou si vous souhaitez ajouter de l'espace quelque part, ajustez les marges et la marge interne de l'élément. ::: ## Étapes suivantes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: show-plans-bottom-sheet --- --- title: "Afficher tous les plans dans une feuille inférieure" description: "Créez un paywall hero avec un seul CTA, un lien « Afficher tous les plans » et une feuille inférieure qui révèle la liste complète des produits." --- Ce template met d'abord en avant une seule offre phare, avec un lien discret vers la liste complète des plans. En appuyant sur **Show all plans**, une feuille inférieure remonte et affiche les autres produits, un bouton d'achat et les liens du pied de page. Utilisez-le lorsqu'un plan convertit nettement mieux que les autres — la feuille inférieure garde les alternatives à portée d'un tap sans encombrer l'écran principal. ## Avant de commencer \{#before-you-start\} - [Créez des produits](create-product) dans l'Adapty Dashboard. - [Connectez Adapty à l'App Store et Google Play](integrate-payments). ## 1. Configurer la mise en page de l'écran \{#1-set-up-the-screen-layout\} Utilisez l'image hero comme arrière-plan de l'écran et regroupez le reste du contenu en bas, de sorte que l'image remplisse la partie supérieure de l'écran. Pour la liste complète des propriétés d'écran, consultez [Écrans et calques — Paramètres d'écran](paywall-layout-and-products#screen-settings). Pour configurer l'écran : 1. Cliquez sur une zone vide du canevas pour sélectionner l'écran. 2. Sous **System UI**, désactivez **Safe area** pour que l'image hero s'étende jusqu'aux bords de l'écran. 3. Sous **Fill**, choisissez **Image** Image et importez votre image hero. 4. Sous **Layout**, configurez la direction, l'espacement et l'alignement pour ancrer le contenu là où vous le souhaitez. Pour ce template, une direction **Vertical** Vertical avec un petit espacement et un alignement **bottom-middle** regroupe le titre et les boutons dans la partie inférieure de l'écran. ## 2. Ajouter le titre CTA \{#2-add-the-cta-heading\} Le titre se trouve dans la partie inférieure de l'écran, juste au-dessus du bouton d'abonnement. L'image hero remplit la zone au-dessus. 1. Cliquez sur **+** > **Text** > **H1**. 2. Avec le H1 sélectionné, ouvrez l'onglet **Design** et modifiez le texte dans le champ **Content**. ## 3. Ajouter la feuille inférieure et son titre \{#3-add-the-bottom-sheet-and-its-title\} La feuille inférieure est un conteneur de mise en page qui remonte depuis le bas de l'écran. Ajoutez-la visible pour l'instant — vous la remplirez dans les prochaines étapes et la masquerez une fois le contenu en place. Les éléments masqués ne peuvent pas être modifiés, donc la feuille doit rester visible jusqu'à ce que vous ayez fini de la remplir. Pour en savoir plus sur les feuilles inférieures et autres conteneurs de mise en page, consultez [Éléments — Layout](builder-elements#layout). Pour ajouter la feuille inférieure et son titre : 1. Cliquez sur **+** > **Layout** > **Bottom Sheet**. 2. Dans le panneau **Layers**, développez la feuille inférieure, sélectionnez le calque **Title** et modifiez le champ **Content** dans l'onglet **Design** — par exemple, `Choose your plan`. ## 4. Ajouter la liste de produits dans la feuille inférieure \{#4-add-the-product-list-inside-the-bottom-sheet\} Placez tous les produits à l'intérieur de la feuille inférieure. L'un d'eux alimentera également le prix affiché sur le bouton CTA principal. Pour en savoir plus sur la gestion des produits, consultez [Configurer les achats](paywall-product-block). Pour ajouter et configurer les produits : 1. Cliquez sur **+** > **Products** et choisissez un preset de mise en page. La liste verticale convient dans la plupart des cas. L'élément apparaît sur l'écran, en dehors de la feuille inférieure. 2. Dans le panneau **Layers**, faites glisser le calque Products dans le conteneur **Content** à l'intérieur de la feuille inférieure. 3. Sélectionnez chaque carte produit sur le canevas et choisissez un produit dans la liste déroulante de l'onglet **Design**. ## 5. Ajouter le bouton d'achat dans la feuille inférieure \{#5-add-the-purchase-button-inside-the-bottom-sheet\} La feuille inférieure a besoin de son propre bouton d'achat pour acquérir le plan sélectionné par l'utilisateur dans la liste. 1. Cliquez sur **+** > **Buttons** et choisissez un preset de bouton. 2. Dans le panneau **Layers**, faites glisser le nouveau bouton dans le conteneur **Content** à l'intérieur de la feuille inférieure. 3. Avec le bouton sélectionné, ouvrez l'onglet **Interactions** dans le panneau de droite. 4. Cliquez sur **Add trigger** > **On tap**, puis sur **Add action**. 5. Définissez **Action** sur **Purchase** et **Product** sur `products.selectedProduct`. ## 6. Ajouter les liens du pied de page dans la feuille inférieure \{#6-add-the-footer-links-inside-the-bottom-sheet\} :::important N'utilisez pas de [liens inline](onboarding-text#inline-link) pour du texte imbriqué dans des boutons. À la place, configurez l'action **Open URL** sur le bouton lui-même. ::: Les conditions d'utilisation, la politique de confidentialité et la restauration des achats se trouvent en bas de la feuille — l'écran principal reste ainsi épuré. 1. Cliquez sur **+** > **Buttons** > **Links**. Cela ajoute une ligne avec Restore Purchases, Terms of Use et Privacy Policy. 2. Dans le panneau **Layers**, faites glisser la ligne Links dans le conteneur **Content** à l'intérieur de la feuille inférieure. 3. Dans le panneau **Layers**, sélectionnez le bouton **Terms of Use**. Ouvrez l'onglet **Interactions** et collez l'URL de vos conditions dans le champ **Open URL**. 4. Répétez l'opération pour le bouton **Privacy Policy** avec l'URL de votre politique de confidentialité. 5. Laissez le lien **Restore Purchases** tel quel. Son action est préconfigurée. ## 7. Masquer la feuille inférieure \{#7-hide-the-bottom-sheet\} Une fois le contenu de la feuille en place, masquez-la pour qu'elle n'apparaisse pas sur l'écran par défaut. Les utilisateurs la révèleront en appuyant sur **Show all plans** à la dernière étape. Dans le panneau **Layers**, sélectionnez la feuille inférieure et définissez son état sur **Hide** Hide. La feuille reste dans l'arborescence des calques mais ne s'affiche plus sur le canevas. ## 8. Ajouter le bouton d'abonnement principal \{#8-add-the-main-subscribe-button\} Le bouton principal de l'écran abonne l'utilisateur au plan mensuel en un seul tap. Son libellé utilise la variable de prix du produit mensuel pour que le bouton reste synchronisé avec le produit. 1. Dans le panneau **Layers**, cliquez sur l'écran pour que les nouveaux éléments s'ajoutent à la racine, et non à l'intérieur de la feuille inférieure. 2. Cliquez sur **+** > **Buttons** et choisissez un preset de bouton. 3. Avec le bouton sélectionné, ouvrez l'onglet **Design** et placez le curseur dans le champ **Content**. Cliquez sur Variable icon et choisissez la variable de prix pour le produit principal. Entourez-la avec le reste du libellé — par exemple, `Subscribe for {price}/month`. 4. Passez à l'onglet **Interactions** et cliquez sur **Add trigger** > **On tap** > **Add action**. 5. Définissez **Action** sur **Purchase** et **Product** sur le produit souhaité. Contrairement au bouton de la feuille inférieure, celui-ci cible un produit spécifique plutôt que `products.selectedProduct`. ## 9. Ajouter le lien « Afficher tous les plans » \{#9-add-the-show-all-plans-link\} Un lien textuel sous le bouton d'abonnement révèle la feuille inférieure au tap. L'ajouter en tant qu'élément texte avec le style **Button Label** garde un aspect minimaliste tout en vous permettant d'y associer une action. Pour en savoir plus sur l'action Afficher/Masquer, consultez [Actions — Afficher/masquer des éléments](onboarding-actions#showhide-elements). Pour ajouter le lien : 1. Avec l'écran sélectionné dans le panneau **Layers**, cliquez sur **+** > **Text** > **Button Label**. 2. Avec l'élément texte sélectionné, modifiez le champ **Content** pour qu'il affiche `Show all plans`. 3. Ouvrez l'onglet **Interactions** et cliquez sur **Add trigger** > **On tap** > **Add action**. 4. Définissez **Action** sur **Show** et sélectionnez l'élément feuille inférieure dans la liste déroulante. ## Étapes suivantes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: paywall-with-tabs --- --- title: "Créer un paywall avec des onglets" description: "Créez un écran de paywall avec deux onglets qui alternent entre différentes listes de fonctionnalités, groupes de produits et actions d'achat." --- Ce template utilise des onglets pour alterner entre deux variantes de la même offre sur un seul écran. Chaque onglet contient sa propre liste de fonctionnalités, liste de produits et bouton d'achat. Appuyer sur un onglet change le contenu visible sans quitter l'écran — pratique pour diviser les plans par niveau, période de facturation ou segment d'audience. ## Avant de commencer \{#before-you-start\} - [Créez des produits](create-product) dans l'Adapty Dashboard. - [Connectez Adapty à l'App Store et Google Play](integrate-payments). ## 1. Configurer la mise en page de l'écran \{#1-set-up-the-screen-layout\} L'écran sert de conteneur pour le bouton de fermeture, le titre, les onglets et leur contenu. Dans cet exemple, l'arrière-plan est une image, mais une couleur unie ou un dégradé fonctionne de la même façon. Pour la liste complète des propriétés d'écran, voir [Écrans et calques — Paramètres de l'écran](paywall-layout-and-products#screen-settings). Pour configurer l'écran : 1. Cliquez sur une zone vide du canvas pour sélectionner l'écran. 2. Sous **System UI**, désactivez **Safe area** pour que l'arrière-plan s'étende jusqu'aux bords de l'écran. 3. Sous **Fill**, choisissez un type d'arrière-plan et configurez-le. Cet exemple utilise une **Image** Image, mais une couleur unie ou un dégradé fonctionne de la même façon. 4. Sous **Layout**, définissez la direction sur **Vertical** Vertical et configurez l'espacement et l'alignement pour que les éléments s'empilent depuis le haut, le contenu des onglets remplissant l'espace restant. ## 2. Ajouter le bouton de fermeture \{#2-add-the-close-button\} Le bouton de fermeture ferme le paywall. Le preset **Close** est préconfiguré — aucune configuration d'action n'est nécessaire. 1. Sur le canvas, cliquez sur **+**. 2. Sélectionnez **Buttons** > **Close**. ## 3. Ajouter le titre et le grouper avec le bouton de fermeture \{#3-add-the-title-and-pair-it-with-the-close-button\} Le titre se place à côté du bouton de fermeture en haut de l'écran. Pour les aligner horizontalement, enveloppez-les dans un conteneur horizontal. Pour ajouter le titre : 1. Cliquez sur **+** > **Text** > **H1**. 2. Avec le H1 sélectionné, ouvrez l'onglet **Design** et modifiez le texte dans le champ **Content**. Pour grouper le titre avec le bouton de fermeture : 1. Dans le panneau **Layers**, cliquez sur le menu trois points Context menu du calque du bouton de fermeture et choisissez **Wrap** > **Wrap in Horizontal Container**. 2. Faites glisser le calque H1 dans le nouveau conteneur horizontal. Pour aligner les deux éléments : 1. Ajustez la taille du bouton de fermeture et la taille de police du H1 pour qu'ils tiennent confortablement sur la même ligne. 2. Avec le conteneur horizontal sélectionné, définissez l'alignement et la distribution dans le panneau de droite pour que les éléments s'alignent correctement. ## 4. Ajouter les onglets et configurer leurs étiquettes \{#4-add-the-tabs-and-configure-their-labels\} L'élément Tabs divise une section de l'écran en panneaux de contenu commutables. Chaque onglet dispose de son propre conteneur de contenu qui s'affiche lorsque l'utilisateur sélectionne cet onglet. Pour en savoir plus sur l'élément Tabs, voir [Éléments — Tabs](builder-elements#tabs). Pour en savoir plus sur les groupes sélectionnables, voir [Éléments et groupes sélectionnables](flow-selectable-elements). Pour ajouter les onglets : 1. Cliquez sur **+** > **Tabs** et choisissez un preset — Segment control, Button Tabs ou Underline. 2. Avec le nom de chaque onglet sélectionné sur le canvas ou dans le panneau **Layers**, modifiez le champ **Content** dans l'onglet **Design** pour changer l'étiquette — par exemple, `Premium` et `Pro`. ## 5. Ajouter une liste de fonctionnalités au premier onglet \{#5-add-a-feature-list-to-the-first-tab\} Une liste de fonctionnalités courte et compacte dans le premier onglet indique aux utilisateurs ce que ce plan inclut. Pour l'ensemble des presets de liste, voir [Éléments — List](builder-elements#list). Pour ajouter la liste de fonctionnalités : 1. Cliquez sur **+** > **List** et choisissez un preset de liste. Icon List est le plus compact pour les paywalls. L'élément apparaît à la fin de l'arborescence des calques. 2. Avec chaque ligne sélectionnée, modifiez le titre dans le champ **Content**. 3. Dans le panneau **Layers**, faites glisser la liste dans le conteneur **Content** du premier onglet. ## 6. Ajouter la liste de produits au premier onglet \{#6-add-the-product-list-to-the-first-tab\} La liste de produits affiche les options d'abonnement du premier onglet. L'élément Products génère une carte par produit assigné à l'écran et crée son propre groupe sélectionnable. Pour en savoir plus sur la gestion des produits, voir [Configurer les achats](paywall-product-block). Pour ajouter et configurer les produits : 1. Cliquez sur **+** > **Products** et choisissez un preset de mise en page. Vertical List convient bien aux plans empilés. L'élément apparaît à la fin de l'arborescence des calques. 2. Sélectionnez chaque carte produit sur le canvas et choisissez un produit dans le menu déroulant de l'onglet **Design**. 3. Dans le panneau **Layers**, faites glisser le calque Products dans le conteneur **Content** du premier onglet. ## 7. Ajouter le bouton d'achat au premier onglet \{#7-add-the-purchase-button-to-the-first-tab\} Le bouton d'achat lance l'achat intégré pour le produit sélectionné par l'utilisateur dans le premier onglet. Son étiquette utilise le prix du produit sélectionné pour rester synchronisée avec le choix de l'utilisateur. Pour en savoir plus sur l'action Purchase, voir [Actions — Purchase](onboarding-actions#purchase). Pour ajouter et configurer le bouton d'achat : 1. Cliquez sur **+** > **Buttons** et choisissez un preset de bouton. L'élément apparaît à la fin de l'arborescence des calques. 2. Avec le bouton sélectionné, ouvrez l'onglet **Design** et placez le curseur dans le champ **Content**. Cliquez sur l'icône de variable Variable icon, sélectionnez `products.selectedProduct`, puis sélectionnez l'attribut `prod_price` — la variable complète est `products.selectedProduct.prod_price`. Entourez-la du reste de l'étiquette — par exemple, `Subscribe for {prod_price}`. 3. Passez à l'onglet **Interactions** et cliquez sur **Add trigger** > **On tap** > **Add action**. 4. Définissez **Action** sur **Purchase** et **Product** sur `products.selectedProduct`. 5. Dans le panneau **Layers**, faites glisser le bouton dans le conteneur **Content** du premier onglet. ## 8. Copier le contenu du premier onglet dans le second \{#8-copy-the-first-tabs-content-into-the-second-tab\} Plutôt que de reconstruire la même structure de zéro, copiez la liste de fonctionnalités, la liste de produits et le bouton d'achat du premier onglet dans le second. Vous n'aurez qu'à mettre à jour les valeurs ensuite. Pour copier le contenu : 1. Dans le panneau **Layers**, développez le conteneur **Content** du premier onglet. 2. Sélectionnez chaque élément à l'intérieur (liste de fonctionnalités, produits, bouton d'achat), copiez-le avec ⌘C / Ctrl+C, et collez-le avec ⌘V / Ctrl+V. Les copies apparaissent à la fin de l'arborescence des calques. 3. Faites glisser chaque élément copié dans le conteneur **Content** du second onglet. ## 9. Mettre à jour le contenu du second onglet \{#9-update-the-second-tabs-content\} Le second onglet reproduit maintenant le premier. Mettez à jour chaque élément pour qu'il reflète le second plan. Pour mettre à jour le second onglet : 1. Modifiez la liste de fonctionnalités dans le second onglet pour que les lignes correspondent aux fonctionnalités du second plan. 2. Sélectionnez chaque carte produit dans l'élément Products du second onglet et assignez les produits du second plan depuis le menu déroulant. Cet élément Products devient automatiquement un groupe sélectionnable distinct (`products2`). 3. Sélectionnez le bouton d'achat dans le second onglet. Dans le champ **Content** de l'onglet **Design**, changez la variable de prix de `products.selectedProduct.prod_price` en `products2.selectedProduct.prod_price`. 4. Passez à l'onglet **Interactions** et mettez à jour le **Product** de l'action **Purchase** de `products.selectedProduct` vers `products2.selectedProduct`. ## 10. Ajouter les liens du pied de page partagés \{#10-add-the-shared-footer-links\} Les conditions d'utilisation, la politique de confidentialité et la restauration des achats restent visibles quel que soit l'onglet actif. Ajoutez-les au niveau de l'écran — en dehors des deux conteneurs de contenu des onglets — pour qu'ils soient partagés entre les onglets. Pour ajouter les liens du pied de page : 1. Cliquez sur **+** > **Buttons** > **Links**. Cela ajoute une ligne avec Restore Purchases, Terms of Use et Privacy Policy à la fin de l'arborescence des calques, ce qui est exactement l'emplacement voulu — à la racine de l'écran, pas imbriqué dans un onglet. 2. Dans le panneau **Layers**, sélectionnez le bouton **Terms of Use**. Ouvrez l'onglet **Interactions** et collez l'URL de vos conditions dans le champ **Open URL**. 3. Répétez l'opération pour le bouton **Privacy Policy** avec votre URL de confidentialité. 4. Laissez le lien **Restore Purchases** tel quel. Son action est préconfigurée. ## Étapes suivantes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: paywall-features-per-product --- --- title: "Afficher des fonctionnalités différentes par produit" description: "Affichez une liste de fonctionnalités différente selon le produit sélectionné par l'utilisateur, grâce à la visibilité conditionnelle." --- Ce template utilise la visibilité conditionnelle pour mettre en avant des listes de fonctionnalités différentes selon les offres. L'écran affiche deux produits — par exemple, Pro et Pro+ — et une liste de fonctionnalités différente apparaît selon le produit sélectionné par l'utilisateur. Un produit est défini par défaut, de sorte que sa liste de fonctionnalités est visible dès le chargement de l'écran. ## Avant de commencer \{#before-you-start\} - [Créez des produits](create-product) dans l'Adapty Dashboard. - [Connectez Adapty à l'App Store et à Google Play](integrate-payments). ## 1. Configurez la mise en page de l'écran \{#1-set-up-the-screen-layout\} L'écran sert de conteneur pour tout ce que vous y ajoutez. Dans cet exemple, l'arrière-plan est une image, mais une couleur unie ou un dégradé fonctionnent de la même façon. Pour la liste complète des propriétés d'écran, consultez [Écrans et calques — Paramètres d'écran](paywall-layout-and-products#screen-settings). Pour configurer l'écran : 1. Cliquez sur une zone vide du canevas pour sélectionner l'écran. 2. Sous **System UI**, désactivez **Safe area** pour que l'arrière-plan s'étende jusqu'aux bords de l'écran. 3. Sous **Fill**, choisissez un type d'arrière-plan et configurez-le. Cet exemple utilise une **Image** Image, mais une couleur unie ou un dégradé fonctionnent de la même façon. 4. Sous **Layout**, définissez la direction sur **Vertical** Vertical et configurez l'espacement et l'alignement pour que les éléments s'empilent depuis le haut, le contenu occupant l'espace restant. ## 2. Ajoutez le bouton de fermeture \{#2-add-the-close-button\} Le bouton de fermeture permet de quitter le paywall. Le preset **Close** est préconfiguré — aucune configuration d'action n'est requise. 1. Sur le canevas, cliquez sur **+**. 2. Sélectionnez **Buttons** > **Close**. ## 3. Ajoutez le titre et associez-le au bouton de fermeture \{#3-add-the-title-and-pair-it-with-the-close-button\} Le titre se place à côté du bouton de fermeture en haut de l'écran. Pour les aligner horizontalement, enveloppez-les tous les deux dans un conteneur horizontal. Pour ajouter le titre : 1. Cliquez sur **+** > **Text** > **H1**. 2. Avec le H1 sélectionné, ouvrez l'onglet **Design** et modifiez le texte dans le champ **Content**. Pour regrouper le titre avec le bouton de fermeture : 1. Dans le panneau **Layers**, cliquez sur le menu à trois points Context menu du calque du bouton de fermeture et choisissez **Wrap** > **Wrap in Horizontal Container**. 2. Faites glisser le calque H1 dans le nouveau conteneur horizontal. Pour aligner les deux éléments : 1. Ajustez la taille du bouton de fermeture et la taille de police du H1 pour qu'ils tiennent confortablement sur la même ligne. 2. Avec le conteneur horizontal sélectionné, définissez l'alignement et la distribution dans le panneau de droite pour que les éléments s'alignent correctement. ## 4. Ajoutez la liste de produits \{#4-add-the-product-list\} Ajoutez les produits entre lesquels l'utilisateur peut choisir. Marquez-en un par défaut afin que l'écran ait un état cohérent dès le premier chargement. Pour en savoir plus sur la gestion des produits, consultez [Configurer les achats](paywall-product-block). Pour ajouter et configurer les produits : 1. Cliquez sur **+** > **Products** et choisissez un preset de mise en page. La liste verticale convient bien à ce template. 2. Sélectionnez chaque carte produit sur le canevas et choisissez un produit dans le menu déroulant de l'onglet **Design**. 3. Sélectionnez la carte que vous souhaitez sélectionnée par défaut — par exemple, Pro+ — et activez **Set as default product** dans l'onglet **Design**. ## 5. Ajoutez la liste de fonctionnalités du premier produit \{#5-add-the-feature-list-for-the-first-product\} La première liste de fonctionnalités décrit le produit par défaut. Elle n'est visible que lorsque l'utilisateur a sélectionné le premier produit. Pour en savoir plus sur la visibilité conditionnelle, consultez [Visibilité conditionnelle](onboarding-element-visibility). :::tip Plutôt que deux listes séparées, vous pouvez ajouter une seule liste et rendre les éléments texte à l'intérieur conditionnels, de façon qu'une seule liste s'adapte au produit sélectionné. Voir [Ajouter du texte conditionnel](onboarding-text#add-conditional-text). ::: Pour ajouter et configurer la liste de fonctionnalités : 1. Cliquez sur **+** > **List** et choisissez un preset de liste compacte. Icon List convient bien aux paywalls. 2. Avec chaque ligne sélectionnée, modifiez le titre dans le champ **Content** pour décrire les fonctionnalités du premier produit. 3. Avec la liste toujours sélectionnée, ouvrez l'onglet **Design**. Sous **Visibility**, sélectionnez **Conditional** Conditional. 4. Configurez la condition pour que la liste s'affiche uniquement lorsque le premier produit est celui actuellement sélectionné. Faites correspondre avec la variable `products.selectedProduct.prod_title`. Pour la **Value**, cliquez sur l'icône de variable `{}`, sélectionnez la première carte produit, puis son attribut `prod_title` — la comparaison se résout au titre de ce produit. ## 6. Ajoutez la liste de fonctionnalités du second produit \{#6-add-the-feature-list-for-the-second-product\} Répétez la même approche pour le second produit. Les deux listes sont mutuellement exclusives — une seule est visible à la fois, selon le produit sélectionné. Pour ajouter la seconde liste de fonctionnalités : 1. Cliquez sur **+** > **List** et choisissez le même preset compact pour la cohérence visuelle. 2. Modifiez chaque ligne pour décrire les fonctionnalités du second produit. 3. Sous **Visibility**, sélectionnez **Conditional** Conditional et configurez la même condition qu'à l'étape 5, mais pointez le sélecteur de variable **Value** sur le `prod_title` de la seconde carte produit. ## 7. Ajoutez le bouton d'achat \{#7-add-the-purchase-button\} Le bouton d'achat lance l'achat intégré pour le produit sélectionné par l'utilisateur. Son libellé utilise le prix du produit sélectionné, il se met donc à jour lorsque l'utilisateur change d'offre. Pour en savoir plus sur l'action Achat, consultez [Actions — Achat](onboarding-actions#purchase). Pour ajouter et configurer le bouton d'achat : 1. Cliquez sur **+** > **Buttons** et choisissez un preset de bouton. 2. Avec le bouton sélectionné, ouvrez l'onglet **Design** et placez le curseur dans le champ **Content**. Cliquez sur l'icône de variable Variable icon, sélectionnez `products.selectedProduct`, puis l'attribut `prod_price` — la variable complète se résout en `products.selectedProduct.prod_price`. Entourez-la du reste du libellé — par exemple, `Subscribe for {prod_price}`. 3. Passez à l'onglet **Interactions** et cliquez sur **Add trigger** > **On tap** > **Add action**. 4. Définissez **Action** sur **Purchase** et **Product** sur `products.selectedProduct`. ## 8. Ajoutez les liens du pied de page \{#8-add-the-footer-links\} Les conditions d'utilisation, la politique de confidentialité et la restauration des achats se trouvent sous le contenu principal. Pour ajouter les liens du pied de page : 1. Cliquez sur **+** > **Buttons** > **Links**. Cela ajoute une ligne avec Restore Purchases, Terms of Use et Privacy Policy à la fin de l'arborescence des calques. 2. Dans le panneau **Layers**, sélectionnez le bouton **Terms of Use**. Ouvrez l'onglet **Interactions** et collez l'URL de vos conditions dans le champ **Open URL**. 3. Répétez l'opération pour le bouton **Privacy Policy** avec votre URL de confidentialité. 4. Laissez le lien **Restore Purchases** tel quel. Son action est préconfigurée. ## Étapes suivantes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: show-offer-on-close --- --- title: "Afficher une offre quand les utilisateurs appuient sur Fermer" description: "Interceptez le premier appui sur Fermer pour afficher une offre de dernière chance avant que les utilisateurs ne quittent le paywall." --- Quand un utilisateur appuie sur le bouton Fermer, il est sur le point de partir sans acheter. Cette recette intercepte le premier appui sur Fermer : au lieu de fermer le paywall, elle affiche un overlay d'offre de dernière chance. Quand l'utilisateur ferme cet overlay, le bouton Fermer fonctionne normalement et clôt le flow. La logique repose sur une variable Boolean personnalisée et une action conditionnelle : - `close_tapped` commence à `False`. - Le premier appui sur Fermer affiche l'overlay d'offre et passe `close_tapped` à `True`. - Tout appui ultérieur sur Fermer clôt le flow. ## Avant de commencer \{#before-you-start\} - Créez un écran de paywall avec un bouton Fermer — par exemple, en suivant [Créer un écran de paywall de base](basic-paywall-screen). - [Créez un produit](create-product) avec une [offre](offers) à mettre en avant dans l'overlay. ## 1. Créer la variable \{#1-create-the-variable\} Pour en savoir plus sur les variables personnalisées, consultez [Variables](onboarding-variables#custom-variables). 1. Dans le panneau de gauche, cliquez sur l'icône **{ }** pour ouvrir **Variables**. 2. Dans l'onglet **Custom**, cliquez sur **+**. 3. Nommez la variable `close_tapped` et définissez **Value Type** sur **Boolean**. Laissez **Initial Value** sur **False**. 4. Cliquez sur **Create variable**. ## 2. Créer l'overlay d'offre \{#2-build-the-offer-overlay\} L'overlay est un conteneur qui se fixe à l'écran de l'appareil et s'affiche par-dessus le paywall. Construisez-le visible — les éléments masqués ne peuvent pas être modifiés, vous le cacherez à l'étape 4, une fois le contenu en place. 1. Cliquez sur **+** > **Layout** > **Vertical Container**. 2. Le conteneur étant sélectionné, ouvrez l'onglet **Design** et définissez **Position** sur **Fixed**. Réglez l'alignement horizontal sur **Left & Right** et l'alignement vertical sur **Top**. Il n'existe pas d'option de centrage vertical, saisissez donc un décalage en haut (par exemple `300`) pour rapprocher l'overlay du centre de l'écran. 3. Sous **Fill**, définissez un arrière-plan — une couleur unie ou une image. Le conteneur est transparent par défaut, donc sans remplissage le paywall reste visible sous l'overlay. 4. Ajoutez le contenu de l'offre. Le conteneur étant sélectionné dans le panneau **Layers**, cliquez sur **+** > **Text** > **H2**. Pour afficher le prix réduit, insérez des [variables d'offre](onboarding-variables#product-variables) comme `offer_price` dans le champ **Content**. 5. Cliquez sur **+** > **Products**, choisissez un preset de mise en page et faites-le glisser dans l'overlay. Sélectionnez la carte produit sur le canevas et choisissez le produit et l'offre dans l'onglet **Design**. 6. Cliquez sur **+** > **Buttons**, choisissez un preset de bouton et faites-le glisser dans l'overlay. Dans l'onglet **Interactions**, cliquez sur **Add trigger** > **On tap** > **Add action**, puis définissez **Action** sur **Purchase** et **Product** sur votre produit avec offre. ## 3. Ajouter le bouton de fermeture à l'overlay \{#3-add-the-dismiss-button-to-the-overlay\} L'overlay a besoin de son propre bouton de fermeture. Son action doit masquer l'overlay — et non fermer le flow. 1. L'overlay étant sélectionné, cliquez sur **+** > **Buttons** > **Close flow**. 2. Le bouton étant sélectionné, ouvrez l'onglet **Interactions**. Le preset est livré avec une action **Close Flow** préconfigurée. Cliquez sur l'action et changez son type en **Hide element**. Définissez la cible sur le conteneur de l'overlay. :::important Ne laissez pas l'action **Close Flow** préconfigurée sur le bouton de fermeture de l'overlay — elle fermerait le flow entier au lieu de masquer l'overlay. ::: ## 4. Masquer l'overlay \{#4-hide-the-overlay\} L'overlay doit rester invisible jusqu'au premier appui sur Fermer. Dans le panneau **Layers**, sélectionnez le conteneur de l'overlay et définissez son état sur **Hide** Hide. L'overlay reste dans l'arborescence des calques mais ne s'affiche plus sur le canevas. ## 5. Configurer le bouton Fermer \{#5-set-up-the-close-button\} Remplacez l'action par défaut du bouton Fermer par une action conditionnelle qui se branche sur `close_tapped`. Pour en savoir plus sur les actions conditionnelles, consultez [Actions — Actions conditionnelles](onboarding-actions#conditional-actions). 1. Sélectionnez le bouton Fermer du paywall — celui qui se trouve sur l'écran, pas le bouton de fermeture de l'overlay. 2. Ouvrez l'onglet **Interactions**, cliquez sur l'action **Close Flow** préconfigurée et changez son type en **Conditional Action**. 3. Dans le bloc **if**, cliquez sur **Add condition** et définissez : `close_tapped` **Equals** **False**. 4. Dans le bloc **then**, ajoutez deux actions : - **Set Variable** : définissez `close_tapped` sur **True**. - **Show element** : définissez la cible sur l'overlay d'offre. 5. Dans le bloc **else**, ajoutez une action **Close Flow**. Le premier appui sur Fermer affiche maintenant l'offre. Après que l'utilisateur a fermé l'overlay, un nouvel appui sur Fermer correspond à la branche **else** et clôt le flow. ## Étapes suivantes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: strikethrough-price --- --- title: "Afficher un prix barré avec un badge de réduction" description: "Barrez le prix mensuel à côté du prix mensuel effectif du plan annuel pour rendre la réduction visible d'un coup d'œil." --- Un prix barré à côté du vrai prix rend la réduction visible d'un coup d'œil. Cette recette retravaille une carte de produit annuel pour afficher ce que l'abonnement coûterait par mois avec le plan mensuel — barré — à côté du prix mensuel effectif du plan annuel, le tout surmonté d'un badge de réduction. Le formatage barré s'applique à un élément texte entier — vous ne pouvez pas barrer une variable à l'intérieur d'un texte plus grand. C'est pourquoi le prix barré vit dans son propre élément texte, côte à côte avec le prix réduit dans un conteneur horizontal. :::tip Si un prix « avant » gonflé pour le même produit suffit — par exemple, le double du prix actuel, barré — ajoutez plutôt l'élément [Old Price](onboarding-text#add-an-old-price) prêt à l'emploi. Cette recette couvre le cas où le prix barré est le vrai prix d'un autre produit. ::: ## Avant de commencer \{#before-you-start\} - Construisez un écran de paywall avec des produits — par exemple, en suivant [Créer un écran de paywall de base](basic-paywall-screen). Cette recette suppose que le paywall propose un produit annuel et un produit mensuel. ## 1. Empiler les lignes de prix \{#1-stack-the-price-rows\} La carte annuelle commence avec une seule ligne de prix — la variable `prod_price` du produit annuel suivie de `/year`, ce qui s'affiche par exemple comme `$29.99/year`. Ajoutez une deuxième ligne au-dessus pour la tarification mensuelle. 1. Dans le panneau **Layers**, sélectionnez le texte du prix à l'intérieur de la carte de produit annuel. Il se trouve déjà dans le conteneur vertical de la carte, donc la copie s'empilera en dessous. 2. Cliquez sur le menu à trois points Context menu sur le calque et choisissez **Duplicate**. La copie apparaît sous l'original. À l'étape suivante, le texte du haut devient la ligne de prix mensuel ; celui du bas conserve le prix annuel. ## 2. Diviser la ligne mensuelle en deux prix \{#2-split-the-monthly-row-into-two-prices\} La ligne mensuelle contient deux éléments texte : le prix barré du plan mensuel et le prix par mois du plan annuel. :::important Le sélecteur de variables ne propose que les prix des produits présents sur un écran du flow. Pour référencer un produit qui n'est pas dans le flow, créez un écran vide, ajoutez-y un élément **Products** et assignez-lui le produit. Assurez-vous qu'aucune action de navigation ne mène à cet écran. ::: 1. Sélectionnez l'élément texte du haut, cliquez sur son menu à trois points et choisissez **Wrap** > **Wrap in Horizontal Container**. 2. Cliquez sur le menu à trois points du calque texte à l'intérieur du nouveau conteneur et choisissez **Duplicate**. 3. Sélectionnez le premier élément texte et effacez son champ **Content**. Cliquez sur l'icône de variable Variable icon, choisissez le produit mensuel, puis son attribut `prod_price_per_month`. Tapez `/month` après la variable. 4. Dans l'onglet **Design**, sous **Typography**, réglez **Decoration** sur **Strikethrough** Strikethrough (voir [Styles et apparence — Decoration](builder-styling#decoration)). 5. Sélectionnez le second élément texte et remplacez son contenu de la même manière, mais choisissez l'attribut `prod_price_per_month` du produit annuel. Tapez `/month` après la variable. ## 3. Atténuer le prix annuel \{#3-tone-down-the-yearly-price\} Les prix mensuels dupliqués ont hérité du style du prix original, donc les trois prix partagent actuellement la même taille et la même graisse. Rendez le prix annuel plus discret pour que la ligne mensuelle ressorte davantage. 1. Sur le canevas, sélectionnez l'élément texte du bas — le prix annuel. 2. Dans la barre d'outils au-dessus de l'élément, ouvrez le menu déroulant des styles de texte et choisissez un style plus discret — par exemple, **Caption**. Ou sélectionnez un style différent sous **Typography** dans l'onglet **Design**. ## 4. Ajouter le badge de réduction \{#4-add-the-discount-badge\} Le badge met en valeur l'économie réalisée à côté des prix. 1. Cliquez sur **+** > **Badge**. 2. Dans le panneau **Layers**, faites glisser le badge à l'intérieur du produit annuel, entre le conteneur vertical avec les prix et le bouton radio. 3. Sélectionnez le calque texte du badge et modifiez le champ **Content** — par exemple, `Save 75%`. Il n'existe pas de variable pour le pourcentage de réduction — calculez-le à partir de vos prix et saisissez-le comme texte statique. La carte annuelle ancre désormais son prix par rapport au plan mensuel : le prix mensuel barré, le prix mensuel effectif du plan annuel et le badge de réduction se trouvent sur une même ligne, avec le prix annuel complet en dessous. ## Étapes suivantes \{#next-steps\} - [Enregistrer et publier votre flow](builder-save-publish). - [Ajouter le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. --- # File: onboarding-flow-tutorial --- --- title: "Créer un onboarding personnalisé" description: "Parcourez le processus complet de création d'un onboarding multi-écrans — écrans, contenu, navigation et branchements conditionnels — à travers un exemple concret." --- Un flow multi-écrans dans le Flow Builder est une séquence d'écrans reliés par des actions de navigation. Le flow peut rester linéaire ou se ramifier selon les réponses de l'utilisateur collectées sur un écran précédent. Ce tutoriel couvre le processus de bout en bout — création des écrans, construction du contenu, câblage de la navigation et ajout de branchements conditionnels — en prenant comme exemple un onboarding en quatre écrans. L'exemple utilise : - Une **saisie de prénom** qui expose le prénom de l'utilisateur comme variable pour la personnalisation. - Un **quiz à choix unique** dont la réponse détermine quel écran l'utilisateur voit ensuite. - **Deux chemins de branchement** avec des textes adaptés à chaque segment d'audience. - Un **paywall** comme écran final. Ce même schéma s'applique à tout flow qui personnalise le contenu selon les saisies de l'utilisateur. Vous préférez la vidéo ? Ce tutoriel de démarrage rapide couvre le même processus de bout en bout : <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aa-m459VIuY?si=zN_Co6B6qB88UPZP" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Avant de commencer \{#before-you-start\} - [Créez des produits](create-product) dans l'Adapty Dashboard. L'exemple de flow en utilise deux — un abonnement Annuel et un Mensuel. - [Connectez Adapty à l'App Store et Google Play](integrate-payments). ## 1. Configurer les styles réutilisables \{#1-set-up-reusable-styles\} Les styles réutilisables vous permettent d'appliquer une typographie et des couleurs cohérentes sur tous les écrans en un seul clic. Les styles de couleur comportent une variante Claire et une variante Sombre, de sorte que le flow prend automatiquement en charge les deux thèmes. Pour les instructions complètes, consultez [Styles et apparence — Styles réutilisables](builder-styling#reusable-styles). Pour configurer les styles : 1. Dans le panneau gauche, ouvrez le panneau **Styles** Styles. 2. Dans l'onglet **Colors**, cliquez sur **Plus Create style** et ajoutez les couleurs que vous souhaitez réutiliser. Pour chaque couleur, choisissez une valeur Claire, passez à l'onglet Dark et choisissez une valeur Sombre. 3. Dans l'onglet **Text**, cliquez sur un style existant pour modifier sa police, sa graisse et sa taille, ou cliquez sur **Plus Create style** pour ajouter des préréglages personnalisés. ## 2. Créer les écrans \{#2-create-the-screens\} Un flow est une séquence d'écrans. Configurez le premier écran avec la base commune — mise en page, arrière-plan et zone de sécurité — puis dupliquez-le pour les autres. Ainsi, tous les écrans partagent la même fondation et vous ne la configurez qu'une seule fois. Pour en savoir plus sur la gestion des écrans, consultez [Écrans et calques — Gérer les écrans](paywall-layout-and-products#manage-screens). Pour configurer les écrans : 1. Cliquez sur une zone vide du canevas du premier écran pour ouvrir ses paramètres. 2. Sous **System UI**, désactivez **Safe area** pour que les arrière-plans et les éléments alignés sur les bords puissent s'étendre jusqu'aux bords de l'écran. 3. Sous **Fill**, choisissez un type d'arrière-plan et configurez-le — par exemple, une **Image** Image qui s'affiche derrière chaque écran du flow. 4. Sous **Layout**, définissez la direction sur **Vertical** Vertical et choisissez une distribution adaptée à votre design. 5. Dans la section **Screens** du panneau gauche, cliquez sur le menu à trois points Context menu du premier écran et choisissez **Duplicate**. Répétez l'opération jusqu'à avoir quatre écrans au total — le deuxième chemin de branchement sera ajouté plus tard en dupliquant le premier. 6. Renommez chaque écran selon son rôle — dans notre exemple : `Welcome`, `Quiz`, `Rock path` et `Paywall`. ## 3. Construire l'écran d'introduction \{#3-build-the-introduction-screen\} Le premier écran donne généralement le ton — un titre, une liste de fonctionnalités et un appel à l'action qui ouvre la suite du flow. Dans notre exemple, il s'agit de l'écran Welcome. Cliquez sur l'écran **Welcome** dans le panneau **Screens**, puis ajoutez les éléments : 1. Ajoutez l'image principale. Cliquez sur **+** > **Media** > **Image**, téléversez votre image et ajustez les marges si nécessaire. 2. Ajoutez un titre : cliquez sur **+** > **Text**, choisissez un style de titre parmi vos styles de texte enregistrés et modifiez le champ **Content**. 3. Ajoutez la liste de fonctionnalités. Cliquez sur **+** > **List** > **Icon Cards**, puis modifiez l'icône et le libellé de chaque carte. 4. Ajoutez un bouton de navigation principal en bas. Il recevra une action lors de l'étape de navigation. ## 4. Construire l'écran de saisie et de quiz \{#4-build-the-input-and-quiz-screen\} Le deuxième écran collecte des informations auprès de l'utilisateur. Dans notre exemple, il demande un prénom et une réponse à choix unique qui détermine quel chemin l'utilisateur verra ensuite. Pour en savoir plus sur les saisies et les quiz, consultez [Saisies et formulaires](builder-inputs-and-forms) et [Sondages et quiz](onboarding-quizzes). Cliquez sur l'écran **Quiz** dans le panneau **Screens**, puis ajoutez les éléments. Chaque groupe sur l'écran — intro, question + saisie, question + quiz — est placé dans son propre Conteneur Vertical pour que les éléments associés restent groupés visuellement. 1. Ajoutez le titre et le corps de l'intro. Cliquez sur **+** > **Text** > **H1** pour le titre et **+** > **Text** > **Body** pour le texte d'accompagnement. 2. Groupez l'intro. Cliquez sur **+** > **Layout** > **Vertical Container**, faites glisser le nouveau conteneur en haut de l'arborescence des calques, puis faites glisser le H1 et le corps à l'intérieur. 3. Ajoutez la première question et la saisie. Cliquez sur **+** > **Text** pour la légende de la question, puis cliquez sur **+** > **Inputs** > **Text** pour le champ. 4. Définissez l'**Element ID** de la saisie dans l'onglet **Design** — dans notre exemple, `name`. Cela expose la valeur comme variable référençable par les autres écrans. 5. Groupez la légende et la saisie dans un Conteneur Vertical de la même façon que l'intro. 6. Ajoutez la deuxième question et le quiz. Cliquez sur **+** > **Text** pour la légende, puis cliquez sur **+** > **Quiz** et choisissez un préréglage de mise en page comme Icon Options. Configurez les options — dans notre exemple, `Rock` et `Hip hop`. 7. Groupez la légende et le quiz dans un Conteneur Vertical de la même façon. 8. Définissez les ID des options. Sélectionnez chaque option du quiz, ouvrez l'onglet **Interactions** et définissez son **Element ID**. Ces ID sont référencés dans la navigation conditionnelle plus tard. 9. Passez le quiz en choix unique : cliquez sur une zone vide du canevas pour ouvrir les **Screen settings**, faites défiler jusqu'à **Selectable Groups**, cliquez sur le nom du groupe du quiz et définissez le type sur **Single choice**. 10. Ajoutez un bouton principal en bas — c'est le bouton Suivant qui déclenche le branchement. ## 5. Construire le premier chemin de branchement \{#5-build-the-first-branching-path\} Chaque écran de chemin adapte le contenu à un segment d'audience. Dans notre exemple, le chemin Rock propose du contenu axé rock — playlists, artistes et recommandations. Pour en savoir plus sur les variables, consultez [Variables](onboarding-variables). Pour construire l'écran : 1. Dans le panneau **Screens**, cliquez sur l'écran **Rock path**. 2. Ajoutez un titre. Placez le curseur dans le champ **Content** à l'endroit où la personnalisation doit apparaître, cliquez sur l'icône de variable Variable icon et ouvrez l'onglet **Elements**. Choisissez l'écran où se trouve la saisie — dans notre exemple, **Quiz** — puis sélectionnez la variable de valeur de la saisie. Le sélecteur la résout sous la forme `<elementId>.value` — dans notre exemple, `name.value`. Au moment de l'exécution, le titre se met à jour avec ce que l'utilisateur a saisi. 3. Ajoutez le texte du corps comme éléments de texte supplémentaires, adaptés au segment d'audience de ce chemin. 4. Ajoutez un bouton principal en bas. ## 6. Construire le deuxième chemin de branchement \{#6-build-the-second-branching-path\} Les écrans de chemin partagent généralement une mise en page — seul le texte change. Dupliquez le premier écran de chemin et mettez le contenu à jour. Pour dupliquer et mettre à jour : 1. Dans le panneau **Screens**, sélectionnez le premier écran de chemin et appuyez sur ⌘D / Ctrl+D pour le dupliquer. La copie apparaît à la fin de la liste des écrans. 2. Renommez la copie — dans notre exemple, `Hip hop path` — et faites-la glisser à la bonne position dans la liste des écrans, de sorte qu'elle soit à côté de l'écran dont elle a été dupliquée. 3. Mettez à jour le texte du corps pour l'autre segment d'audience. Le titre personnalisé continue de fonctionner — la variable est conservée. ## 7. Construire le paywall \{#7-build-the-paywall\} Le dernier écran est le paywall — là où l'utilisateur peut s'abonner. Pour un guide plus complet des mécaniques de paywall, consultez [Créer un écran de paywall basique](basic-paywall-screen). La version ci-dessous condense ce guide. Cliquez sur l'écran **Paywall** dans le panneau **Screens**, puis ajoutez les éléments : 1. Ajoutez un **Horizontal Container** en haut et insérez un bouton **Close** à l'intérieur. Le préréglage Close est préconfiguré. 2. Ajoutez l'image principale, le titre (avec la même variable de personnalisation que sur les écrans de chemin) et un sous-titre comme texte d'accompagnement. 3. Ajoutez les produits : cliquez sur **+** > **Products** et choisissez **Vertical List**. Assignez à chaque carte un produit depuis le menu déroulant dans l'onglet **Design**. 4. Cliquez sur la carte du produit par défaut et activez **Set as default product** pour qu'il soit présélectionné au chargement de l'écran. 5. Ajoutez le bouton d'achat. Cliquez sur **+** > **Buttons** et choisissez un préréglage. Dans l'onglet **Interactions**, cliquez sur **Add trigger** > **On tap** > **Add action** et définissez **Action** sur **Purchase** avec **Product** comme `products.selectedProduct`. 6. Ajoutez le template **Button** > **Links** à l'écran. Il comprend trois liens de pied de page : Restore Purchases, Terms of Use et Privacy Policy. Le lien Restore est préconfiguré. Pour configurer les autres liens, sélectionnez l'élément bouton, ouvrez l'onglet **Interactions** et définissez la cible pour l'action **Open URL**. ## 8. Câbler la navigation entre les écrans \{#8-wire-navigation-between-the-screens\} Les écrans ne se connectent pas automatiquement les uns aux autres. Utilisez des déclencheurs **On tap** et des actions **Navigate to** pour relier le bouton principal de chaque écran à l'écran suivant. Un écran qui se branche selon les saisies de l'utilisateur utilise une **Conditional action** à la place. Pour en savoir plus sur la navigation et les actions conditionnelles, consultez [Navigation et interaction](onboarding-navigation-branching) et [Actions — Actions conditionnelles](onboarding-actions#conditional-actions). Pour câbler la navigation dans l'exemple de flow : 1. **Navigation statique depuis l'écran d'introduction.** Ouvrez l'écran Welcome, sélectionnez le bouton principal et passez à l'onglet **Interactions**. Cliquez sur **Add trigger** > **On tap** > **Add action**, définissez **Action** sur **Navigate to** et choisissez l'écran suivant — dans notre exemple, l'écran Quiz. 2. **Navigation conditionnelle depuis le quiz.** Ouvrez l'écran Quiz, sélectionnez le bouton Suivant et ajoutez un déclencheur **On tap** avec une **Conditional action**. Configurez la règle IF/ELSE : - Dans le sélecteur de variable, ouvrez l'onglet **Elements**, choisissez l'écran **Quiz** et sélectionnez `quiz.selectedOptionId`. - Utilisez l'opérateur **Equals** et comparez avec l'ID d'une des options — dans notre exemple, l'option Rock. - **IF** la comparaison correspond, déclenchez **Navigate to** et choisissez le premier écran de chemin. - **ELSE**, déclenchez **Navigate to** et choisissez le deuxième écran de chemin. 3. **Navigation statique depuis chaque chemin de branchement vers le paywall.** Répétez le schéma de l'étape 1 sur chaque écran de chemin, avec le paywall comme destination. ## Prochaines étapes \{#next-steps\} - [Enregistrez et publiez votre flow](builder-save-publish). - [Ajoutez le flow à un placement](create-placement) pour commencer à le montrer aux utilisateurs. - Pour des flows spécifiques à une audience (au lieu de branchements dans le flow), créez des segments d'audience et assignez différents flows sur la page Placement. :::link Vous souhaitez en savoir plus sur la création de flows ? Regardez les tutoriels vidéo étape par étape dans notre [playlist YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM). ::: --- # File: migrate-to-flows --- --- title: "Migrer vers les flows" description: "Regroupez votre onboarding et votre paywall dans un seul flow Adapty — ce qui change et comment le déployer sans perturber les utilisateurs sur des versions d'application plus anciennes." --- Dans Adapty, un *flow* regroupe un onboarding et un paywall en une seule entité rattachée à un placement. Un flow remplace l'onboarding et le paywall distincts que vous construisez et servez séparément aujourd'hui. Ce guide explique ce qui change lors du passage aux flows et comment déployer ce changement sans perturber les utilisateurs sur des versions d'application plus anciennes. :::important Les flows sont actuellement pris en charge sur iOS, Android, React Native, Flutter et Capacitor SDK v4 et versions ultérieures. La prise en charge d'autres plateformes et frameworks arrive prochainement. ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/8Cby6lVGI0o?si=rYA1HtdayyF1ffWd" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Flows vs. onboardings et paywalls \{#flows-vs-onboardings-and-paywalls\} Avec des onboardings et des paywalls séparés, vous gérez deux builders et deux placements. Vous devez aussi transférer les utilisateurs de l'onboarding au paywall dans votre propre code. Un flow remplace les deux par une expérience unique — écrans d'introduction, quiz et écran d'achat — créée dans un seul éditeur et servie depuis un seul placement. Le tableau ci-dessous compare ce que chaque option vous offre : | | Flow | Paywall Builder paywall | Onboarding | |---|---|---|---| | Plusieurs écrans | Oui | Non — écran unique | Oui | | Rendu | Natif | Natif | WebView | | Produits et placement | Un placement ; vous ajoutez les produits directement au flow | Un placement ; vous ajoutez les produits directement au paywall | Un placement, mais sans produits propres — pour vendre, vous créez un paywall séparé et le servez depuis son propre placement | ## Devez-vous migrer ? \{#should-you-migrate\} Vos onboardings et paywalls existants continuent de fonctionner, et Adapty continue de les prendre en charge. Les nouvelles fonctionnalités, en revanche, sont désormais publiées dans les flows plutôt que dans les builders d'onboarding et de paywall indépendants. **Si vous construisez sur le long terme, les flows sont une meilleure base** — migrez vers eux quand cela s'intègre à votre calendrier de publication. ## Comment migrer \{#how-to-migrate\} La migration comporte quatre étapes. L'essentiel du travail est une mise à niveau unique du SDK — la création et la prévisualisation du flow se font sans code. 1. **[Créez votre flow](#build-your-flow)** : Créez un flow dans l'éditeur no-code ; aucun développeur nécessaire. 2. **[Prévisualisez sur un appareil](#preview-on-device)** : Vérifiez le flow sur un vrai appareil via l'application mobile Adapty ; aucune build d'application nécessaire. 3. **[Créez un nouveau placement pour votre flow](#create-a-new-placement-for-your-flow)** : Créez un nouveau placement de flow avec son propre identifiant unique, et décidez comment il coexiste avec vos placements existants. 4. **[Mettez à jour le SDK](#update-the-sdk)** : Passez au SDK iOS, Android, React Native ou Capacitor v4, récupérez le flow depuis son placement, et vérifiez un achat sandbox. C'est la principale tâche du développeur. ### Créez votre flow \{#build-your-flow\} Sur la page **Flows**, cliquez sur **Create flow** pour commencer à créer votre onboarding et votre paywall en une seule expérience. Pour en savoir plus sur le builder : - **[Documentation sur les flows](adapty-flow-builder)** : vous guide à travers le builder et ce que vous pouvez créer. - **[Recettes de flows courantes](flow-builder-recipes)** : guides pas à pas pour les écrans les plus courants. - **Ask AI** : utilisez le chat sur n'importe quelle page de la documentation en cas de blocage. :::note La création d'un flow à partir d'un modèle prêt à l'emploi ou par génération avec l'IA n'est pas encore disponible — ces deux options arrivent prochainement. Pour l'instant, chaque nouveau flow démarre avec plusieurs écrans couramment utilisés que vous pouvez modifier et styliser selon vos besoins. ::: ### Aperçu sur appareil \{#preview-on-device\} Vous pouvez prévisualiser le flow sur un vrai appareil sans toucher au code de l'application. Téléchargez l'application mobile Adapty pour [iOS](https://apps.apple.com/us/app/adapty/id6739359219) ou [Android](https://play.google.com/store/apps/details?id=io.adapty.dashboard). Ensuite, dans le flow builder, cliquez sur **Test on device**, choisissez une locale et scannez le QR code avec votre appareil. Vous verrez les vrais écrans, les branchements, les textes et le design. :::note En mode aperçu, Adapty ne peut pas accéder à vos produits dans les stores, donc les prix affichés dans l'aperçu ne sont pas réels. Les vrais achats sont vérifiés plus tard, dans le build v4 avec un compte sandbox — voir [Mettre à jour le SDK](#update-the-sdk). ::: ### Créer un nouveau placement pour votre flow \{#create-a-new-placement-for-your-flow\} Un placement ne sert qu'un seul type de contenu — un flow, un paywall ou un onboarding. Vous ne pouvez pas convertir un placement onboarding ou paywall existant en placement flow (voir [types de placement](create-placement)). Un flow a besoin de son propre nouveau placement. **Donnez au nouveau placement flow un identifiant de placement entièrement nouveau et unique.** Il ne peut pas correspondre ni réutiliser l'identifiant d'un placement paywall ou onboarding existant. :::warning Conservez vos anciens placements actifs pendant la transition Les utilisateurs sur d'anciennes versions de l'application ont les identifiants de vos placements onboarding et paywall compilés dans l'app. Ils continuent d'appeler les méthodes onboarding et paywall et voient votre onboarding et paywall existants jusqu'à ce qu'ils mettent à jour. Ne retirez les anciens placements qu'une fois que l'adoption du SDK v4 est suffisamment élevée. ::: Vous n'avez pas besoin de migrer tous vos emplacements vers les flows en une seule fois. Dans le SDK v4, la méthode `getFlow` récupère les données aussi bien depuis les placements de flows que depuis les placements de paywalls, donc votre application utilise la même méthode partout. Conservez vos paywalls Paywall Builder dans les placements où vous le souhaitez, et utilisez les flows pour le reste. Pendant la transition, chaque type de placement suit ses propres métriques. Tant que les anciennes et nouvelles versions de l'application sont actives, vos données se répartissent entre deux ensembles de placements. Les anciens placements d'onboarding et de paywall couvrent les versions antérieures ; le nouveau placement de flow couvre le SDK v4+. Comparez-les comme des cohortes distinctes, et attendez-vous à ce que la part du placement de flow augmente au fur et à mesure que les utilisateurs mettent à jour. Vous pouvez continuer à faire des tests A/B avec les flows : lancez un [test A/B classique](ab-tests) entre des variantes de flow sur un placement de flow. Les tests A/B cross-placement ne sont actuellement disponibles que pour les paywalls, il n'est donc pas encore possible d'en lancer un sur des placements de flow. Comparer un nouveau flow avec votre ancien paywall est une comparaison de cohortes, pas un test unique — ils appartiennent à des types de placement différents. ### Mettre à jour le SDK \{#update-the-sdk\} Une fois votre placement de flow prêt, reliez l'application à celui-ci. Les flows ne s'affichent qu'avec le SDK Adapty v4 ou ultérieur. Mettez à jour le SDK et récupérez le flow depuis votre nouveau placement avec `getFlow`. Consultez le guide de migration vers la v4 pour votre plateforme — [iOS](migration-to-ios-sdk-v4), [Android](migration-to-android-sdk-v4), [React Native](migration-to-react-native-sdk-v4) ou [Capacitor](migration-to-capacitor-sdk-v4) — pour les étapes détaillées de mise à jour. Une fois le flow intégré, vérifiez-le comme n'importe quel autre flux d'achat : lancez-le sur un appareil ou un simulateur et effectuez un achat sandbox ([iOS](ios-test) / [Android](testing-on-android)) pour confirmer que les produits, l'achat et le niveau d'accès fonctionnent correctement. :::note Les utilisateurs voient les flows uniquement après avoir installé l'application compilée avec le SDK v4+. Les personnes sur une version plus ancienne continuent à voir votre onboarding et votre paywall existants, c'est pourquoi les anciens placements restent actifs pendant la transition. Il en va de même pour les plateformes qui ne prennent pas encore en charge les flows. ::: --- # File: paywall-layout-and-products --- --- title: Écrans et calques description: "Gérez les écrans et la hiérarchie des éléments dans chaque écran du Flow Builder." --- Un flow est composé d'un ou plusieurs écrans. Chaque écran représente une étape du parcours utilisateur — par exemple, un paywall, un quiz ou une diapositive présentant des informations sur un produit. Les éléments de chaque écran sont organisés selon une hiérarchie de calques. Pour gérer vos écrans, calques et éléments, ouvrez la vue **Screens and Layers** par défaut. Elle affiche la séquence de vos écrans ainsi que la structure des calques de chaque écran. ## Gérer les écrans \{#manage-screens\} La partie supérieure du panneau gauche liste tous les écrans du flow. Chaque entrée affiche un libellé numéroté et un aperçu miniature. * **Sélectionner un écran** : Cliquez sur une entrée pour la rendre active. L'éditeur visuel affiche l'écran sélectionné et la section Calques en dessous se met à jour pour montrer sa hiérarchie de calques. * **Ajouter un écran** : Cliquez sur le bouton Plus en haut de la section Screens pour ajouter un nouvel écran vide au flow. * **Ouvrir la bibliothèque de templates** : Cliquez sur le bouton Templates en haut de la section Screens pour parcourir et appliquer des [templates de flow](paywall-builder-templates). * **Réorganiser les écrans** : Faites glisser-déposer les entrées pour modifier leur ordre dans le flow. :::important Si votre flow contient des écrans vides inutilisés, la publication sera impossible. Supprimez les écrans brouillons avant de publier. ::: ### Actions sur les écrans \{#screen-actions\} Cliquez sur l'icône à trois points Context d'une entrée d'écran pour ouvrir le menu contextuel. | Action | Raccourci | Description | |--------|----------|-------------| | **Play Animation** | | Prévisualiser les animations configurées sur cet écran | | **Copy** | ⌘C / Ctrl+C | Copier l'écran dans le presse-papiers | | **Paste here** | ⌘V / Ctrl+V | Coller un écran précédemment copié | | **Duplicate** | ⌘D / Ctrl+D | Créer une copie de l'écran et l'ajouter au flow | | **Rename** | | Modifier le nom d'affichage de l'écran | | **Delete** | ⌘⌫ / Ctrl+Del | Supprimer l'écran du flow | :::tip Le presse-papiers est partagé entre les flows. Copiez un écran ou un élément depuis un flow, ouvrez un autre flow et collez-le. ::: :::warning Lorsque vous supprimez un écran, toute action [Navigate to Screen](onboarding-navigation-branching) qui pointait vers lui **perd sa cible**, mais l'action elle-même **n'est pas supprimée**. Assignez une nouvelle destination ou supprimez l'action — sinon, vous ne pourrez pas [prévisualiser ni publier le flow](builder-save-publish#publish-a-flow). ::: ## Naviguer entre les écrans \{#navigate-between-screens\} :::link Article principal : [Navigation et interaction](onboarding-navigation-branching) ::: L'ordre des écrans dans la liste ne détermine pas la navigation par lui-même. Pour relier les écrans, utilisez les interactions des éléments : configurez un bouton pour diriger l'utilisateur vers un autre écran. ## Paramètres de l'écran \{#screen-settings\} Pour afficher les propriétés et paramètres de l'écran actif, cliquez sur une zone vide de l'aperçu de l'écran. Le panneau droit basculera vers la vue des paramètres de l'écran. ### Interface système \{#system-ui\} Contrôle la façon dont l'écran interagit avec le matériel de l'appareil. * **Safe area** ajoute un espacement qui maintient le contenu à l'écart de l'encoche et des barres système. Les éléments positionnés individuellement peuvent désactiver cet espacement — voir [Ignore safe area](manage-paywall-ui-elements#ignore-safe-area). * **Status bar** affiche ou masque la barre d'état système (heure, batterie, signal). ### Inclure l'écran dans l'indicateur de progression \{#include-screen-in-progress-indicator\} Si vous ajoutez un élément [Progress Indicator](builder-loaders-and-progress-bars#progress-indicators) à votre flow, Adapty l'affiche sur chaque écran. Décochez **Include screen in progress indicator** pour retirer l'indicateur de progression d'un écran particulier. Utilisez cette option pour soigner l'affichage des écrans de bienvenue, du paywall final ou de toute étape que vous ne souhaitez pas comptabiliser comme progression. ### Mise en page de l'écran \{#screen-layout\} :::link Article complet : [Mise en page et positionnement](manage-paywall-ui-elements) ::: La section **Layout** détermine comment l'écran distribue ses éléments enfants. Ces propriétés sont disponibles sur tout élément conteneur. * **Free** : Les éléments enfants sont positionnés de façon indépendante. * **Vertical** : Les éléments sont disposés de haut en bas, comme une colonne flexbox. * **Horizontal** : Les éléments sont disposés de gauche à droite, comme une rangée flexbox. Pour les mises en page verticales et horizontales, vous pouvez également configurer l'espacement et l'alignement. * **Alignment** : Position des éléments sur l'axe transversal. * **Gap** : Espace entre les éléments adjacents. * **Distribution** : Répartition de l'espace entre les éléments enfants et autour d'eux. #### Mise en page RTL \{#rtl-layout\} Cochez la case **Mirror for RTL** pour inverser la mise en page pour les systèmes d'écriture allant de droite à gauche. L'ordre des éléments dans les conteneurs horizontaux sera retourné. ### Arrière-plan de l'écran \{#screen-background\} :::link Article principal : [Arrière-plans](paywall-head-picture) ::: **Fill** définit l'[arrière-plan de l'écran](paywall-head-picture) avec une couleur unie, un dégradé, une image ou une vidéo. L'arrière-plan couvre l'intégralité de la zone d'affichage de l'appareil, y compris les zones derrière l'encoche et les barres système — même lorsque **Safe area** est activé. #### Boucle de la vidéo d'arrière-plan \{#loop-background-video\} Activez le bouton **Loop** pour lire la vidéo d'arrière-plan en boucle continue. #### Assigner un identifiant média personnalisé \{#assign-a-custom-media-id\} Comme pour [toute image ou vidéo](custom-media), vous pouvez assigner un identifiant média personnalisé à l'arrière-plan de l'écran pour le référencer dans votre SDK. ### Espacement de l'écran \{#screen-spacing\} Ajuste le padding de l'écran pour chaque côté (haut, droite, bas, gauche). ### Défilement \{#scroll\} Contrôle le comportement en cas de débordement. Activez **Vertical scroll** pour permettre au contenu de l'écran de défiler lorsqu'il dépasse la hauteur de la zone d'affichage. :::link Utilisez un [Footer](builder-containers#footer) pour ancrer du contenu en bas de l'écran lorsque celui-ci déborde. ::: ### Groupes sélectionnables \{#selectable-groups\} :::link Article principal : [Éléments et groupes sélectionnables](flow-selectable-elements) ::: La section **Selectable groups** liste tous les groupes sélectionnables de l'écran actuel — issus de [quiz](onboarding-quizzes), de [produits](paywall-product-block), d'[onglets](builder-tabs), de [bascules d'essai](builder-toggles) ou de tout [élément sélectionnable personnalisé](flow-selectable-elements#make-an-element-selectable). Cliquez sur une entrée de groupe pour la renommer, modifier son type, consulter les variables qu'elle expose ou la supprimer. ## Gérer les calques \{#manage-layers\} Chaque élément d'un écran est représenté sous forme de calque. La section Calques affiche l'ordre des éléments sur l'écran actif. :::important Les calques d'un flow ne se superposent pas comme dans un logiciel de conception graphique. Ils représentent des composants individuels de l'écran. Les éléments ne se chevauchent *que* s'ils utilisent un [positionnement absolu ou fixe](manage-paywall-ui-elements). Leur ordre d'empilement est déterminé par la propriété `z-index`, et non par leur position dans l'arborescence des calques. ::: L'arborescence reflète les relations parent-enfant. Cliquez sur la flèche d'un calque parent pour développer ou réduire ses enfants. Vous ne pouvez pas créer de calques directement. Chaque élément ajouté via la vue [Add element](builder-elements) apparaît comme un nouveau calque dans l'arborescence. * **Sélectionner un calque** : Cliquez sur un calque pour le sélectionner. L'éditeur visuel met en surbrillance l'élément correspondant sur le canevas, et le panneau droit affiche ses propriétés de [conception](builder-styling) et d'[interaction](onboarding-navigation-branching). * **Réorganiser les calques** : Faites glisser-déposer les calques dans l'arborescence pour modifier leur ordre dans le conteneur parent. L'ordre dans l'arborescence correspond à l'ordre visuel à l'écran. * **Afficher ou masquer un calque** : Survolez un calque pour révéler l'icône œil Eye sur sa droite. Cliquez dessus pour basculer la visibilité du calque. Les calques masqués restent dans l'arborescence mais n'apparaissent ni dans l'éditeur visuel ni sur l'appareil. Pour contrôler la visibilité avec une logique à l'exécution, utilisez la [visibilité conditionnelle](onboarding-element-visibility). * **Réduire tous les calques** : Cliquez sur le bouton réduire Collapse en haut à droite de la section Calques pour replier toute l'arborescence. ### Actions sur les calques \{#layer-actions\} Cliquez sur l'icône à trois points Context pour ouvrir le menu contextuel. | Action | Raccourci | Description | |--------|----------|-------------| | **Copy** | ⌘C / Ctrl+C | Copier le calque dans le presse-papiers | | **Paste here** | ⌘V / Ctrl+V | Coller un calque précédemment copié en tant qu'enfant | | **Duplicate** | ⌘D / Ctrl+D | Créer une copie du calque dans le même conteneur | | **Rename** | | Modifier le nom d'affichage du calque. Par défaut, les calques utilisent leur contenu ou type de composant comme nom | | **Delete** | ⌘⌫ / Ctrl+Del | Supprimer le calque et tous ses enfants | | **Wrap** | | Envelopper le calque dans un nouveau conteneur : **Wrap in Horizontal Container** ou **Wrap in Vertical Container** | | **Unwrap / Ungroup** | | Retirer le conteneur enveloppant et déplacer ses enfants d'un niveau vers le haut | | **Move up** | ↑ | Déplacer le calque d'une position vers le haut dans son conteneur parent | | **Move down** | ↓ | Déplacer le calque d'une position vers le bas dans son conteneur parent | --- # File: manage-paywall-ui-elements --- --- title: "Disposition et positionnement" description: "Organisez les éléments à l'écran grâce à la disposition, au mode de positionnement, au dimensionnement et à l'espacement." --- Le Flow Builder crée des mises en page responsives. Vous ne faites pas glisser les éléments vers des coordonnées précises — vous les imbriquez dans des **conteneurs** qui organisent automatiquement leurs enfants. Le conteneur détermine la direction des éléments (verticale ou horizontale), leur alignement et leur espacement. Les éléments individuels peuvent ensuite ajuster leur taille et leurs marges, ou — si nécessaire — sortir du flux avec un positionnement absolu ou fixe. :::link Pour les propriétés visuelles comme le remplissage, les bordures et les effets, consultez [Styles et apparence](builder-styling). ::: <Tabs groupId="video"> <TabItem value="align" label="Alignement et positionnement"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aRS4Bzb6W4I?si=qH7B6t3kMab70gBi" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ``` </TabItem> <TabItem value="layout" label="Mise en page, dimensions & espacement"> ``` <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/WQ9fpxrndok?si=ROMdIPvJ32tSwUX6" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> </Tabs> ## Disposition \{#layout\} La disposition est l'outil principal pour organiser les éléments à l'écran. Chaque conteneur distribue automatiquement ses enfants selon un ensemble de règles — direction, alignement et espacement. Les éléments de disposition disponibles dans le builder sont : * **[Conteneur vertical](builder-containers#containers)** : Dispose les enfants de haut en bas * **[Conteneur horizontal](builder-containers#containers)** : Dispose les enfants de gauche à droite * **[Séparateur](builder-containers#dividers)** : Un séparateur visuel entre les éléments * **[Carrousel](builder-containers#carousel)** : Un ensemble de diapositives défilant horizontalement * **[Feuille du bas](builder-containers#bottom-sheet)** : Un panneau superposé coulissant qui révèle du contenu supplémentaire lorsque l'utilisateur appuie sur un bouton Les conteneurs sont les éléments de base d'un écran. Vous pouvez les imbriquer les uns dans les autres pour créer des mises en page complexes. Chaque conteneur dispose d'une section **Layout** dans le panneau de droite qui contrôle la disposition de ses enfants. Pour regrouper des éléments dans un nouveau conteneur, utilisez l'action de calque **Wrap** [layer action](paywall-layout-and-products#layer-actions). Pour supprimer un conteneur et promouvoir ses enfants, utilisez **Unwrap**. :::link Pour plus de détails sur la hiérarchie des écrans et des calques, consultez [Écrans et calques](paywall-layout-and-products). ::: ### Direction * Free **Free** : Pas de mise en page automatique. Les enfants sont positionnés indépendamment (utile lorsque les enfants utilisent un positionnement absolu) * Vertical **Vertical** : Les enfants s'empilent de haut en bas, comme des lignes dans une colonne * Horizontal **Horizontal** : Les enfants s'organisent de gauche à droite, comme des éléments dans une rangée ### Ordre des éléments \{#element-order\} Les enfants s'affichent dans l'ordre où ils apparaissent dans le panneau **Layers**. Dans un conteneur vertical, l'élément en haut de la liste apparaît en haut de l'écran. Dans un conteneur horizontal, l'élément en haut apparaît à gauche. Faites glisser les éléments dans le panneau Layers pour les réorganiser, ou utilisez **Move Up** et **Move Down** dans les [actions de calque](paywall-layout-and-products#layer-actions). ### Alignement \{#alignment\} La grille d'alignement contrôle la position des éléments enfants sur l'axe transversal du conteneur. Dans un conteneur vertical, l'alignement gère le placement horizontal des enfants (gauche, centre ou droite). Dans un conteneur horizontal, il gère leur placement vertical (haut, milieu ou bas). ### Distribution \{#distribution\} La distribution détermine comment l'espace est réparti entre les enfants le long de l'axe principal : * **Gap** Gap (par défaut) : Une valeur en pixels fixe entre les enfants adjacents * **Space Between** : Les enfants s'étendent jusqu'aux bords ; des espaces égaux apparaissent entre eux * **Space Around** : Un espace égal entoure chaque enfant, avec des demi-espaces aux bords * **Space Evenly** : Un espace égal avant, entre et après tous les enfants ### Rogner le contenu \{#clip-content\} Rogne visuellement le contenu qui dépasse les limites du conteneur. Désactivez cette option pour autoriser le débordement (par exemple, un badge qui dépasse intentionnellement le bord de la carte). ## Position \{#position\} Par défaut, la position de chaque élément est déterminée automatiquement par la disposition de son conteneur. Le bouton **Position** vous permet de le sortir du flux normal et de le positionner manuellement. ### Relative (par défaut) \{#relative-default\} L'élément reste dans le flux de mise en page normal. Sa position est déterminée automatiquement par les règles de disposition du conteneur parent — vous ne pouvez pas le déplacer librement. Utilisez **Margin** pour ajuster l'espace autour d'un élément en position relative. Utilisez le positionnement relatif pour la grande majorité des contenus : blocs de texte, images, cartes, boutons et éléments de liste. ### Absolu \{#absolute\} L'élément sort du flux normal et se superpose aux autres contenus. Il n'affecte plus la disposition des éléments voisins. Lorsque vous sélectionnez **Absolute**, des contrôles supplémentaires apparaissent : * **Champs de décalage** (T, L, R, B) : Définissent la distance en pixels entre l'élément et chaque bord de son conteneur parent * **Grille d'ancrage** : Cliquez sur un point de la grille 3×3 pour choisir le coin, le bord ou le centre du parent auquel l'élément s'ancre * **Ancrage horizontal** Horizontal positioning (Gauche / Centre / Droite) et **Ancrage vertical** Vertical positioning (Haut / Centre / Bas) : Listes déroulantes qui contrôlent le même point d'ancrage que la grille * **Z-index** : Champ numérique qui contrôle [l'ordre d'empilement](#stacking-order) de l'élément par rapport à ses voisins. Les éléments avec des valeurs plus élevées apparaissent au-dessus Utilisez le positionnement absolu pour les superpositions décoratives, les badges, les boutons de fermeture et les icônes placés au-dessus des images. :::tip Pour étirer un élément absolu sur toute la largeur de son parent, définissez l'ancre horizontale sur **Left**, puis ajoutez un décalage **Right** de 0. L'élément sera ancré aux deux bords. ::: ### Fixe \{#fixed\} L'élément ignore complètement son conteneur parent et se fixe à l'écran. Il reste visible pendant que l'utilisateur fait défiler — le contenu de la page défile en dessous. Le positionnement fixe utilise les mêmes commandes qu'Absolu (décalages, grille d'ancrage, Z-index). Tous les décalages sont relatifs à la zone de sécurité de l'écran plutôt qu'au parent. Par exemple, un décalage de 0 depuis le bas maintient l'élément au-dessus de l'indicateur d'accueil. Pour mesurer les décalages depuis les bords physiques de l'écran, activez [Ignorer la zone de sécurité](#ignore-safe-area). Utilisez le positionnement fixe pour les éléments qui doivent flotter au-dessus du contenu défilant plutôt que de réserver de l'espace — boutons de fermeture ou de restauration flottants, bannières supérieures persistantes, contrôles de retour en haut de page et barres de navigation. Pour une zone d'action dédiée en bas de page, utilisez plutôt un [Footer](builder-containers#footer). ### Ignorer la zone de sécurité \{#ignore-safe-area\} La zone de sécurité est la partie de l'écran qui reste dégagée de l'encoche, de la barre de statut et de l'indicateur d'accueil. Par défaut, les éléments positionnés restent à l'intérieur de cette zone. Cochez la case **Ignore safe area** sous le sélecteur de type de position pour mesurer les décalages de l'élément depuis les bords physiques de l'écran. L'élément peut alors s'étendre derrière l'encoche et l'indicateur d'accueil. Pour les médias plein écran : positionnez une image ou une vidéo en **Fixed**, réglez les quatre décalages à 0, et sélectionnez **Ignore safe area**. Le média couvre ainsi tout l'écran, bord à bord. La case à cocher ne fonctionne qu'avec les positionnements absolu et fixe. Pour les éléments en positionnement relatif, elle est désactivée, et repasser un élément en **Relative** efface ce réglage. ## Dimensionnement \{#sizing\} Chaque élément dispose de contrôles **Width** et **Height**. Cliquez sur le menu déroulant pour choisir un mode de dimensionnement : * **Fill** : l'élément s'étire pour occuper tout l'espace disponible dans son parent. La valeur en pixels affichée est le résultat calculé. * **Hug** : l'élément se réduit pour s'ajuster à son contenu. La valeur en pixels affichée est le résultat calculé. * **Fixed** : l'élément utilise la valeur en pixels exacte que vous spécifiez, indépendamment du parent ou de la taille du contenu. C'est le seul mode disponible pour les éléments positionnés en absolu ou en fixe. ## Espacement \{#spacing\} Définissez les valeurs d'espacement indépendamment pour chaque côté de l'élément. * **Margin** : L'espace entre l'élément et ses voisins. Ne dépasse pas les limites du conteneur parent, quelle que soit sa valeur. * **Padding** : L'espace entre la bordure de l'élément et son contenu. Les éléments texte n'ont qu'une margin. Les écrans n'ont que du padding. Les deux sont disponibles pour les conteneurs et les autres éléments ayant du contenu enfant. ## Ordre d'empilement \{#stacking-order\} Les éléments relatifs ne se chevauchent jamais entre eux — chaque conteneur dispose ses enfants en séquence. Le chevauchement n'apparaît qu'à partir du moment où un élément sort du flux normal avec un positionnement **Absolute** ou **Fixed**. Lorsque des éléments se chevauchent, les éléments frères placés plus bas dans le panneau **Layers** s'affichent au-dessus des précédents — même si cet élément frère est relatif et l'autre est absolu. Les éléments **Absolute** et **Fixed** disposent d'un champ **Z-index** pour un contrôle plus précis : les valeurs les plus élevées l'emportent. Les éléments Relative n'ont pas de Z-index — seul l'ordre des calques détermine leur empilement. Utilisez les [actions de calque](paywall-layout-and-products#layer-actions) **Move up** et **Move down** pour modifier l'ordre des éléments. --- # File: builder-styling --- --- title: "Styles et apparence" description: "Configurez l'apparence visuelle des éléments — remplissage, bordures, effets, typographie, états et styles à l'échelle du projet." --- L'onglet **Design** du panneau de droite contrôle l'apparence visuelle de chaque élément. Les propriétés disponibles dépendent du type d'élément, mais la plupart partagent des options de style communes. :::link Pour la taille, l'espacement et le positionnement, voir [Mise en page et positionnement](manage-paywall-ui-elements). ::: ## Visibilité \{#visibility\} Le bouton **Visibility** détermine si l'élément est affiché à l'écran. * Show **Show** (par défaut) : L'élément est toujours visible. * Conditional **Conditional** : L'élément est visible uniquement lorsque des conditions spécifiques sont remplies. Consultez [Visibilité conditionnelle](onboarding-element-visibility) pour plus d'informations. * Hide **Hide** : L'élément est toujours masqué. Utilisez cette option pour retirer temporairement un élément du flow sans le supprimer. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Remplissage \{#fill\} La section **Fill** contrôle l'arrière-plan de l'élément. Quatre types de remplissage sont disponibles : couleur unie, dégradé, image et vidéo. Utilisez cette propriété pour définir l'image principale / la vidéo de tout l'écran. * **Couleur unie** Solid color. Utilisez le sélecteur de couleur, entrez une valeur hexadécimale ou attribuez un [style de couleur global](#color-styles). Ajustez l'**opacité** pour rendre l'arrière-plan semi-transparent. * **Dégradé** Gradient. Ajoutez un remplissage en dégradé avec deux points de couleur ou plus. Faites glisser les points pour ajuster la transition et modifiez l'angle du dégradé pour en contrôler la direction. * **Image** Image ou **Vidéo** Video. Définit une [image / vidéo](custom-media) comme arrière-plan de l'élément. ## Bordure \{#border\} Les bordures sont désactivées par défaut. Cliquez sur Plus à côté de **Border** dans le panneau de droite pour en ajouter une. Pour supprimer une bordure, cliquez sur Close à côté du titre **Border**. Lorsqu'une bordure est présente, configurez : * **Color** : utilisez le sélecteur de couleur, saisissez une valeur hexadécimale ou attribuez un [style de couleur global](#color-styles). Ajustez l'**opacity** pour rendre la bordure semi-transparente. * **Width** : l'épaisseur de la bordure en pixels. ## Coins \{#corners\} La section **Corners** contrôle le rayon de bordure (coins arrondis). * **Curseur de rayon** : Définit le même rayon pour les quatre coins * **Bascule par coin** Per Corner : Activez cette option pour définir un rayon différent pour chaque coin individuellement ## Effets \{#effects\} Cliquez sur le bouton plus Plus à côté de **Effects** pour ajouter un ou plusieurs effets visuels : * **Drop shadow** : une ombre derrière l'élément * **Inner shadow** : une ombre à l'intérieur des contours de l'élément * **Background blur** : floute l'arrière-plan * **Layer blur** : floute l'élément et ses enfants Vous pouvez cumuler plusieurs effets sur un même élément. Activez ou désactivez la visibilité Show pour désactiver temporairement un effet. ## Animation \{#animation\} Cliquez sur le bouton Plus à côté de **Animation** pour ajouter un effet animé. Actuellement, **Pulse** est la seule animation disponible — l'élément s'agrandit et se réduit rhythmiquement pour attirer l'attention. Configurez l'animation Pulse avec les paramètres suivants : | Paramètre | Description | |-----------|-------------| | Scale amount (%) | De combien l'élément grossit par rapport à sa taille d'origine | | Duration (ms) | Durée d'un cycle d'animation | | Delay between loops (ms) | Pause entre les répétitions | | Shadow color | Couleur de l'effet d'ombre pulsante | | Shadow size (px) | Taille de l'ombre pulsante | ### Prévisualiser l'animation \{#preview-the-animation\} Par défaut, le builder affiche des écrans statiques — les animations restent immobiles jusqu'à ce que vous les activiez. Deux façons de procéder : - Cliquez sur le bouton **Toggle animations** Toggle animations au-dessus de la prévisualisation de l'appareil. Il active ou désactive les animations de l'écran — une fois activées, elles tournent en continu jusqu'à ce que vous cliquiez à nouveau. Le bouton n'apparaît que si l'écran actif contient au moins une animation. - Ouvrez le [menu contextuel](paywall-layout-and-products#screen-actions) de l'écran (l'icône à trois points à côté du calque d'écran) et choisissez **Play Animation**. ## Apparence \{#appearance\} * **Opacity** : De 0 % (transparent) à 100 % (opaque) * **Rotation** : Saisissez une valeur en degrés pour faire pivoter l'élément ## Propriétés de typographie (éléments texte) \{#typography-properties-text-elements\} Les éléments texte affichent une section **Typography** avec les contrôles suivants : ### Police \{#font\} :::link Voir aussi : [Polices personnalisées](using-custom-fonts-in-flow-builder) ::: Cliquez sur le menu déroulant de police Font select pour ouvrir le sélecteur de polices. Il comporte deux onglets : * **Styles** : liste les [styles de texte](#text-styles) enregistrés dans votre projet. Sélectionnez un style pour appliquer d'un coup tous ses paramètres typographiques. * **Fonts** : liste toutes les familles de polices disponibles. Recherchez ou faites défiler pour trouver celle dont vous avez besoin. Les polices intégrées peuvent **s'afficher différemment selon les appareils** — pour un rendu cohérent, importez une [police personnalisée](using-custom-fonts-in-flow-builder). ### Taille et graisse \{#size-and-weight\} :::warning Pour les [polices personnalisées](using-custom-fonts-in-flow-builder), les contrôles **Weight**, **Bold** et **Italic** n'affectent que l'aperçu intégré de l'éditeur. Pour afficher différentes graisses et styles, importez chaque variation de la police sous forme de fichier séparé. ::: * **Weight** : sélectionnez une graisse de police dans le menu déroulant * **Size** : sélectionnez une taille dans le menu déroulant ou saisissez une valeur personnalisée ### Couleur \{#color\} Cliquez sur la pastille de couleur pour ouvrir le sélecteur de couleurs. Saisissez une valeur hexadécimale, utilisez la palette, ou sélectionnez l'un des [styles réutilisables](#reusable-styles). Ajustez le curseur d'opacité pour rendre le texte semi-transparent. ### Alignement \{#alignment\} Deux groupes de contrôles d'alignement : * **Horizontal** : Gauche Align left, Centre Align center, ou Droite Align right * **Vertical** : Haut Align top, Milieu Align middle, ou Bas Align bottom ### Décoration \{#decoration\} * **None** None: Aucune décoration (par défaut) * **Underline** Underline: Ajoute un soulignement au texte * **Strikethrough** Strikethrough: Ajoute un texte barré ### Troncature \{#truncation\} Activez la troncature pour couper le texte qui dépasse le paramètre **Max Lines**. C'est utile lorsque vous prenez en charge plusieurs langues : si une chaîne traduite est plus longue que l'original, la troncature évite que la mise en page ne soit cassée. :::note Lorsque vous sélectionnez un élément de texte, une **barre d'outils intégrée** apparaît également au-dessus sur le canevas. Elle permet d'accéder rapidement à la police, au poids, à la taille et à l'alignement sans avoir à faire défiler le panneau de droite. ::: ## Paramètres spécifiques aux états (éléments interactifs) \{#state-specific-settings-interactive-elements\} Les éléments interactifs prennent en charge plusieurs états visuels. Lorsque vous sélectionnez un tel élément, une section **States** apparaît dans le panneau de droite. Passez d'un état à l'autre pour configurer des propriétés visuelles différentes pour chacun. Chaque état peut remplacer n'importe quelle propriété visuelle : remplissage, bordure, couleur de typographie, opacité, etc. ### États sélectionnables \{#selectable-states\} :::link Article principal : [Éléments sélectionnables](flow-selectable-elements) ::: Les éléments appartenant à un groupe sélectionnable (options de quiz, produits, onglets, interrupteurs d'essai) proposent deux états par défaut : * **Default** : L'apparence normale de l'élément * **Selected** : L'apparence lorsque l'utilisateur a sélectionné cette option. Remplacez des propriétés comme le remplissage, la couleur de bordure et la couleur de texte pour mettre en évidence le choix actif Pour appliquer un style à un élément sélectionnable lorsqu'il n'est pas interactif, ajoutez manuellement un troisième état. Ouvrez **States settings** Settings et ajoutez un **Disabled state**. L'état **Disabled** est conditionnel. Sélectionnez-le et cliquez sur **Set conditions** set conditions pour définir quand l'élément devient désactivé à l'exécution, par exemple lorsqu'un champ obligatoire est vide. ### États de saisie \{#input-states\} Les champs de saisie proposent des états supplémentaires : * **Default** : Apparence normale, sans focus * **Active** : Le champ est actif et prêt à recevoir une saisie * **Invalid** : La valeur saisie échoue à la validation * **Disabled** : Le champ n'est pas interactif ### Autres éléments avec des états \{#other-state-bearing-elements\} Certains éléments exposent un style propre à leurs états en dehors du modèle standard **Default / Selected / Disabled** : - **[Étapes de l'indicateur de progression](builder-loaders-and-progress-bars#step-states)** — trois états par étape : **Completed**, **Current** et **Upcoming**. - **[Points du carrousel](builder-containers#dots)** — deux variantes de couleur : **Color** pour les points inactifs et **Active Color** pour le point de la diapositive en cours. ## Styles réutilisables \{#reusable-styles\} Le panneau **Styles** Styles dans la barre latérale gauche vous permet de définir des styles réutilisables qui s'appliquent à l'ensemble de votre flow. Deux types de styles sont disponibles : les styles de texte et les styles de couleur. Vous devez utiliser des styles de couleur pour activer la prise en charge du mode sombre. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/auMs_Tr9xtU?si=Ti7fZbZpbd0p_XEO" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ### Styles de texte \{#text-styles\} :::link Article principal : [Contenu textuel](onboarding-text) ::: Les styles de texte regroupent un ensemble complet de paramètres typographiques : famille de polices, graisse, taille, interligne, alignement et décoration. Chaque modèle de flow inclut des préréglages par défaut, et vous pouvez créer des styles personnalisés. Pour créer un style de texte : 1. Ouvrez le panneau **Styles** Styles et sélectionnez l'onglet **Text**. 2. Cliquez sur **Plus Create style**. 3. Saisissez un nom et configurez les paramètres typographiques. 4. Cliquez sur **Create**. Pour appliquer un style de texte, sélectionnez un élément texte et choisissez le style dans le menu déroulant de police de la section **Typography**. ### Styles de couleur \{#color-styles\} Les styles de couleur sont des couleurs nommées que vous pouvez référencer dans tout votre flow. Chaque style de couleur possède un nom (comme « Texte principal » ou « Marque »), une valeur hexadécimale et un compteur d'utilisation indiquant combien d'éléments y font référence. Pour créer un style de couleur : 1. Ouvrez le panneau **Styles** Styles et sélectionnez l'onglet **Colors**. 2. Cliquez sur **Plus Create style**. 3. Saisissez un nom et choisissez une couleur. Lorsque vous modifiez un style de couleur, tous les éléments qui y font référence se mettent à jour automatiquement. ### Mode sombre \{#dark-mode\} :::link Article principal : [Mode sombre](paywall-dark-mode) ::: Si nécessaire, vous pouvez ajouter deux variantes à chaque style de couleur — une pour le mode clair Light mode et une pour le mode sombre Dark mode. Le SDK applique automatiquement la variante correcte en fonction du mode de couleur actuel de l'appareil. Pour prévisualiser le mode sombre dans le builder, utilisez le **sélecteur de thème** Dark mode dans la [barre d'outils inférieure](builder-ui#view-controls-bottom-toolbar). --- # File: paywall-product-block --- --- title: "Configurer les achats" description: "Assignez des produits aux écrans, ajoutez des éléments de produit et connectez un bouton d'achat dans le Flow Builder." --- Pour configurer les achats sur un écran, ajoutez un bouton d'achat et configurez son action **Purchase**. Cette action peut cibler un produit spécifique ou celui que l'utilisateur sélectionne depuis un élément Products sur l'écran. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/LLIZCd94PlE?si=t_8BitA1FBpbd8ue" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Ajouter des produits \{#add-products\} Un élément de produit est une carte visuelle qui affiche un produit sur le canevas. Pour ajouter un élément de produit : 1. Sur le canevas, cliquez sur **+** sur l'écran cible. 2. Sélectionnez **Products**. 3. Choisissez une disposition prédéfinie : liste verticale, liste horizontale, carrousel de fonctionnalités, cartes de fonctionnalités, liste en bannière ou feuille du bas. 4. Sélectionnez chaque carte de produit et assignez-lui un produit dans le menu déroulant du panneau **Design**. :::important Un élément de produit sans produit associé [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Assignez un produit ou supprimez l'élément. ::: Pour afficher un prix d'ancrage barré sur une carte, ajoutez un [élément Old Price](onboarding-text#add-an-old-price) à l'intérieur. :::note Vous pouvez également associer une action **Purchase** directement à l'interaction **On tap** d'une carte de produit. En appuyant sur la carte, l'achat se déclenche sans avoir besoin d'un bouton d'achat séparé. ::: :::important Si vous supprimez un groupe de produits et le remplacez par un nouveau, vérifiez que chaque action et variable cible le nouveau groupe. Les références pointant toujours vers le groupe supprimé [bloquent l'aperçu et la publication](builder-save-publish#troubleshooting). ::: ## Ajouter un bouton d'achat \{#add-a-purchase-button\} Un bouton d'achat déclenche une action **Purchase** lorsque l'utilisateur appuie dessus. Pour ajouter un bouton d'achat : 1. Sur le canevas, cliquez sur **+** sur l'écran. 2. Sélectionnez **Button** et choisissez un style de bouton prédéfini. 3. Avec le bouton sélectionné, ouvrez l'onglet **Interactions** dans le panneau de droite. 4. Cliquez sur **Add trigger** > **On tap**, puis cliquez sur **Add action**. 5. Définissez **Action** sur **Purchase**, puis définissez **Product** sur l'une des options suivantes : - `products.selectedProduct` : achète le produit que l'utilisateur a sélectionné depuis un élément Products sur l'écran. - Un produit spécifique : achète toujours ce produit, quelle que soit la sélection sur l'écran. ### Afficher le prix sur le bouton \{#show-the-price-on-the-button\} Pour insérer le prix du produit sélectionné dans le libellé du bouton, utilisez une variable : 1. Avec le bouton sélectionné, ouvrez l'onglet **Design** dans le panneau de droite. 2. Dans le champ **Content**, placez le curseur à l'endroit où le prix doit apparaître. 3. Cliquez sur l'icône de variable, sélectionnez `products.selectedProduct`, puis l'attribut `prod_price`. La variable complète devient `products.selectedProduct.prod_price`. 4. Ajoutez du texte statique autour de la variable — par exemple, `Subscribe for {prod_price}`. Le libellé se met à jour lorsque l'utilisateur sélectionne différents produits. ## Restaurer les achats \{#restore-purchases\} Pour permettre aux utilisateurs de restaurer leurs achats précédents, ajoutez un bouton ou un lien de restauration à l'écran. Pour ajouter un élément de restauration des achats : 1. Sur le canevas, cliquez sur **+** sur l'écran. 2. Sélectionnez **Button**, puis choisissez **Links** pour un lien textuel ou tout autre type de bouton pour un bouton stylisé. 3. Avec l'élément sélectionné, ouvrez l'onglet **Interactions** dans le panneau de droite et cliquez sur **Add trigger**. 4. Sélectionnez **On tap** et cliquez sur **Add action**. 5. Dans le menu déroulant **Action**, sélectionnez **Restore purchases**. ## Afficher des éléments supplémentaires selon le produit sélectionné \{#display-additional-elements-based-on-the-selected-product\} Si un écran contient des produits, vous pouvez afficher ou masquer d'autres éléments selon le produit que l'utilisateur sélectionne. Pour configurer la visibilité conditionnelle : 1. Dans l'élément **Products**, sélectionnez une carte de produit. 2. Ouvrez l'onglet **Interactions** dans le panneau de droite et cliquez sur **Add trigger**. 3. Sélectionnez **On tap** et cliquez sur **Add action**. 4. Dans le menu déroulant **Action**, sélectionnez **Show** ou **Hide**. 5. Sélectionnez l'élément à afficher ou masquer lorsque ce produit est sélectionné. ## Consulter les produits dans le flow \{#review-products-in-flow\} Le panneau **Products** dans la barre latérale gauche répertorie les produits existants pour chaque écran du flow. Chaque écran comporte deux sections : - **Default** — un produit, présélectionné au chargement de l'écran. - **Other** — produits supplémentaires disponibles sur le même écran. --- # File: builder-elements --- --- title: "Éléments" description: "Tous les éléments visuels disponibles dans le Flow Builder : conteneurs de mise en page, texte, médias, listes, boutons, champs de saisie, produits et plus encore." --- Pour ouvrir la bibliothèque d'éléments et ajouter un nouvel élément à un écran, cliquez sur le bouton plus Plus dans le panneau gauche ou au-dessus de l'aperçu de l'appareil. Les éléments se répartissent dans les catégories suivantes : - [Bases](#basics) (conteneurs de mise en page, texte, médias, listes, badges, coches) - [Formulaires et quiz](#forms--quiz) (boutons, champs de saisie, quiz, onglets) - [Paywall et commerce](#paywall--commerce) (produits, bouton d'essai gratuit, engagement utilisateur, compte à rebours) - [Indicateurs de progression](#progress) et chargeurs Pour chaque élément, Adapty propose plusieurs présets — des modèles avec du contenu de substitution ou des interactions prédéfinies. ## Bases \{#basics\} ### Mise en page \{#layout\} :::link Article principal : [Éléments de mise en page](builder-containers) ::: Les éléments de mise en page sont des conteneurs qui organisent les éléments qu'ils contiennent. - **Conteneur vertical** : dispose les éléments enfants de haut en bas - **Conteneur horizontal** : dispose les éléments enfants de gauche à droite - **Séparateurs (horizontal et vertical)** : lignes qui séparent visuellement les sections de contenu - **Carousel** : un conteneur à défilement par glissement - **Pied de page** : un panneau épinglé au bas de l'écran, en dehors de la zone de défilement - **Feuille inférieure** : un panneau coulissant ancré au bas de l'écran ### Texte \{#text\} :::link Article principal : [Contenu textuel](onboarding-text) ::: Le texte peut être statique ou inclure des [variables](onboarding-variables) (ex. : nom d'utilisateur) et du [contenu localisé](paywall-localization). Les présets de texte suivants sont disponibles par défaut. Pour modifier cette liste, ajoutez ou supprimez des [styles de texte enregistrés](builder-styling#reusable-styles) : - H1 - H2 - H3 - Button Label - Body - Caption - Small Label Le menu **Text** comprend également l'élément **Old Price** — un prix de produit barré calculé automatiquement à partir d'un multiplicateur. Voir [Ajouter un ancien prix](onboarding-text#add-an-old-price). ### Médias \{#media\} :::link Article principal : [Images, vidéos et icônes](custom-media) ::: :::note Cette section décrit les éléments multimédias au premier plan. Modifiez l'[arrière-plan de l'écran](paywall-layout-and-products#screen-background) pour remplir tout l'écran avec une image ou une vidéo. ::: - **Icône** : une icône vectorielle de la bibliothèque d'icônes intégrée, avec taille et couleur personnalisables - **Image** : une image — téléchargez la vôtre ou fournissez une URL - **Vidéo** : un lecteur vidéo intégré pour les fichiers jusqu'à 50 Mo. Supporte la lecture en boucle. ### Liste \{#list\} Les éléments de liste organisent le contenu en lignes et en colonnes pour afficher des données uniformément formatées. En coulisse, une liste est un [conteneur](manage-paywall-ui-elements#layout). - **Liste d'icônes** : lignes avec une icône en tête et une étiquette de texte - **Chronologie** : séquence verticale avec des indicateurs d'étapes connectées - **Liste d'images** : lignes avec une image en tête et du texte - **Cartes d'icônes** : grille de cartes avec des icônes centrées - **Cartes d'images** : grille de cartes avec des images - **Tableau comparatif** : tableau multi-colonnes comparant des fonctionnalités entre les plans (ex. : Gratuit vs Pro) ### Badge \{#badge\} Une petite étiquette superposée pour mettre en avant un élément — généralement utilisée pour promouvoir des remises ou des plans spécifiques (ex. : « Économisez 5 % »). Utilisez le [positionnement absolu](manage-paywall-ui-elements#absolute) pour placer un badge par-dessus un autre élément. ### Coches \{#checkmarks\} Icônes d'indicateur de sélection à utiliser dans des [éléments sélectionnables](flow-selectable-elements). Chaque préset de coche inclut un état activé et désactivé qui se met à jour automatiquement en fonction de la sélection de l'utilisateur. - Checkbox - Circle - Radiobutton - Toggle ## Formulaires et quiz \{#forms--quiz\} ### Boutons \{#buttons\} :::link Article principal : [Boutons](paywall-buttons) ::: Les boutons déclenchent des actions lorsqu'on appuie dessus — naviguer vers un autre écran, ouvrir une URL ou quitter le flow. Chaque préset est un point de départ — personnalisez son style et assignez-lui n'importe quelle action. Configurez le comportement des boutons dans l'onglet [Interactions](builder-ui#interactions-properties). - **Base** : bouton classique avec texte centré - **Icône à droite** : bouton avec une icône sur le côté droit - **Avec sous-titre** : inclut deux lignes de texte - **Animation pulsée** : inclut un effet de pulsation animé - **Achat** : déclenche un achat - **Contour secondaire** : bouton avec contour pour les actions secondaires - **Retour** : retourner à l'écran précédent - **Fermer le flow** : quitter le flow - **Voir plus de plans** : révéler des options de produits supplémentaires - **Liens** : un ensemble de boutons de pied de page (Restore, Terms of Service, Privacy Policy) ### Champs de saisie \{#inputs\} :::link Article principal : [Champs de saisie et formulaires](builder-inputs-and-forms) ::: Les champs de saisie permettent aux utilisateurs d'entrer des données. Chacun applique une méthode de saisie et des règles de validation adaptées. - Texte - E-mail - Mot de passe - Nombre - Numéro de téléphone - Date - Heure - Date et heure Les champs Date, Heure et Date et heure ouvrent le sélecteur natif de l'appareil (molette ou calendrier) lorsqu'on appuie dessus. Utilisez des [variables](onboarding-variables) pour traiter les saisies des utilisateurs et influencer la logique conditionnelle. ### Quiz \{#quizzes\} :::link Article principal : [Sondages et quiz](onboarding-quizzes) ::: Les éléments de quiz présentent des écrans de sélection multi-options pour les sondages, la collecte de préférences et la segmentation des utilisateurs. Configurez des [interactions](onboarding-navigation-branching) pour orienter le flow en fonction de la réponse de l'utilisateur. - **Options avec icônes** : liste à une colonne avec des icônes - **Options avec emojis** : liste à une colonne avec des emojis - **Options avec images** : liste à une colonne avec des images - **Grille d'icônes** : grille multi-colonnes avec des icônes - **Grille d'emojis** : grille multi-colonnes avec des emojis - **Grille d'images** : grille multi-colonnes avec des photos - **Évaluation** : échelle numérique (ex. : 1–5) ### Onglets \{#tabs\} :::link Article principal : [Onglets](builder-tabs) ::: Les onglets divisent une section d'écran en panneaux de contenu commutables. L'utilisateur sélectionne un onglet et le contenu en dessous se met à jour en conséquence. Couramment utilisés pour regrouper des plans de produits ou basculer entre une tarification mensuelle et annuelle. - **Contrôle segmenté** : sélecteur en forme de pilule avec des coins arrondis autour de l'onglet sélectionné - **Onglets boutons** : onglets séparés en style bouton - **Souligné** : étiquettes de texte avec un soulignement marquant l'onglet sélectionné ## Paywall et commerce \{#paywall--commerce\} ### Produits \{#products\} :::link Article principal : [Produits](paywall-product-block) ::: Les éléments de produit affichent les détails des achats intégrés et gèrent la sélection de produits. Chaque préset dispose les données produit dans une mise en page différente. Liez vos produits pour alimenter les éléments avec des données réelles provenant d'Adapty. - **Liste verticale** : cartes de produits empilées - **Liste horizontale** : cartes de produits côte à côte - **Carousel de fonctionnalités** : cartes à défilement par glissement avec listes de fonctionnalités - **Cartes de fonctionnalités** : cartes statiques avec listes de fonctionnalités - **Liste bannière** : lignes compactes avec des badges intégrés {/* Coming soon - **Bottom Sheet**: product selector inside a slide-up panel */} ### Bouton d'essai gratuit \{#trial-toggle\} :::link Article principal : [Boutons bascule](builder-toggles) ::: Un bouton bascule qui fait passer le produit affiché de son prix standard à son offre d'essai gratuit. Lorsqu'il est activé, la sélection du produit et l'état de l'élément se mettent à jour automatiquement. ### Engagement utilisateur \{#user-engagement\} Blocs prêts à l'emploi avec des évaluations utilisateurs qui renforcent la confiance et encouragent la conversion. Les modèles sont des conteneurs simples avec du contenu de substitution. - **Avis** : une note en étoiles avec un commentaire et le nom de l'auteur - **Évaluation** : un score numérique avec affichage d'étoiles - **Note de l'app** : un grand score avec une barre d'étoiles et un nombre d'avis - **Preuve sociale** : une pile d'avatars avec un nombre d'utilisateurs ### Compte à rebours \{#countdown\} :::link Article principal : [Minuteur de compte à rebours](paywall-timer) ::: Affiche des heures, des minutes et des secondes décomptant jusqu'à zéro. Utilisez-le pour créer un sentiment d'urgence pour des offres à durée limitée. Le minuteur peut déclencher des actions lorsqu'il atteint zéro — comme naviguer vers un autre écran ou masquer le badge de remise. - **Inline** : affichage numérique compact - **Inline avec unités** : affichage numérique avec étiquettes d'unités - **Badge** : petite superposition de minuteur mise en évidence - **Blocs** : cartes séparées pour les jours, les heures, les minutes et les secondes ## Progression \{#progress\} :::link Article principal : [Chargeurs et barres de progression](builder-loaders-and-progress-bars) ::: ### Indicateurs de progression \{#progress-indicators\} Barres de progression par étapes qui montrent la position de l'utilisateur dans un flow à plusieurs écrans. Utiles pour les séquences d'onboarding où l'utilisateur doit voir combien d'étapes il reste. - **Linéaire** : une seule barre continue qui se remplit à mesure que l'utilisateur avance - **Segmenté** : une barre divisée en segments distincts, un par étape - **Connecteurs** : marqueurs d'étapes numérotés reliés par de courtes lignes de connexion ### Chargeurs \{#loaders\} Indicateurs de chargement animés pour les transitions. Utilisez des chargeurs lorsque votre application traite des données utilisateur — par exemple, après la soumission d'un quiz. - **Spinner** : indicateur circulaire rotatif - **Spinner avec étiquette** : spinner accompagné d'une étiquette de texte (ex. : « Chargement... ») - **Chargeur** : barre de progression horizontale {/* - **Loader with label**: progress bar paired with a text label and percentage */} --- # File: flow-selectable-elements --- --- title: "Éléments sélectionnables et groupes" description: "Rendez des éléments sélectionnables, organisez-les en groupes et utilisez leur état dans les conditions du flow." --- Les éléments sélectionnables sont des éléments du flow sur lesquels les utilisateurs peuvent appuyer pour les sélectionner ou les désélectionner. Leur état peut piloter la navigation, la visibilité et d'autres logiques dans le flow. Voici ce que vous pouvez faire : - [Utiliser les éléments sélectionnables par défaut](#default-selectable-elements) — les options de quiz, les produits, les onglets et les bascules d'essai sont sélectionnables d'emblée - [Rendre n'importe quel élément sélectionnable](#make-an-element-selectable) — transformez n'importe quel élément en élément sélectionnable et affectez-le à un groupe - [Créer et gérer des groupes](#create-a-group) — organisez les éléments sélectionnables en groupes à choix unique, à choix multiple ou en bascule - [Utiliser l'état sélectionné dans les conditions](#use-selectable-state-in-conditions) — référencez les valeurs de groupe dans les conditions sur n'importe quel écran du flow ## Éléments sélectionnables par défaut \{#default-selectable-elements\} Certains types d'éléments sont sélectionnables par défaut — ils appartiennent déjà à des groupes créés automatiquement et ne nécessitent aucune configuration supplémentaire : - **Options de quiz** : chaque réponse de quiz est un élément sélectionnable au sein du groupe de quiz. Voir [Quiz](onboarding-quizzes). - **Produits** : les cartes produit dans un groupe de produits. Voir [Bloc produit](paywall-product-block). - **Onglets** : les éléments d'onglet au sein d'un groupe d'onglets. Voir [Onglets](builder-tabs). - **Bascules d'essai** : un conteneur qui appartient à un groupe et prend un état sélectionné. Voir [Bascules](builder-toggles). ## Rendre un élément sélectionnable \{#make-an-element-selectable\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/btpZPOm9VRY?si=1P959iwNfIJ1ZP7N" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Dans certains cas, vous pourriez vouloir rendre des éléments supplémentaires sélectionnables. Par exemple, vous pouvez ajouter une case à cocher **Ne plus me demander** qui fonctionne comme un élément au sein d'un groupe de quiz. Pour rendre un élément sélectionnable : 1. Sélectionnez l'élément sur l'écran ou dans le panneau **Layers**. 2. À droite, basculez vers le panneau **Interactions**. 3. Sélectionnez **Turn into selectable element**. 4. Dans le menu déroulant **Group**, sélectionnez un groupe existant ou [créez-en un nouveau](#create-a-group). 5. Définissez l'**Element ID** — un identifiant unique pour cet élément au sein du groupe. 6. Si vous souhaitez que cet élément soit sélectionné par défaut, cochez la case **Set as default in group**. ## Créer un groupe \{#create-a-group\} Les groupes organisent les éléments sélectionnables sur un écran et définissent le fonctionnement de la sélection — choix unique, choix multiple ou bascule. Pour créer un groupe : 1. Sélectionnez un élément et [rendez-le sélectionnable](#make-an-element-selectable). 2. Dans le menu déroulant **Group**, sélectionnez **Create group**. 3. Saisissez un **Group name**. 4. Sélectionnez le [type de groupe](#group-types). Le groupe est maintenant disponible dans le menu déroulant **Group** pour les autres éléments sélectionnables du même écran. ## Types de groupes \{#group-types\} :::important La plupart des [préréglages de quiz](onboarding-quizzes) sont **multi-choice** par défaut. Modifiez le [type de groupe](#manage-groups) pour n'autoriser qu'une seule réponse. ::: - **Single choice** : un seul élément du groupe peut être sélectionné à la fois. Sélectionner un nouvel élément désélectionne le précédent. - **Multi-choice** : plusieurs éléments peuvent être sélectionnés simultanément. - **Toggle** : chaque élément bascule entre sélectionné et désélectionné à chaque appui, indépendamment des autres éléments. ## Gérer les groupes \{#manage-groups\} Pour afficher et modifier les groupes, ouvrez le panneau **Screen settings** et repérez la section **Selectable groups**. Elle liste tous les groupes de l'écran actuel. Cliquez sur l'ID d'un groupe pour : - Modifier l'ID du groupe - Modifier le [type de groupe](#group-types) - Voir comment les éléments du groupe sont référencés dans les conditions ## Utiliser l'état sélectionnable dans les conditions \{#use-selectable-state-in-conditions\} Vous pouvez référencer l'état sélectionné d'un groupe dans les conditions sur n'importe quel écran du flow — pas seulement sur l'écran où le groupe est défini. Par exemple : `SI quiz.photo est sélectionné, ALORS naviguer vers l'écran Photo`. :::important Tous les éléments d'un groupe doivent se trouver sur le même écran. Vous ne pouvez pas ajouter des éléments provenant d'écrans différents à un même groupe. En revanche, vous pouvez référencer les valeurs de groupe dans les conditions sur n'importe quel écran du flow. ::: Utilisez l'état sélectionnable avec : - **[Actions conditionnelles](onboarding-actions#conditional-actions)** : orientez les utilisateurs vers différents écrans ou déclenchez différentes actions en fonction des éléments sélectionnés. - **[Navigation dynamique](onboarding-navigation-branching)** : faites bifurquer le flow selon les réponses au quiz, les états des bascules ou d'autres sélections. - **[Visibilité conditionnelle](onboarding-element-visibility)** : affichez ou masquez des éléments selon ce que les utilisateurs ont sélectionné sur les écrans précédents. --- # File: builder-element-states --- --- title: "États des éléments" description: "Stylisez les éléments selon leur état et utilisez une condition pour désactiver un élément au moment de l'exécution." --- Les éléments interactifs d'un flow changent d'apparence selon les actions de l'utilisateur : une option de quiz appuyée devient **Selected**, un champ de saisie actif devient **Active**. Certains états sont pilotés par des conditions — par exemple, vous pouvez **désactiver** un bouton. Stylisez chaque état séparément pour donner un retour visuel aux utilisateurs sans écrire de code dans l'application. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/gdsNfHpKAqQ?si=VY5mqZgH1j0RB6fE" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## États disponibles selon le type d'élément \{#available-states-by-element-kind\} | Type d'élément | États intégrés | États ajoutables | |---|---|---| | [Éléments sélectionnables](#selectable-element-states) | **Default**, **Selected** | **Disabled** | | [Inputs](#input-states) | **Default**, **Active**, **Invalid** | **Disabled** | | [Tout élément avec une interaction tactile](#condition-driven-disabled-state) — boutons, images, icônes, conteneurs, etc. | **Default** | **Disabled** | | [Étapes d'un indicateur de progression](#step-states-for-progress-indicators) | **Completed**, **Current**, **Upcoming** | — | Les états **Ajoutables** n'apparaissent pas par défaut — ouvrez **States settings** Settings pour les ajouter. Ils sont [**pilotés par des conditions**](#condition-driven-disabled-state) : vous définissez quand ils s'activent. ## Comment styliser un état \{#how-to-style-a-state\} 1. Sélectionnez un élément. La section **States** dans le panneau de droite liste les états pris en charge par cet élément. 2. Dans la section **States**, activez l'état cible. Ajoutez l'[état Disabled piloté par condition](#condition-driven-disabled-state) si nécessaire. 3. Modifiez n'importe quelle propriété — remplissage, bordure, typographie, etc. La modification est limitée à cet état. Les éléments imbriqués deviennent eux aussi avec état en même temps que le parent. Toute modification apportée à un enfant est limitée à l'état actif du parent. 4. Le Builder applique le style correspondant au moment de l'exécution. ## États des éléments sélectionnables \{#selectable-element-states\} Les éléments sélectionnables — options de quiz, produits, onglets, bascules d'essai et tout [élément sélectionnable personnalisé](flow-selectable-elements#make-an-element-selectable) — disposent de deux états par défaut : - **Default** : L'apparence au repos de l'élément. - **Selected** : S'applique lorsque l'utilisateur appuie sur l'élément. Le Builder revient à Default lorsque l'utilisateur désélectionne l'élément. Dans un groupe à choix unique, sélectionner un élément désélectionne les autres. Les groupes à choix multiple permettent à plusieurs éléments d'être Selected en même temps. Les bascules sont indépendantes — en sélectionner une n'affecte pas ses voisines. Voir [types de groupes](flow-selectable-elements#group-types). :::tip Besoin de styliser le même état pour plusieurs éléments (par exemple, des options de quiz) ? Stylisez d'abord un élément, puis dupliquez-le. Le style d'état ne se propage pas entre les éléments frères — la duplication est le contournement actuel. ::: ## États des inputs \{#input-states\} - **Default** : L'apparence au repos du champ de saisie. - **Active** : S'applique pendant que le champ est actif. - **Invalid** : S'applique lorsque le contenu du champ ne passe pas la validation. Par exemple, quand un champ e-mail ne contient pas `@`. Voir [Validation des inputs](builder-inputs-and-forms#input-validation). - **Disabled** : Le champ n'est pas interactif. Ajoutez cet état manuellement ; voir [État Disabled piloté par condition](#condition-driven-disabled-state). Stylisez chaque état de la même façon qu'un élément sélectionnable : activez l'état cible, modifiez les propriétés. ## État Disabled piloté par condition \{#condition-driven-disabled-state\} L'état Disabled empêche l'utilisateur d'interagir avec un élément. Contrairement à Default, Selected, Active ou Invalid, l'état Disabled ne s'active pas tout seul — il nécessite une condition déclencheur définie par l'utilisateur. Disabled est disponible sur : - **Inputs** : Tout [champ de saisie](builder-inputs-and-forms) — texte, e-mail, mot de passe, nombre, téléphone, date et/ou heure. - **Éléments sélectionnables** : Options de quiz, produits, onglets, bascules d'essai et tout [élément sélectionnable personnalisé](flow-selectable-elements#make-an-element-selectable). - **Tout élément avec une interaction tactile** : Par exemple, un bouton, une image ou une icône qui déclenche une action de navigation. ### Ajouter l'état Disabled \{#add-the-disabled-state\} Pour ajouter et configurer un état Disabled : 1. Sélectionnez l'élément cible. 2. Dans la section **States**, cliquez sur **Settings** Settings. 3. Choisissez **Add Disabled state**. L'état Disabled apparaît dans la section **States**. 4. À côté du nouvel état Disabled, cliquez sur **Edit conditional state** Edit conditional state. 5. Ajoutez une condition. Si vous souhaitez désactiver le bouton **submit** tant que le champ ne passe pas la validation, comparez la variable `isValid` du champ à `false`. 6. Stylisez l'état Disabled pour communiquer visuellement la restriction (par exemple, réduisez l'opacité). { } Le SDK Adapty évalue la condition au moment de l'exécution et applique l'état Disabled le cas échéant — aucun code dans l'application n'est nécessaire. ## États des étapes pour les indicateurs de progression \{#step-states-for-progress-indicators\} :::link Article principal : [Indicateurs de progression](builder-loaders-and-progress-bars#step-states) ::: Les indicateurs de progression montrent aux utilisateurs où ils en sont dans un flow d'onboarding. Chaque étape dispose de trois états : - **Completed** : Les étapes que l'utilisateur a déjà franchies. - **Current** : L'étape en cours de l'utilisateur. - **Upcoming** : Les étapes que l'utilisateur n'a pas encore atteintes. --- # File: builder-containers --- --- title: "Éléments de mise en page : conteneurs, carrousels, feuilles du bas" description: "Regroupez des éléments en conteneurs, carrousels et feuilles du bas dans le Flow Builder." --- Les éléments de mise en page regroupent d'autres éléments et contrôlent leur disposition à l'écran. :Le Flow Builder comprend cinq types d'éléments de mise en page : - **Conteneurs** : disposent les enfants selon un axe — verticalement ou horizontalement - **Carrousel** : un conteneur à défilement qui affiche une diapositive à la fois - **Feuille du bas** : un panneau qui remonte depuis le bas de l'écran et s'affiche par-dessus le contenu sous-jacent - **Pied de page** : un panneau épinglé en bas de l'écran, en dehors de la zone de défilement - **Séparateurs** : de fines lignes qui séparent des lignes ou des colonnes :::link Les **onglets** relèvent également de cette catégorie, mais font l'objet d'un article séparé. Consultez [Onglets](builder-tabs) pour plus de détails. ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/ZlI-1D1a0cU?si=F0Kqf9EmyvwcQMp8" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Conteneurs \{#containers\} :::link Article principal : [Mise en page et positionnement](manage-paywall-ui-elements) ::: Les conteneurs regroupent des éléments verticalement ou horizontalement. Le **Conteneur vertical** dispose les éléments en lignes ; le **Conteneur horizontal** les dispose en colonnes. :::tip Imbriquez des conteneurs les uns dans les autres pour composer des mises en page plus complexes. ::: ### Changer la direction du conteneur \{#change-container-direction\} La direction d'un conteneur n'est pas figée. Basculez entre **Vertical**, **Horizontal** et **Libre** dans la section **Mise en page** du panneau droit à tout moment — pas besoin de supprimer et de recréer le conteneur. Configurez l'espacement, l'alignement et la distribution dans la même section **Mise en page**. Les enfants s'affichent dans l'ordre où ils apparaissent dans le panneau **Calques** — faites-les glisser pour les réordonner. ### Envelopper et désenvelopper \{#wrap-and-unwrap\} Pour transformer un élément existant en conteneur, sélectionnez-le et utilisez l'[action de calque](paywall-layout-and-products#layer-actions) **Envelopper**. Faites glisser des éléments supplémentaires dans le nouveau conteneur depuis le panneau **Calques**. Pour supprimer un conteneur et faire remonter ses enfants d'un niveau, utilisez **Désenvelopper**. ## Carrousel \{#carousel\} Un **Carrousel** est un conteneur à défilement qui affiche une diapositive à la fois. L'utilisateur fait glisser horizontalement pour voir la diapositive suivante, ou le carrousel avance automatiquement selon une minuterie. Un Carrousel contient un ensemble de calques **Diapositive**. Lorsqu'une diapositive est active, les éléments de ce calque apparaissent à l'écran. Contrairement aux onglets, la diapositive active du carrousel n'est pas exposée comme un [groupe sélectionnable](flow-selectable-elements) — les diapositives ne peuvent pas être référencées dans des conditions ou du texte dynamique. Utilisez un Carrousel pour la rotation visuelle, pas pour des embranchements pilotés par l'utilisateur. ### Changer la diapositive active \{#change-active-slide\} Lorsque vous sélectionnez le carrousel, le builder affiche une barre de contrôle contextuelle avec un menu déroulant **Diapositive** et un bouton **+ Ajouter une diapositive**. - Cliquez sur **+ Ajouter une diapositive** pour ajouter une nouvelle diapositive vide. - Utilisez le menu déroulant **Diapositive** pour choisir quelle diapositive est active sur le canevas — ou cliquez sur le calque Diapositive correspondant dans le panneau **Calques**. Pour réordonner les diapositives, faites-les glisser à l'intérieur du Carrousel dans le panneau Calques. {/* TODO: on-device GIF */} ### Propriétés \{#properties\} #### Défilement automatique \{#auto-scroll\} Le défilement automatique fait défiler les diapositives automatiquement — l'utilisateur n'a pas besoin de faire glisser pour voir tout le contenu. Deux contrôles de minuterie définissent son comportement : - **Délai** — durée pendant laquelle chaque diapositive reste visible (ms). - **Durée** — durée de la transition entre les diapositives (ms). #### Taille du carrousel \{#carousel-sizing\} Des contrôles dédiés déterminent la taille du carrousel et l'espacement entre les diapositives adjacentes. Définissez la **Hauteur** sur **Fixe** pour éviter que la mise en page ne se décale lorsque l'utilisateur fait défiler entre des diapositives de longueurs de contenu différentes. #### Taille des diapositives \{#slide-sizing\} **Largeur** et **Hauteur** par diapositive. Par défaut sur Remplir afin que chaque diapositive suive les dimensions du carrousel. Définissez une largeur fixe pour créer un effet d'aperçu où les diapositives adjacentes sont partiellement visibles. #### Points \{#dots\} L'indicateur de page en bas du carrousel. Il indique à l'utilisateur combien de diapositives existent et laquelle est active. Désactivez le bouton **Afficher les points** pour masquer l'indicateur de diapositive. Lorsque les points sont visibles, les propriétés suivantes contrôlent leur apparence : - **Couleur** — remplissage d'un point inactif. - **Couleur active** — remplissage du point pour la diapositive actuellement visible. - **Taille** — diamètre de chaque point, en pixels. - **Écart** — espacement entre les points adjacents. - **Rembourrage** — espace entre la rangée de points et le contenu du carrousel au-dessus. ## Feuille du bas \{#bottom-sheet\} :::link Procédure : [Afficher tous les plans dans une feuille du bas](show-plans-bottom-sheet) ::: Une **Feuille du bas** est un panneau de mise en page qui remonte depuis le bas de l'écran, par-dessus le contenu sous-jacent. La feuille floute toujours ce qui se trouve derrière elle ; ce flou ne peut pas être désactivé. Déclenchez-la au toucher — par exemple, derrière un lien **Voir tous les plans** — plutôt qu'au chargement de l'écran. ### Structure \{#structure\} Une Feuille du bas est livrée avec deux calques de premier niveau : - **En-tête** — un conteneur en haut de la feuille, prérempli avec un calque de texte **Titre** et un **Bouton Fermer** Close. Modifiez-les ou supprimez-les selon vos besoins. - **Contenu** — le conteneur principal. Ajoutez-y des produits, des boutons, des liens ou tout autre élément. {/* TODO: on-device GIF */} ### Visibilité initiale \{#initial-visibility\} Par défaut, une feuille du bas apparaît dès que l'écran s'affiche. Pour l'ouvrir à la demande à la place : 1. **Remplissez d'abord le contenu de la feuille** — les calques masqués ne peuvent pas être modifiés, donc la feuille doit rester visible jusqu'à ce que vous ayez terminé de la remplir. 2. Dans le panneau **Calques**, sélectionnez la feuille du bas. 3. Définissez la **Visibilité** sur **Masquer** Hide. La feuille reste dans l'arborescence des calques mais cesse de s'afficher à l'écran. ### Déclencher la feuille du bas \{#triggering-the-bottom-sheet\} Pour ouvrir une feuille du bas masquée, attachez une action **Afficher** à un autre élément : 1. Sélectionnez l'élément déclencheur (par exemple, un bouton ou un lien texte). 2. Ouvrez l'onglet **Interactions** dans le panneau droit. 3. Cliquez sur **Ajouter un déclencheur** > **Au toucher**, puis sur **Ajouter une action**. 4. Définissez l'**Action** sur **Afficher** et sélectionnez la feuille du bas dans le menu déroulant. ## Pied de page \{#footer\} Un **Pied de page** est un conteneur fixe qui occupe la partie inférieure d'un écran. Il peut avoir n'importe quelle hauteur et contenir n'importe quoi, d'un simple bouton à plusieurs lignes de texte. Utilisez le pied de page pour le contenu qui doit rester en place pendant que le reste de l'écran défile — boutons d'appel à l'action, mentions légales, liens. Contrairement aux éléments classiques, le pied de page s'étend jusqu'à la zone de sécurité inférieure de l'appareil : son arrière-plan va jusqu'au bord de l'écran. Un seul pied de page est autorisé par écran. Vous ne pouvez pas dupliquer un pied de page existant, ni en ajouter un nouveau. ### Pied de page vs. un élément fixe ordinaire \{#footer-vs-a-regular-fixed-element\} Les deux restent à l'écran pendant que le contenu défile. Choisissez l'option qui correspond à votre besoin : - **Utilisez un Pied de page** pour la barre inférieure principale de l'écran (bouton d'appel à l'action, mentions légales, liens). Il réserve sa propre hauteur, de sorte que le contenu défile toujours au-dessus de lui et ne se cache jamais derrière lui, et il couvre automatiquement la zone de sécurité inférieure. - **Utilisez un [élément fixe](manage-paywall-ui-elements)** pour quelque chose qui doit flotter au-dessus du contenu défilant plutôt que de réserver de l'espace, ou qui s'épingle à un bord autre que le bas — un bouton de fermeture/restauration flottant, une bannière persistante en haut, un contrôle de retour en haut. Vous gérez vous-même l'espacement de la zone de sécurité. ## Séparateurs \{#dividers\} Le **Séparateur horizontal** et le **Séparateur vertical** sont de fines lignes qui séparent le contenu. Utilisez le Séparateur horizontal pour diviser des lignes, et le Séparateur vertical pour diviser des colonnes à l'intérieur d'un conteneur horizontal. Ajustez l'épaisseur, la couleur et la longueur depuis le panneau droit. --- # File: onboarding-text --- --- title: "Ajouter et styliser du texte et des listes dans le Flow Builder" description: "Ajoutez et stylisez des titres, sous-titres, paragraphes et listes dans le flow builder d'Adapty, et personnalisez le texte pour des expériences utilisateur cohérentes avec votre marque." --- Ajoutez des titres, des paragraphes ou des listes en un clic, stylisez-les pour correspondre à votre charte graphique, et utilisez des [variables dynamiques](onboarding-variables) pour personnaliser le contenu pour chaque utilisateur. ## Configurer les styles de texte \{#set-up-text-styles\} Le panneau **Styles** contient des styles de texte préconfigurés : H1, H2, H3, Button Label, Body, Caption et Small Label. Cliquez sur un style pour modifier sa famille de polices, son graisse, sa taille, son alignement, sa décoration et d'autres propriétés. Lorsque vous [ajoutez un élément texte](#add-text), vous pouvez choisir parmi les styles que vous avez configurés ici. :::important Les modifications apportées à un style s'appliquent à tous les éléments texte qui l'utilisent, sur tous les écrans. ::: Pour créer un nouveau style : 1. Cliquez sur Palette pour ouvrir le panneau **Styles**. 2. Dans l'onglet **Text**, cliquez sur **Create style**. 3. Entrez un nom et configurez la typographie — famille de polices, graisse, alignement et [autres propriétés](#typography-properties). :::warning Les [polices personnalisées](using-custom-fonts-in-flow-builder) se comportent différemment des polices intégrées. Lisez le guide — certains contrôles ne s'appliquent pas, et chaque variante de police nécessite son propre fichier. ::: 4. Cliquez sur **Create**. ## Ajouter du texte \{#add-text\} Pour ajouter un élément texte : 1. Cliquez sur **+** en haut à gauche. Sélectionnez **Text**. Choisissez l'un des [styles de texte](#set-up-text-styles) préconfigurés ou définis par vous. 2. Cliquez sur le nouvel élément et modifiez son contenu dans la section **Content** du panneau **Design** à droite. 3. Si nécessaire, ajustez les [propriétés typographiques](#typography-properties) dans le panneau **Design**. Ou sélectionnez le texte dans l'aperçu pour ouvrir une infobulle de personnalisation rapide du style. 4. Optionnellement, dans les panneaux **Design** et **Interaction**, vous pouvez également appliquer d'autres configurations disponibles pour les composants dans le flow. Pour plus de détails, voir [Styles et apparence](builder-styling). :::tip Si vous devez utiliser le même élément texte sur plusieurs écrans, copiez-collez-le : sélectionnez l'élément, appuyez sur Ctrl+C (ou ⌘+C sur Mac), naviguez vers un autre écran, et appuyez sur Ctrl+V (ou ⌘+V sur Mac) pour coller. ::: ### Modifier le style d'une partie du texte \{#change-styling-for-parts-of-text\} :::warning La mise en forme **Gras** et **Italique** n'a aucun effet sur les textes utilisant des [polices personnalisées](using-custom-fonts-in-flow-builder). Pour appliquer des variantes d'une police personnalisée, importez chaque variante comme un fichier de police séparé et sélectionnez-la dans le menu déroulant **Font family**. ::: Pour modifier le style d'une partie seulement d'un élément texte : 1. Sélectionnez une partie d'un élément texte dans la section **Content**. 2. Dans l'infobulle qui apparaît, changez la couleur du texte, appliquez une mise en forme gras, soulignement, italique ou barré, ou ajoutez une URL. L'aperçu se met à jour immédiatement. ## Ajouter un ancien prix \{#add-an-old-price\} L'élément Ancien Prix affiche un prix gonflé « avant » à côté du vrai prix d'un produit, pour que la remise soit visible d'un coup d'œil. Il affiche le prix du produit multiplié par un facteur que vous choisissez et le barre automatiquement. Vous n'éditez pas le contenu de l'élément. La valeur est calculée à partir du prix du produit dans le store au moment de l'exécution, donc la devise correspond toujours au vrai prix. Pour ajouter un ancien prix : 1. Cliquez sur **+** en haut à gauche. Sélectionnez **Text**, puis sélectionnez **Old Price**. 2. Dans le panneau **Layers**, faites glisser l'élément à l'intérieur d'une fiche produit. L'élément fonctionne également à l'intérieur des fiches produit enregistrées comme composants réutilisables. :::important L'élément Ancien Prix doit se trouver à l'intérieur d'une fiche produit — le prix est pris depuis le produit de cette fiche. En dehors d'une fiche produit, le builder affiche un espace réservé « Old price » au lieu d'un prix. ::: 3. Dans le panneau **Design**, dans la section **Price**, définissez le **Multiplier**. Adapty multiplie le prix du produit par cette valeur. Par exemple, avec le multiplicateur par défaut de 2, un produit à 12,99 $ affiche un prix barré de 25,98 $. 4. Si nécessaire, ajustez les [propriétés typographiques](#typography-properties). L'élément prend en charge le même style que le texte ordinaire. :::tip Pour barrer le vrai prix d'un autre produit — par exemple, le prix du plan mensuel sur une fiche annuelle — construisez la ligne de prix avec des éléments texte et des variables. Voir [Afficher un prix barré avec un badge de remise](strikethrough-price). ::: ## Propriétés typographiques \{#typography-properties\} Tous les éléments texte et styles de texte partagent le même ensemble de contrôles typographiques : - **Font family** : Choisissez une police — une police intégrée ou une [police personnalisée](using-custom-fonts-in-flow-builder). :::warning Les différents appareils incluent des polices différentes, ou peuvent restituer la même police différemment. Si la police n'est pas présente sur l'appareil, le système utilisera une police par défaut (SF Pro / Roboto). Pour afficher la même police de manière cohérente sur tous les appareils, importez une [police personnalisée](using-custom-fonts-in-flow-builder). ::: - **Weight** : Définit la graisse de la police. :::warning Les contrôles **Weight**, **Bold** et **Italic** ne s'appliquent pas aux [polices personnalisées](using-custom-fonts-in-flow-builder), qu'ils soient définis dans le panneau **Styles**, la section typographie du panneau **Design**, la barre d'outils en ligne ou l'infobulle de formatage de partie de texte. Pour appliquer des variantes d'une police personnalisée, importez chaque variante comme un fichier de police séparé et sélectionnez la bonne dans le menu déroulant **Font**. ::: - **Size** : Définit la taille de la police en pixels. - **Color** : Définit la couleur du texte. - **Line height** : Définit l'espacement entre les lignes, ou laissez-le sur **Auto**. - **Alignment** : Définit l'alignement horizontal (gauche, centre, droite) et vertical (haut, milieu, bas). - **Decoration** : Applique un soulignement ou un barré. - **Truncate** : Limite le nombre de lignes affichées. Le texte au-delà de cette limite est tronqué. Utile quand la longueur du contenu varie en raison de variables dynamiques ou de la localisation. ## Ajouter des liens \{#add-links\} Les flows offrent deux façons de transformer du texte en liens cliquables. Choisissez en fonction du rôle que joue le texte : - **Lien en ligne** — pour une URL dans du texte courant, comme une référence « En savoir plus » intégrée dans un paragraphe. S'ouvre toujours dans le navigateur intégré à l'application. - **Une action Open URL** — pour des cibles autonomes, comme un bouton Conditions d'utilisation. Peut s'ouvrir dans le navigateur intégré ou externe. ### Lien en ligne \{#inline-link\} Pour transformer une partie d'un élément texte en lien : 1. Sélectionnez le texte dans la section **Content**. 2. Dans l'infobulle de formatage, cliquez sur l'icône de lien. 3. Collez l'URL de destination dans la fenêtre contextuelle. ### Action Open URL \{#open-url-action\} :::link Article principal : [Actions](onboarding-actions#open-url) ::: Pour transformer un bouton entier en lien : 1. Ajoutez un [Bouton](builder-elements#buttons) — ou utilisez le preset **Links**, une rangée prête à l'emploi avec des boutons Restore / Terms of Service / Privacy Policy. 2. Sélectionnez le bouton dans le panneau **Layers** et ouvrez l'onglet **Interactions** dans le panneau de droite. 3. Définissez la destination pour l'action [**Open URL**](onboarding-actions#open-url). :::important Une action Open URL vide [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). ::: ## Ajouter du texte conditionnel \{#add-conditional-text\} Le texte conditionnel modifie ce qu'affiche un élément texte en fonction d'une condition. Par exemple, un titre peut afficher un message quand un utilisateur sélectionne le plan annuel et un message différent pour le plan mensuel. Le texte conditionnel fonctionne comme la [visibilité conditionnelle](onboarding-element-visibility), mais il remplace le contenu au lieu d'afficher ou masquer l'élément. Pour configurer le texte conditionnel : 1. Sélectionnez un élément texte sur le canvas. 2. Dans le panneau **Design**, dans la section **Content**, sélectionnez **Conditional**. 3. Construisez la condition **if**. Choisissez une propriété dans l'onglet **Custom**, **Products** ou **Elements**, définissez l'opérateur et entrez la valeur à correspondre. Pour plus de détails sur les types de propriétés, voir [Visibilité conditionnelle](onboarding-element-visibility). 4. Sous **then**, entrez le texte à afficher quand la condition est vraie. La mise en forme de texte enrichi fonctionne de la même façon que pour le [texte ordinaire](#change-styling-for-parts-of-text). Pour insérer une [variable](onboarding-variables), cliquez sur **{ } Add variable**. 5. Sous **else**, entrez le texte de secours à afficher quand aucune condition ne correspond. 6. (Optionnel) Cliquez sur **+ Add else/if** pour ajouter d'autres conditions, chacune avec son propre texte. :::tip Pour modifier le texte conditionnel dans une autre langue, changez la locale active en bas de l'éditeur. Ajoutez d'abord des langues dans le panneau **Localizations** — voir [Ajouter une locale dans le Flow Builder](add-paywall-locale-in-adapty-paywall-builder). ::: ## Ajouter des listes \{#add-lists\} :::note Les éléments de liste sont des conteneurs composés de composants d'élément individuels. Pour des listes à puces ou numérotées simples dans du texte courant, utilisez un élément texte et appliquez la mise en forme souhaitée via le panneau **Design**. ::: 1. Cliquez sur **+** en haut à gauche. Sélectionnez **List** et choisissez l'un des modèles de liste. 2. Allez dans le panneau **Design** à droite pour modifier les éléments de la liste ou importer une image comme marqueur d'élément. --- # File: using-custom-fonts-in-flow-builder --- --- title: "Polices personnalisées dans le Flow Builder" description: "Importez et utilisez des polices personnalisées dans le Flow Builder." --- Lorsque vous créez des flows, vous pouvez avoir besoin d'utiliser une police personnalisée pour correspondre au reste de votre application. Voici comment ajouter des polices personnalisées et les utiliser dans vos flows. :::tip [Configurez les polices](onboarding-text) dans le panneau **Styles** avant de commencer à concevoir le flow. Ainsi, toutes les modifications que vous effectuerez s'appliqueront globalement. ::: ## Polices intégrées \{#built-in-fonts\} Lorsque vous créez un flow dans le Builder, Adapty utilise une police système par défaut. Il s'agit généralement de SF Pro sur iOS et Roboto sur Android, bien que cela puisse varier selon l'appareil. Vous pouvez également choisir parmi des polices couramment utilisées comme Arial, Times New Roman, Courier New, Georgia et Helvetica. Chacune de ces polices est disponible avec plusieurs options de style. Ces polices ne sont pas fournies dans le cadre du SDK Adapty et ne sont utilisées qu'à des fins de prévisualisation. Nous ne pouvons pas garantir qu'elles fonctionneront parfaitement sur tous les appareils. Cependant, d'après nos tests, ces polices sont généralement reconnues par la plupart des appareils sans effort supplémentaire de votre part. Vous pouvez également [consulter les polices disponibles par défaut sur iOS](https://developer.apple.com/fonts/system-fonts/). ## Ajouter une police personnalisée \{#add-a-custom-font\} :::warning Le fichier que vous importez est **uniquement destiné à la prévisualisation dans l'éditeur** — Adapty ne le distribue pas aux appareils des utilisateurs. Pour afficher la police sur l'appareil, [incluez le fichier dans le bundle de votre application](#add-the-font-files-to-your-apps-bundle). Sans cela, le SDK utilisera SF Pro (iOS) ou Roboto (Android) au moment de l'exécution. ::: Si vous avez besoin d'utiliser des polices autres que la police système par défaut, vous pouvez ajouter une police personnalisée. Pour ajouter une police personnalisée : 0. Si la police est variable, divisez-la en fichiers à style unique avec des noms uniques. Les contrôles de graisse, gras et italique ne s'appliquent pas aux polices personnalisées. Adapty n'enregistre qu'un seul style par fichier de police personnalisée. Pour [mettre en forme le texte](onboarding-text), basculez vers la variante de police appropriée. 1. Choisissez **Upload new font** dans l'un des menus déroulants de police. 2. Dans la fenêtre **Add custom font**, renseignez les champs suivants : :::warning Les champs **Font name in Builder**, **iOS font name** et **Android font name** doivent chacun être uniques parmi tous les fichiers de polices personnalisées de l'application. ::: - **Font name in Builder** : Saisissez un nom d'affichage pour la police. Ce nom apparaîtra dans les menus déroulants de police du Builder. - **iOS font name** : Saisissez le nom PostScript de la police. Vous pouvez le trouver dans Font Book → PostScript name, ou via l'[API `UIFont`](https://developer.apple.com/documentation/uikit/uifont). - **Android font name** : Saisissez le nom de fichier depuis `res/font/`. Utilisez uniquement des lettres minuscules, des chiffres et des tirets bas. - **Font file** : Glissez-déposez le fichier de police ou cliquez sur **Select files**. Formats pris en charge : `.ttf`, `.otf`, `.woff`, `.woff2`. 3. Cliquez sur **Save font**. En important le fichier de police dans Adapty, vous confirmez que vous disposez du droit de l'utiliser dans votre application. ### Supprimer une police personnalisée \{#delete-a-custom-font\} La suppression d'une police personnalisée depuis le tableau de bord remplace silencieusement toutes les références à cette police par la police système dans les flows brouillons et publiés. Aucun avertissement n'est affiché et cette action est irréversible. Avant de supprimer, assurez-vous qu'aucun flow en production n'utilise cette police. ## Polices personnalisées dans les modèles de flow \{#custom-fonts-in-flow-templates\} La [bibliothèque de modèles de flow](paywall-builder-templates) comprend des modèles avec des polices personnalisées. Survolez l'étiquette **Custom font** sur une carte de modèle pour voir quelles polices il utilise. Adapty ne fournit pas ces polices. Vous devez les obtenir vous-même en faisant correspondre les noms de polices indiqués sur l'étiquette. Certaines polices peuvent nécessiter une licence commerciale. Une fois que vous disposez des fichiers de polices, suivez les étapes d'intégration ci-dessous. ## Ajouter les fichiers de polices au bundle de votre application \{#add-the-font-files-to-your-apps-bundle\} Si vous utilisez déjà une police personnalisée ailleurs dans votre application, il vous suffit d'ajouter vos polices de paywall de la même manière. Sinon, veillez à inclure le fichier de police dans le projet et le bundle de votre application. Lisez comment procéder ci-dessous : - Sur iOS : [Dans la documentation officielle Apple](https://developer.apple.com/documentation/uikit/adding-a-custom-font-to-your-app) - Sur Android : [Dans la documentation officielle Android](https://developer.android.com/develop/ui/views/text-and-emoji/fonts-in-xml) --- # File: paywall-head-picture --- --- title: "Arrière-plans" description: "Remplissez un écran avec un arrière-plan uni, dégradé, image ou vidéo dans le Flow Builder." --- Définissez un arrière-plan sur n'importe quel écran via le panneau **Fill** dans les [**Screen settings**](paywall-layout-and-products#screen-settings). Choisissez parmi quatre types d'arrière-plan : couleur unie, dégradé, image ou vidéo. ## Image \{#image\} Importez un fichier `.JPG`, `.PNG` ou `.WEBP` de 20 Mo maximum. L'image est mise à l'échelle pour couvrir l'intégralité de l'arrière-plan. :::note Les images et vidéos d'arrière-plan remplissent tout le viewport, y compris les zones derrière l'encoche et les barres système — même lorsque **Safe area** est activée. Gardez le contenu important loin des bords pour éviter qu'il ne soit rogné. ::: Pour changer l'image d'arrière-plan à l'exécution depuis le code de votre application, activez un [ID média personnalisé](custom-media#custom-media-id). ## Vidéo \{#video\} Importez un fichier `.MP4` ou `.WEBM` de 50 Mo maximum. L'aperçu affiche une image fixe, mais la vidéo est lue sur l'appareil à l'exécution. Activez **Loop** pour rejouer la vidéo en boucle. Pour remplacer la vidéo d'arrière-plan à l'exécution, activez un [identifiant de média personnalisé](custom-media#custom-media-id). ## Couleur unie \{#solid-color\} Saisissez une valeur hexadécimale et définissez l'opacité de 0 à 100 %. Choisissez un [style de couleur](builder-styling) enregistré dans la palette pour appliquer la couleur de votre marque — l'arrière-plan suit automatiquement vos thèmes clair et sombre. ## Dégradé \{#gradient\} Créez un dégradé linéaire à plusieurs arrêts : - **Direction** — faites pivoter le dégradé de 0 à 360°. - **Stops** — faites glisser le long de la barre pour repositionner. Cliquez sur un arrêt pour modifier sa valeur hexadécimale et son opacité. --- # File: custom-media --- --- title: "Images, vidéos et icônes" description: "Ajoutez des éléments image, vidéo et icône à un écran dans le Flow Builder, et remplacez les médias à l'exécution avec des identifiants personnalisés." --- Le Flow Builder propose trois types d'éléments médias dans la catégorie **Media** : Image, Video et Icon. :::tip Pour qu'une image ou une vidéo couvre tout l'écran — y compris les zones derrière l'encoche et l'indicateur d'accueil — positionnez-la en fixe avec tous les décalages à 0 et sélectionnez **Ignore safe area**. Voir [Mise en page et positionnement](manage-paywall-ui-elements#ignore-safe-area). ::: ## Image \{#image\} Importez un fichier `.JPG`, `.PNG` ou `.WEBP` de 20 Mo maximum. Les GIFs et WEBP animés ne sont pas pris en charge. Pour ajouter du mouvement, utilisez plutôt un élément [Video](#video). - **Aspect** — contrôle comment l'image s'adapte à son conteneur : - **Fit** — redimensionne l'image pour qu'elle tienne dans le conteneur sans recadrage. - **Fill** — étire l'image pour remplir le conteneur. - **Cover** — redimensionne l'image pour couvrir le conteneur, en recadrant si nécessaire. Par défaut. - **Use custom media ID** — voir [Custom media ID](#custom-media-id) ci-dessous. ## Vidéo \{#video\} Importez un fichier `.MP4` ou `.WEBM` de 50 Mo maximum et d'une durée maximale de 30 secondes. La résolution minimale est de 640x640 pixels. - **Aspect** — Fit, Fill ou Cover. Fill par défaut. - **Loop** — rejouer la vidéo en boucle. Activé par défaut. - **Use custom media ID** — voir [Custom media ID](#custom-media-id) ci-dessous. Les vidéos ne sont pas lues dans l'aperçu de l'éditeur — le canevas affiche une image fixe. Sur l'appareil au moment de l'exécution, la vidéo est lue sans son par défaut. Avec Loop activé, elle se répète indéfiniment. ### Déclencher une action à la fin de la vidéo \{#trigger-an-action-when-the-video-ends\} :::link Article principal : [Actions](onboarding-actions) ::: L'élément Vidéo prend en charge un déclencheur **On playback finished** qui s'active lorsque la vidéo arrive à sa fin. Configurez-le dans le panneau **Interactions** pour naviguer vers un autre écran, afficher un CTA ou exécuter toute autre action. ## Icône \{#icon\} Choisissez parmi la bibliothèque [Tabler Icons](https://tabler.io/icons) intégrée, qui propose des milliers d'icônes en deux styles visuels : - **Stroke** — contour uniquement. - **Filled** — remplissage plein. Recherchez une icône dans le sélecteur par mot-clé. Définissez la couleur de l'icône dans le sélecteur **Color** — choisissez un [style de couleur](builder-styling) enregistré ou définissez une couleur personnalisée. ## Localiser les médias \{#localize-media\} :::link Article principal : [Ajouter une locale](add-paywall-locale-in-adapty-paywall-builder) ::: Les éléments Image et Vidéo peuvent contenir un fichier différent par locale. Activez la locale cible, sélectionnez l'élément, puis téléchargez le fichier localisé dans le panneau des propriétés. Les locales sans fichier propre affichent le fichier de la locale par défaut. ### Limitations \{#limitations\} Vous ne pouvez pas localiser les éléments suivants : - Les icônes - Les arrière-plans d'écran - Les identifiants de médias personnalisés ## ID média personnalisé \{#custom-media-id\} :::important Vous pouvez également définir un ID média personnalisé pour une image et une vidéo en [arrière-plan](paywall-head-picture). ::: Associez un ID média personnalisé à un élément image ou vidéo pour le remplacer au moment de l'exécution depuis le code de votre application. Utilisez cette fonctionnalité pour des [visuels personnalisés](get-pb-paywalls#customize-assets) — par exemple, pour afficher l'avatar choisi par l'utilisateur. Le média que vous importez dans le Flow Builder sert de secours. Si votre code ne fournit pas de média pour cet ID au moment de l'exécution, c'est le média de secours qui s'affiche. Pour activer un ID média personnalisé sur un élément Image ou Vidéo : 1. Cochez la case **Use custom media ID** sous la zone de téléchargement. 2. Saisissez un identifiant de média. 3. Téléchargez une image ou vidéo de secours. Dans le code de votre application, récupérez le média par son identifiant — consultez [Personnaliser les assets](get-pb-paywalls#customize-assets) pour l'API SDK. --- # File: paywall-buttons --- --- title: "Boutons dans le Flow Builder" description: "Ajoutez et configurez des boutons d'action dans le Flow Builder." --- :::info Cette section décrit le nouveau Flow Builder, qui fonctionne avec les SDK Adapty version 4.0 ou supérieure. ::: Les boutons sont les éléments interactifs du Flow Builder qui réagissent aux appuis des utilisateurs. Utilisez-les pour : - Les CTA d'achat qui se connectent aux produits et traitent les transactions automatiquement - La navigation — déplacer les utilisateurs entre les écrans (Suivant, Retour, Fermer, Ignorer) - Les liens utilitaires — Restaurer les achats, Conditions d'utilisation et Politique de confidentialité :::tip Placez les CTA d'achat, les liens de restauration et les liens légaux dans un [Pied de page](builder-containers#footer) — il est épinglé en bas de l'écran et masque les éléments défilants en dessous. ::: ## Ajouter des boutons \{#add-buttons\} Pour ajouter un bouton : 1. Cliquez sur **+** et sélectionnez **Button**. 2. Sélectionnez un type de bouton. <img src="/assets/shared/img/button-type.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Les boutons d'achat, les liens et les boutons de fermeture sont fournis avec des actions préconfigurées. Pour les liens, [configurez les URL de navigation des utilisateurs](#links). Pour les autres types de boutons, accédez au panneau **Interactions**. Là, dans la section **Button triggers**, configurez les [actions](onboarding-actions) que le bouton doit effectuer. <img src="/assets/shared/img/button-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Configurez le [design du bouton](builder-styling) dans le panneau **Design**. ## Types de boutons \{#button-types\} ### Boutons d'achat \{#purchase-buttons\} :::link Pour que les boutons d'achat fonctionnent, associez des produits aux écrans et ajoutez l'élément **Products**. Consultez le [guide](paywall-product-block). ::: Un bouton d'achat lance l'achat intégré pour le produit que l'utilisateur a sélectionné sur l'écran. Le SDK traite la transaction automatiquement, vous n'avez donc pas besoin de gérer les achats dans le code de l'application. Pour ajouter un bouton d'achat : 1. Cliquez sur **+** et sélectionnez **Button**, puis choisissez un preset de bouton. 2. Avec le bouton sélectionné, ouvrez l'onglet **Interactions** dans le panneau de droite. 3. Cliquez sur **Add trigger** > **On tap**, puis cliquez sur **Add action**. 4. Définissez **Action** sur **Purchase** et **Product** sur `products.selectedProduct`. La variable `products.selectedProduct` correspond toujours au produit actuellement sélectionné sur l'écran. :::tip Vous pouvez attirer davantage l'attention sur les boutons d'achat en les animant. Le Paywall Builder prend actuellement en charge le type d'animation **Pulse**. Configurez le style d'animation dans le panneau **Design**. ::: <img src="/assets/shared/img/purchase-button.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Liens \{#links\} :::important Les boutons **Terms of Use** et **Privacy Policy** disposent d'une action **Open URL** intégrée. Définissez l'URL de destination à cet endroit. Les URL vides dans Open URL et les [liens en ligne](onboarding-text#inline-link) bloquent la prévisualisation et la publication. ::: Pour respecter certaines exigences des stores, vous pouvez ajouter des liens vers : - Les conditions d'utilisation - La politique de confidentialité - La restauration des achats Pour ajouter des liens : 1. Cliquez sur **+** et sélectionnez **Button > Links**. Cela ajoutera une rangée de boutons en ligne avec des actions prédéfinies : restaurer les achats ou ouvrir une URL. Si vous n'avez pas besoin de tous les boutons inclus, supprimez ceux dont vous n'avez pas besoin dans le panneau des calques. <img src="/assets/shared/img/add-links.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Configurez maintenant les actions des boutons : - Le bouton **Restore purchases** gère déjà la restauration des achats. - Pour chaque lien restant : 1. Cliquez sur le bouton pour le sélectionner et passez à l'onglet **Interactions** à droite. 2. Collez l'URL dans le champ. 3. Par défaut, l'URL s'ouvre dans un navigateur intégré à l'application pour une expérience utilisateur fluide. Si vous souhaitez rediriger les utilisateurs vers un navigateur externe, cochez la case **Open in external browser**. <img src="/assets/shared/img/pb-links.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Fermer le flow \{#close-flow\} Le bouton **Close** ferme le flow automatiquement. Pour ajouter un bouton de fermeture, cliquez sur **+** et sélectionnez **Button > Close flow**. <img src="/assets/shared/img/close-flow.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::tip Utilisez la position **Absolute** pour placer votre bouton de fermeture dans le coin de l'écran. ::: Vous pouvez également configurer n'importe quel autre bouton pour fermer le flow à l'aide des [actions](onboarding-actions). ### Boutons personnalisés \{#custom-buttons\} Tout bouton que vous ajoutez peut être configuré pour effectuer n'importe quelle action lors d'un appui : - Naviguer vers l'écran suivant - Afficher une alerte - Définir une [variable](onboarding-variables) - [Afficher ou masquer des éléments de l'écran](onboarding-element-visibility) - Ouvrir des URL - Restaurer les achats - Effectuer des actions conditionnelles --- # File: builder-tabs --- --- title: "Tabs" description: "Ajoutez une navigation par onglets qui change les panneaux de contenu dans un flow." --- **Tabs** divise une section d'écran en panneaux de contenu commutables — l'utilisateur appuie sur un en-tête d'onglet et le panneau en dessous se met à jour en conséquence. {/* TODO: on-device GIF */} ## Ajouter, supprimer et sélectionner des onglets \{#add-remove-and-select-tabs\} Chaque onglet est composé de deux parties - **En-tête d'onglet** — le libellé cliquable (Tab 1, Tab 2, etc.). - **Contenu de l'onglet** — un conteneur par onglet. Tout ce que vous placez dans un conteneur de contenu s'affiche lorsque son onglet est sélectionné. Cliquez sur **Add tab** pour ajouter un nouvel onglet. Chaque nouvel onglet obtient un conteneur de contenu correspondant. Pour qu'un onglet spécifique soit actif à l'affichage initial de l'écran, activez **Selected by default**. ## Styliser les onglets \{#style-the-tabs\} ### Templates \{#templates\} Le Flow Builder propose trois templates d'onglets prêts à l'emploi : - **Segment control** — un sélecteur en forme de pilule avec des coins arrondis autour de l'onglet sélectionné. - **Button Tabs** — onglets distincts avec un style de bouton. - **Underline** — libellés textuels avec un soulignement indiquant l'onglet sélectionné. ### États des onglets \{#tab-states\} Chaque onglet individuel dispose d'un sélecteur d'état (**Default / Selected**) pour styliser séparément les états actif et inactif — typographie, couleurs, remplissage et bordure par état. ## Groupe sélectionnable \{#selectable-group\} Les onglets forment un **groupe sélectionnable à choix unique** — exactement un onglet est actif à la fois. Gérez le groupe depuis le panneau **Screen settings**, dans la section [Selectable groups](paywall-layout-and-products#selectable-groups). Le groupe expose deux variables : - `tabs.selectedOptionId` — l'ID de l'onglet sélectionné. Utilisez-la dans les conditions. - `tabs.selectedOptionTitle` — le libellé de l'onglet sélectionné. Utilisez-la dans le texte dynamique. Remplacez `tabs` par votre **Group ID** personnalisé si vous avez renommé le groupe. Consultez [Éléments et groupes sélectionnables](flow-selectable-elements) pour une vue d'ensemble complète. --- # File: builder-toggles --- --- title: "Toggles" description: "Ajoutez des interrupteurs à vos flows de paiement." --- :::warning Apple peut rejeter les applications qui utilisent un toggle d'essai présélectionné. Un toggle activé par défaut peut être signalé comme un dark pattern manipulateur selon les directives de révision de l'App Store — cela implique le consentement de l'utilisateur à un essai gratuit sans choix explicite. Pour éviter un rejet, réglez le toggle sur **off** par défaut et laissez les utilisateurs activer l'essai eux-mêmes. ::: Un toggle d'essai est un interrupteur binaire qui permet aux utilisateurs de choisir entre des produits standard et des produits avec essai sur un paywall. Lorsque l'utilisateur change son état, cela peut déclencher une action — comme permuter des groupes de produits, mettre à jour des variables, ou afficher et masquer des éléments — instantanément. Pour ajouter un toggle d'essai, cliquez sur **+** sur l'écran cible et sélectionnez **Trial toggle**. Chaque toggle d'essai est un élément sélectionnable de type **Toggle**. Chaque élément sélectionnable a une variable assignée pour refléter son état — par exemple, un toggle nommé `trial` obtient une variable `trial.is_selected` avec une valeur `True` ou `False`. Pour que d'autres éléments dépendent de l'état du toggle, définissez une [action](onboarding-actions) conditionnelle ou une [visibilité conditionnelle](onboarding-element-visibility) basée sur cette variable. --- # File: builder-reviews-and-testimonials --- --- title: "Avis et témoignages" description: "Ajoutez des avis, des notes et des preuves sociales à un paywall." --- La catégorie d'éléments **User Engagement** propose quatre templates pour mettre en avant des avis, des notes et des preuves sociales sur un paywall. Chaque template est une composition entièrement modifiable — remplacez le texte de substitution et appliquez vos [styles de couleur](builder-styling) et votre [typographie](onboarding-text) pour harmoniser l'ensemble du flow. ## Review \{#review\} Une carte avec une note unique, une citation et la signature de l'auteur. Utilisez-la pour mettre en avant une citation mémorable d'un utilisateur. ## Rating \{#rating\} Un compteur et une rangée d'étoiles, par exemple « 17 000+ ratings ». Utilisez-le pour souligner le volume de notes. ## App Rating \{#app-rating\} Un score mis en avant avec le nombre d'évaluations, par exemple « 4,9 / Basé sur 1 000+ avis ». Utilisez-le pour mettre en valeur un score global élevé. ## Social Proof \{#social-proof\} Un groupe d'avatars avec un nombre de membres, par exemple « Rejoignez 50 000+ utilisateurs ». Utilisez-le pour souligner la taille de la communauté. --- # File: flow-timer --- --- title: "Compte à rebours" description: "Ajoutez un compte à rebours à un paywall." --- Le **Countdown timer** décompte d'une durée fixe jusqu'à zéro — une fois arrivé à zéro, l'affichage se fige. ## Templates \{#templates\} La catégorie propose quatre variantes visuelles : - **Blocks** — Jours, heures, minutes et secondes dans des cellules séparées avec libellés. - **Inline Units** — Texte sur une seule ligne avec suffixes d'unités. - **Inline** — Chiffres seuls. - **Badge** — Affichage des chiffres en forme de pastille. ## Paramètres \{#settings\} ### Définir la durée \{#set-the-duration\} Dans la section **Countdown** du panneau droit, saisissez la durée de départ en jours, heures, minutes et secondes. ### Configurer le comportement \{#configure-the-behavior\} Le menu déroulant **Behavior** contrôle le moment où le minuteur démarre : - **Every appear** — Redémarre à chaque fois que l'utilisateur ouvre l'écran. Comportement par défaut. - **First appear** — Démarre à la première vue de l'écran par l'utilisateur dans la session d'application en cours. Continue de décompter si l'utilisateur revient pendant la même session ; se réinitialise à un nouveau lancement de l'application. - **First appear (persisted)** — Démarre à la première ouverture de l'écran et continue de décompter même après relancement de l'application. ### Déclencher une action à la fin du minuteur \{#trigger-an-action-when-the-timer-ends\} :::link Article principal : [Actions](onboarding-actions) ::: Ajoutez un déclencheur **On timer end** pour exécuter une action lorsque le compte à rebours atteint zéro — par exemple, naviguer vers un autre écran ou masquer un badge de réduction. --- # File: onboarding-quizzes --- --- title: "Quiz dans les flows" description: "Ajoutez des quiz interactifs à vos flows Adapty pour recueillir les préférences des utilisateurs et créer des flows personnalisés, sans écrire de code." --- Utilisez les quiz pour proposer aux utilisateurs des choix prédéfinis. Contrairement aux champs de saisie, les quiz n'ont pas de champs texte libres — les utilisateurs choisissent parmi les options que vous définissez. Servez-vous-en pour recueillir des préférences, segmenter les utilisateurs ou orienter le flow en fonction de leurs réponses. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/o27JCZpziVo?si=rooiCS91W0yIBgkz" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ### Ajouter un quiz \{#add-a-quiz\} 1. Cliquez sur **+** en haut à gauche. 2. Sélectionnez **Quiz**. 3. Choisissez le type de quiz : - **Options avec icône/image/emoji :** Une liste verticale d'options sélectionnables, chacune accompagnée d'une icône, d'une image ou d'un emoji et d'un libellé texte. - **Grille avec icône/image/emoji :** Une grille d'options sélectionnables, chacune avec une icône, une image ou un emoji. - **Notation :** Une échelle permettant aux utilisateurs d'exprimer une note — numérique ou sous forme d'étoiles. ### Mettre en place une navigation conditionnelle \{#set-up-conditional-navigation\} Pour rediriger les utilisateurs différemment selon leur choix, définissez une action conditionnelle sur le **bouton de navigation**, et non sur l'option du quiz : 1. Sélectionnez le bouton de navigation. 2. Dans le panneau **Interactions**, ajoutez un déclencheur **On Tap** avec une action **Conditional**. 3. Dans la boîte de dialogue **Edit Action**, configurez la ligne **if** : - À gauche, cliquez sur `{}` et sélectionnez **Elements → Screen → `<quizElementId>.selectedOptionId`** pour référencer la sélection de l'utilisateur. - Laissez l'opérateur sur `=`. - À droite, saisissez l'elementId à faire correspondre — par exemple, `rock`. 4. Sous **then**, définissez l'action sur **Navigate to** et choisissez l'écran de destination. 5. Sous **else**, définissez une destination de secours **Navigate to**, ou cliquez sur **+ Add else/if** pour ajouter d'autres conditions pour les autres options. :::link Consultez les guides correspondants pour comprendre comment utiliser les réponses aux quiz : - [Navigation conditionnelle](onboarding-navigation-branching) - [Variables](onboarding-variables) - [Actions](onboarding-actions) ::: ### Changer le type de quiz \{#change-quiz-type\} Par défaut, un quiz est en mode **multi choice** — les utilisateurs peuvent sélectionner plusieurs options à la fois. Passez en mode **single choice** si vous souhaitez qu'ils n'en choisissent qu'une seule. 1. Sélectionnez l'écran contenant le quiz. 2. Dans **Screen settings**, faites défiler jusqu'à **Selectable groups** et cliquez sur votre quiz. 3. Dans la boîte de dialogue **Edit group**, ouvrez **Group type** et choisissez : - **Single choice** — une seule option peut être sélectionnée à la fois. - **Multi choice** — les utilisateurs peuvent sélectionner plusieurs options. 4. Cliquez sur **Save**. --- # File: builder-inputs-and-forms --- --- title: "Champs de saisie et formulaires dans le Flow Builder" description: "Ajoutez des éléments de formulaire interactifs comme des champs texte et des cases à cocher." --- Utilisez les champs de saisie pour collecter des données textuelles auprès des utilisateurs — par exemple un prénom, une adresse e-mail ou une date de naissance. Enregistrez les réponses et référencez-les ailleurs dans le flow, par exemple pour s'adresser à l'utilisateur par son prénom sur un écran ultérieur. ## Ajouter un champ de saisie \{#add-an-input\} 1. Cliquez sur **+** en haut à gauche. 2. Sélectionnez **Input**. 3. Choisissez le type de champ : - **Text :** Toute saisie courte de texte. - **Email :** Adresses e-mail, avec validation de format optionnelle. - **Password :** Saisie sécurisée, avec des exigences configurables. - **Number :** Valeurs numériques, avec format configurable. - **Phone number :** Numéros de téléphone. - **Date :** Ouvre un sélecteur de date. - **Time :** Ouvre un sélecteur d'heure. - **Date and time :** Ouvre un sélecteur combiné. ## Configurer un champ de saisie \{#configure-an-input\} :::link Pour plus de détails sur les paramètres visuels — mise en page, style et visibilité — consultez [Styles et apparence](builder-styling). ::: Pour tous les types de champ, vous pouvez configurer les éléments suivants dans l'onglet **Design** : - **Type :** Modifiez le type de champ (Text, Email, Password, Number, Phone number, Date, Time ou Date and time). - **Element ID :** Identifiant utilisé pour référencer la valeur du champ ailleurs dans le flow. Voir [Utiliser les valeurs des champs](#use-input-values) ci-dessous. - **Placeholder :** Texte indicatif affiché à l'intérieur du champ vide. - **State :** Définissez l'apparence du champ selon les situations. Basculez entre **Default**, **Active**, **Invalid** et **Disabled** pour appliquer des visuels différents à chacun. - **Typography :** Style de texte pour la valeur affichée dans le champ. - **Leading and trailing icons :** Ajoutez des icônes à l'intérieur du champ. Certains paramètres sont spécifiques à certains types de champ : | Paramètre | Types de champ | |----------------------------|---------------------------| | Clear button | Text, Email | | Validate email format | Email | | Show password icon | Password | | Edit password requirements | Password | | Number format | Number | | Date/time format | Date, Time, Date and time | | Min and max date | Date, Date and time | ## Utiliser les valeurs des champs \{#use-input-values\} Chaque champ de saisie est automatiquement disponible en tant que variable — aucune configuration ni action **On Submit** n'est nécessaire. La valeur est référencée via l'**Element ID** du champ, que vous définissez dans **Input Settings**. Pour utiliser la valeur d'un champ ailleurs dans le flow (par exemple pour personnaliser un texte, remplir un autre champ ou piloter une navigation conditionnelle), insérez une variable et choisissez : **Element > Screen > `<elementId>.value`** :::link Consultez les guides correspondants pour comprendre comment utiliser les valeurs de champs enregistrées : - [Navigation conditionnelle](onboarding-navigation-branching) - [Variables](onboarding-variables) ::: ## Validation des champs \{#input-validation\} Le comportement de validation dépend du type de champ. Chaque champ expose une variable booléenne en lecture seule, `<elementId>.isValid`, qui indique si la valeur saisie satisfait les règles de validation du champ. Utilisez-la dans des actions conditionnelles ou une visibilité conditionnelle — par exemple pour masquer un bouton Suivant tant que le format d'une adresse e-mail n'est pas valide. :::note - La variable `isValid` est en lecture seule — vous ne pouvez pas la modifier. - Un champ vide est toujours considéré comme valide. - Les champs texte n'ont pas de règles de validation. `textInput.isValid` retourne toujours `True`. ::: | Type de champ | Comportement de validation | |---|---| | Text | Aucune règle de validation intégrée. | | Email | Optionnelle. Activez **Validate email format** dans le panneau **Design** pour vérifier que la valeur saisie respecte le format d'une adresse e-mail. | | Phone number | Vérification du format de numéro de téléphone intégrée. Non configurable dans le Builder — la règle est évaluée à l'exécution. | | Password | Configurable. Voir [Exigences de mot de passe](#password-requirements) ci-dessous. | | Number | Basée sur le format. La valeur saisie doit correspondre au format de nombre sélectionné. Voir [Format de nombre](#number-format) ci-dessous. | | Date, Time, Date and time | Intégrée. Le sélecteur n'accepte que des valeurs de date ou d'heure valides. | L'[état visuel](builder-styling#input-states) **Invalid** s'active lorsque l'utilisateur soumet le formulaire — par exemple en appuyant sur Entrée ou Terminé sur le clavier. Jusqu'à ce moment, le champ affiche l'état **Active** ou **Default**. ### Exigences de mot de passe \{#password-requirements\} Les champs de type mot de passe prennent en charge des règles de validation configurables. Cliquez sur **Edit password requirements** dans le panneau **Design** pour ouvrir l'éditeur de règles. Les règles activées s'affichent sous forme de liste de contrôle dynamique sous le champ — chaque élément est coché dès que sa règle est satisfaite. Règles disponibles : - **Min length** — nombre minimum de caractères. Par défaut : 8. - **Max length** — nombre maximum de caractères. Par défaut : 32. - **Uppercase letter** — au moins un caractère A–Z. - **Lowercase letter** — au moins un caractère a–z. - **Number** — au moins un chiffre. - **Special character** — au moins un caractère non alphanumérique (par exemple, `!@#$%`). Le mot de passe est valide uniquement lorsque toutes les règles activées sont satisfaites. ### Format de nombre \{#number-format\} Le menu déroulant **Format** dans les paramètres du champ **Number** contrôle la façon dont la valeur saisie est interprétée : - **Integer** — nombres entiers uniquement (par exemple, `4`). - **Decimal (Point)** — décimaux avec un point comme séparateur (par exemple, `4.89`). - **Decimal (Comma)** — décimaux avec une virgule comme séparateur (par exemple, `4,89`). Les valeurs qui ne correspondent pas au format sélectionné sont considérées comme invalides. ## Déclencher des actions sur les événements de saisie \{#trigger-actions-on-input-events\} :::link Article principal : [Actions](onboarding-actions) ::: Vous pouvez exécuter des actions en réponse aux saisies de l'utilisateur via le panneau **Interactions** : - **On changed** — se déclenche lorsque l'utilisateur modifie la valeur du champ. Disponible pour tous les types de champ. - **On submit** — se déclenche lorsque l'utilisateur soumet un champ texte en appuyant sur Entrée ou Terminé sur le clavier. Les sélecteurs de date et d'heure ne disposent pas de ce déclencheur. --- # File: builder-navigation-actions --- --- title: "Navigation et interaction" description: "Déplacer l'utilisateur entre les écrans et interagir avec lui" --- <CustomDocCardList /> Le Flow Builder vous donne un contrôle total sur la façon dont les utilisateurs se déplacent dans votre flow et sur la manière dont votre application échange des données avec lui — sans écrire une seule ligne de code. - **[Navigation](onboarding-navigation-branching)** : Guidez les utilisateurs à travers les écrans avec des routes statiques ou un branchement dynamique selon leurs choix - **[Actions](onboarding-actions)** : Définissez ce qui se passe quand les utilisateurs appuient sur des boutons ou interagissent avec des éléments - **[Loaders et barres de progression](builder-loaders-and-progress-bars)** : Affichez des indicateurs de chargement et un suivi de la progression entre les écrans - **[Variables](onboarding-variables)** : Affichez du contenu dynamique en référençant les données collectées durant le flow - **[Éléments et groupes sélectionnables](flow-selectable-elements)** : Rendez des éléments sélectionnables, organisez-les en groupes et utilisez leur état dans des conditions - **[Visibilité conditionnelle](onboarding-element-visibility)** : Affichez ou masquez des éléments et des écrans selon les réponses de l'utilisateur ou des conditions --- # File: onboarding-navigation-branching --- --- title: "Navigation et branchement" description: "Guidez les utilisateurs à travers les écrans avec des routes statiques et un branchement dynamique." --- La navigation et le branchement vous permettent de guider les utilisateurs à chaque étape de votre flow : utilisez des routes statiques pour envoyer tout le monde vers les écrans principaux, et la navigation dynamique pour adapter le flow en fonction des choix des utilisateurs. :::link La navigation est un type d'action. Pour en savoir plus sur les actions, consultez [Actions](onboarding-actions). ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/OLl-WziDMhU?si=_eUtsmbEuFAaLj1r" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Naviguer entre les écrans \{#navigate-between-screens\} Vous pouvez configurer une navigation statique et dynamique à l'aide de différents éléments du flow. ### Navigation statique \{#static-navigation\} La navigation statique dirige tous les utilisateurs vers le même écran cible. Pour la configurer : 1. Sélectionnez un élément sur lequel les utilisateurs peuvent appuyer — bouton, réponse à un quiz ou bascule. 2. Ouvrez le panneau **Interactions** à droite. Cliquez sur **Add trigger**. Pour naviguer immédiatement les utilisateurs lorsqu'ils appuient sur une option de quiz — sans nécessiter un appui sur un bouton séparé — sélectionnez ici l'élément d'option de quiz plutôt qu'un bouton. 3. Configurez le déclencheur **On tap** : - **Action** : sélectionnez **Navigate to screen**. - **Destination** : choisissez l'écran de destination. ### Navigation dynamique \{#dynamic-navigation\} La navigation dynamique oriente les utilisateurs en fonction de leurs réponses aux quiz, de l'état des bascules et des attributs personnalisés. N'importe quel [élément sélectionnable](flow-selectable-elements) peut servir de condition pour la navigation dynamique. Pour la configurer : 1. Sélectionnez un élément qui naviguera les utilisateurs. 2. Ouvrez le panneau **Interactions** à droite. Cliquez sur **Add trigger**. Pour naviguer immédiatement les utilisateurs lorsqu'ils appuient sur une option de quiz — sans nécessiter un appui sur un bouton séparé — sélectionnez ici l'élément d'option de quiz plutôt qu'un bouton. 3. Configurez le déclencheur **On tap** : - **Action** : sélectionnez **Conditional**. - **Conditions** : définissez les actions de navigation conditionnelle. En savoir plus [ici](onboarding-actions#conditional-actions). ## Fermer le flow \{#close-flow\} Si le parcours utilisateur nécessite de fermer le flow, vous pouvez le configurer à l'aide de boutons ou de quiz à réponse unique : 1. Ajoutez et sélectionnez un élément qui doit fermer le flow au tap. 2. Ouvrez le panneau **Interactions** à droite. Cliquez sur **Add trigger**. 3. Configurez le déclencheur **On tap** : - **Action** : sélectionnez **Close flow**. --- # File: onboarding-actions --- --- title: "Actions" description: "Définissez les actions déclenchées par les interactions utilisateur dans le builder." --- Le panneau **Interactions** vous permet de définir comment les éléments du flow réagissent aux événements — comme les appuis, l'apparition d'éléments et les soumissions de formulaires. Pour chaque événement, vous assignez une ou plusieurs actions : naviguer entre les écrans, afficher ou masquer des éléments, ouvrir des URLs, définir des variables, et plus encore. Utilisez des conditions pour personnaliser le flow en fonction des données de l'utilisateur. Chaque interaction suit une chaîne en trois parties : 1. **Élément** : Le composant de l'écran qui démarre l'interaction — un bouton, une réponse de quiz, un champ de saisie, ou autre chose. 2. **Déclencheur** : L'événement qui active la logique, comme un appui, l'apparition d'un élément, ou la soumission d'un formulaire. 3. **Action** : La tâche que le flow exécute en réponse. Un seul déclencheur peut exécuter plusieurs actions en séquence. ## Configurer les interactions \{#set-up-interactions\} Pour configurer une interaction : 1. Sélectionnez un élément sur l'écran ou dans le panneau **Layers**. 2. À droite, passez au panneau **Interactions** et cliquez sur **Add trigger**. 3. Dans la section **Button triggers**, sélectionnez le [type de déclencheur](#trigger-types). 4. Cliquez sur **Add action**, cliquez sur le nom de l'action et sélectionnez un [type d'action](#action-types) dans le menu déroulant de la fenêtre **Edit action**. 5. Configurez les propriétés de l'action en fonction du [type d'action](#action-types) que vous avez sélectionné. 6. Si nécessaire, cliquez sur **Add action** pour ajouter d'autres actions pour le même déclencheur. ## Types de déclencheurs \{#trigger-types\} Les déclencheurs se déclenchent en réponse au comportement de l'utilisateur, aux changements d'état des éléments ou au chargement de l'écran. **On screen appear** est universel ; les autres sont spécifiques aux éléments. | Déclencheur | Se déclenche quand... | Pris en charge sur | |---|---|---| | **On screen appear** | L'écran se charge | Tous les éléments | | **On tap** | L'utilisateur appuie sur l'élément | [Boutons](paywall-buttons), [options de quiz](onboarding-quizzes), [bascules](builder-toggles), [comptes à rebours](flow-timer), [vidéos](custom-media) | | **On changed** | L'utilisateur modifie la valeur de la saisie (frappe, sélection d'une date ou d'une heure) | Tous les [éléments de saisie](builder-inputs-and-forms) | | **On submit** | L'utilisateur soumet une saisie de texte en appuyant sur Entrée ou Terminé sur le clavier | [Saisies textuelles](builder-inputs-and-forms) | | **On timer end** | Un élément [Countdown](flow-timer) atteint zéro | [Countdown](flow-timer) | | **On playback finished** | Une [Vidéo](custom-media) atteint la fin | [Vidéo](custom-media) | Pour les éléments sans interactions intégrées (comme le [Loader](builder-loaders-and-progress-bars)), **On screen appear** est le seul déclencheur disponible. ## Types d'actions \{#action-types\} :::important **Toute action de navigation** qui déplace l'utilisateur vers un écran différent doit toujours être la dernière action de la liste. Les actions placées après elle (comme "Set Variable") peuvent ne pas s'exécuter car l'application a déjà changé d'écran. ::: ### Naviguer vers un écran \{#navigate-to-screen\} C'est l'action principale pour déplacer les utilisateurs entre les écrans. Elle emmène l'utilisateur vers un écran de destination spécifié. Pour cette action, vous n'avez besoin de configurer que l'écran de destination. Si vous souhaitez activer une navigation dynamique, consultez [Navigation et branchement](onboarding-navigation-branching) ou la section [Actions conditionnelles](#conditional-actions). ### Naviguer vers le suivant \{#navigate-next\} Avance l'utilisateur vers l'écran suivant dans l'ordre des écrans du flow. Utilisez ceci pour les flows linéaires, où l'ordre des écrans dans l'éditeur correspond à l'ordre dans lequel vous souhaitez que les utilisateurs les voient. ### Naviguer vers le précédent \{#navigate-back\} Renvoie l'utilisateur à l'écran précédent dans son historique de navigation, plutôt qu'à l'écran précédent dans la séquence. ### Ouvrir une URL \{#open-url\} :::tip Utilisez les [liens en ligne](onboarding-text#inline-link) pour insérer des liens dans du texte continu. ::: Ouvre une adresse web spécifique. Utilisez ceci pour envoyer les utilisateurs vers des pages web, des articles ou des profils de réseaux sociaux en dehors des écrans natifs de votre application. Pour cette action, vous pouvez configurer deux paramètres : - **URL address** : Définissez une adresse URL. De plus, vous pouvez la rendre dynamique — par exemple, pour naviguer les utilisateurs vers différentes pages en fonction de leur réponse à un quiz ou des données qu'ils ont soumises. Pour ce faire, cliquez sur Variable icon et sélectionnez la variable que vous souhaitez utiliser. - **Open in external browser** : Définissez où vous souhaitez ouvrir les liens externes. Par défaut, ils s'ouvrent dans un navigateur intégré à l'application pour garder les utilisateurs dans l'app. Cochez la case **Open in external browser** si vous souhaitez ouvrir les liens dans un navigateur externe. ### Fermer le flow \{#close-flow\} Ferme le flow actuel. ### Afficher/masquer des éléments \{#showhide-elements\} Affiche ou masque un élément spécifique sur l'écran. Cette action remplace l'état initial défini dans **Visibility** dans le panneau **Design**. Si **Visibility** est défini sur **Hide**, l'action **Show** le fera apparaître. :::important Une action **Show** ou **Hide** sans élément cible [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Sélectionnez une cible ou supprimez l'action. ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ### Afficher une alerte \{#show-alert\} Affiche une fenêtre pop-up système native. Les utilisateurs doivent appuyer sur **Ok** pour continuer. Pour les alertes, vous devez configurer leur **Title** et leur **Message**. Dans les deux, vous pouvez utiliser des variables pour rendre le contenu dynamique. Pour ce faire, cliquez sur Variable icon et sélectionnez la variable que vous souhaitez utiliser. :::important Une action **Show alert** avec une configuration vide ou incomplète [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Remplissez les deux champs ou supprimez l'action. ::: ### Définir une variable \{#set-variable\} Met à jour la valeur d'une variable dans le flow. Avant d'ajouter cette action, créez des variables dans le panneau **Variables** à gauche (voir [Variables](onboarding-variables)). Cliquez sur **Add variable** et définissez autant de variables et de valeurs que nécessaire. :::important Une action **Set variable** sans assignation [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Configurez au moins une assignation ou supprimez l'action. ::: ### Achat \{#purchase\} Déclenche un flow d'achat directement depuis un bouton ou une interaction dans votre onboarding. Utilisez ceci pour permettre aux utilisateurs de s'abonner ou d'acheter un produit sans quitter le flow. Vous pouvez configurer deux comportements pour cette action : - **In-app store** : Initie un achat natif. Définissez **Product** sur un produit spécifique, ou sur `products.selectedProduct` pour la sélection actuelle de l'utilisateur sur l'écran. - **Web payment** : Envoie l'utilisateur vers un [paywall web](web-paywall) au lieu de déclencher un achat natif. Utilisez ceci lorsque vous souhaitez gérer la transaction en dehors de l'application, par exemple pour des offres d'abonnement basées sur le web. :::important Une action **Purchase** sans **Product** cible ou **Web Paywall URL** [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Assignez une cible ou supprimez l'action. ::: ### Restaurer les achats \{#restore-purchases\} Déclenche le flow de restauration des achats sur l'appareil. Les utilisateurs appuient sur ceci lorsqu'ils ont précédemment acheté un abonnement sur un autre appareil ou après avoir réinstallé l'application, et ont besoin de récupérer l'accès à leurs droits. Il n'y a rien à configurer pour cette action — Adapty gère la restauration via le flow natif du store. L'action **Restore purchases** est également préconfigurée sur le lien **Restore** dans le préréglage de bouton **Links** (voir [Configurer les achats](paywall-product-block#restore-purchases)). ## Actions personnalisées \{#custom-actions\} Une action personnalisée déclenche un **Action ID** nommé que votre propre code d'application gère. Utilisez-la lorsque les types d'actions intégrés ne couvrent pas ce dont vous avez besoin. Adapty fournit le déclencheur ; votre application implémente le comportement : 1. Dans le builder, vous assignez un **Action ID** à l'interaction d'un élément. 2. Lorsque l'utilisateur déclenche l'interaction, le flow transmet l'ID à votre application. 3. Votre application correspond à l'ID et exécute votre code. ### Configurer une action personnalisée \{#set-up-a-custom-action\} 1. Dans la fenêtre **Edit action**, assignez un **Action ID** — une chaîne que votre application reconnaîtra (par exemple, `show_discount`). 2. Dans le code de votre application, implémentez un gestionnaire pour cet Action ID. Consultez [Gérer les actions de paywall](handle-paywall-actions) pour les détails d'implémentation et des exemples de code. :::important Une action **Custom** sans **Action ID** [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). Assignez un Action ID ou supprimez l'action. ::: ### Ce que vous pouvez faire avec les actions personnalisées \{#what-you-can-do-with-custom-actions\} Une action personnalisée ne fait rien par elle-même. Vous définissez un Action ID statique dans le builder, et votre code d'application gère ce qui se passe lorsqu'il reçoit cet ID. Chaque cas d'utilisation ci-dessous suit le même schéma : assignez un ID dans le flow, puis gérez-le dans votre code. - **Déclencher un événement in-app** : Envoyez un ID comme `viewed_special_offer`, puis enregistrez l'événement dans vos analytics lorsque votre application le reçoit. - **Demander une permission système** : Envoyez un ID comme `request_location`, puis appelez la fenêtre de permission du système depuis votre application. Pour les permissions que la fenêtre ne peut pas accorder, ouvrez plutôt les paramètres système du téléphone. Adapty n'affiche pas la fenêtre — c'est votre application qui le fait. - **Démarrer une authentification native** : Envoyez un ID comme `login_google`, puis affichez votre propre écran de connexion. Le flow ne peut pas connecter l'utilisateur. - **Appliquer une logique métier** : Envoyez un ID comme `apply_discount`, puis déverrouillez du contenu ou modifiez l'état de l'application de votre côté. - **Transmettre une réponse de quiz à votre application** : Assignez un Action ID différent à chaque option (par exemple, `goal_weight_loss` et `goal_muscle`), puis lisez l'ID dans votre code. Utilisez l'ID pour définir un [attribut utilisateur personnalisé](setting-user-attributes#custom-user-attributes) sur lequel vous pouvez segmenter ultérieurement. Comme l'action ne porte qu'un ID fixe, c'est le seul moyen de rapporter le choix — le flow ne peut pas envoyer la valeur sélectionnée. :::important Une action personnalisée se déclenche au moment où l'utilisateur sélectionne une option. Si l'utilisateur change sa réponse, le flow déclenche également le nouvel Action ID. Votre application reçoit alors les deux dans l'ordre — par exemple, `goal_weight_loss`, puis `goal_muscle`. Rendez votre gestionnaire idempotent pour que le dernier signal l'emporte. ::: ### Ce que les actions personnalisées ne peuvent pas faire \{#what-custom-actions-cant-do\} Les actions personnalisées sont statiques. L'Action ID est fixé lorsque vous construisez le flow — il ne peut pas lire les [variables](onboarding-variables) ni les [saisies utilisateur](builder-inputs-and-forms). Lorsque l'action se déclenche, votre application ne reçoit que cet ID, jamais l'email, le numéro de téléphone ou toute autre saisie faite par l'utilisateur. Les champs de saisie restent dans le flow sous forme de variables pour le branchement et la personnalisation. Pour utiliser ces valeurs dans votre application, collectez-les via votre propre interface ou API. Les actions personnalisées sont également unidirectionnelles. Votre application ne peut pas renvoyer de résultat au flow, et le flow n'attend pas que votre code se termine. Si une action **Navigate next** suit l'action personnalisée, l'utilisateur passe à l'écran suivant même si votre code échoue — par exemple, lorsque l'utilisateur ferme votre écran de connexion sans se connecter. Combiné avec l'Action ID statique, cela exclut la validation de la saisie utilisateur dans votre application — par exemple, vérifier un code SMS saisi par l'utilisateur et brancher en fonction du résultat. Si la suite du flow dépend de ce que votre code a fait, [divisez le flow entre deux placements](#continue-the-flow-based-on-the-result). ### Continuer le flow en fonction du résultat \{#continue-the-flow-based-on-the-result\} Si certains écrans ne doivent apparaître qu'après la réussite d'une action personnalisée — par exemple, des écrans qui suivent une connexion — divisez le flow entre deux [placements](placements) et laissez votre application décider quand afficher la deuxième partie : 1. Dans le premier placement, créez un flow qui se termine par une action personnalisée (par exemple, `login`). 2. Dans votre application, gérez l'Action ID : affichez votre écran de connexion et vérifiez si l'utilisateur s'est connecté. 3. Si l'utilisateur s'est connecté, affichez le flow du deuxième placement avec les écrans de suivi. Ainsi, votre application contrôle la transition en fonction du résultat réel, au lieu que le flow navigue en avant indépendamment du résultat. ## Actions conditionnelles \{#conditional-actions\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/xmWSEPxnI0s?si=mazHQHE89qEDxvPA" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Utilisez les actions conditionnelles pour diviser le flow en différents chemins selon les données de l'utilisateur. Quelques cas d'utilisation courants : - Vous avez un quiz sur l'écran et souhaitez naviguer les utilisateurs vers différents écrans en fonction de leurs réponses. Dans ce cas, ajoutez une action conditionnelle à un bouton. - Vous souhaitez proposer différents produits et offres à différents groupes d'utilisateurs. Placez-les sur différents écrans et configurez des conditions pour un bouton de navigation. - Vous souhaitez ignorer certaines étapes pour les utilisateurs qui ont déjà terminé un tutoriel lors d'une session précédente. Les actions conditionnelles fonctionnent comme une chaîne if / else-if / else. L'application lit les règles de haut en bas et s'arrête à la première correspondance : 1. **IF** : Le flow vérifie la condition principale. - Est-elle Vraie ? Le flow exécute immédiatement les actions THEN et s'arrête. - Est-elle Fausse ? Le flow passe à la section suivante. 2. **ELSE IF** : Vous pouvez ajouter des vérifications supplémentaires ici (par exemple, "Si pas Premium, l'utilisateur est-il en période d'essai ?"). 3. **ELSE** (Repli) : Si aucune des règles ci-dessus ne correspond, le flow exécute les actions de cette dernière section. :::important - Si une règle est ajoutée mais qu'aucune action ne lui est assignée, la correspondance avec la condition ne fait rien. - Une règle incomplète (sans opérateur ou valeur) [bloque l'aperçu et la publication](builder-save-publish#troubleshooting). ::: Pour chaque règle, sélectionnez une variable à évaluer et une action à exécuter. Vous pouvez définir plusieurs actions par règle. :::important Le flow n'exécute qu'une seule règle — la première qui correspond. Si vous devez exécuter à la fois **IF** et **ELSE IF** en même temps, ajoutez les deux actions à **IF**. ::: Pour savoir comment rendre les éléments sélectionnables et les organiser en groupes pour les utiliser dans des conditions, consultez [Éléments sélectionnables et groupes](flow-selectable-elements). ## Dépannage \{#troubleshooting\} Toute action avec des champs obligatoires manquants bloque l'aperçu et la publication. Consultez [Enregistrer et publier des flows](builder-save-publish#troubleshooting) pour la liste complète. --- # File: builder-loaders-and-progress-bars --- --- title: "Indicateurs de progression et chargements" description: "Affichez la progression par étapes et les états d'occupation dans un flow." --- La catégorie **Progress** propose deux types d'éléments : l'un pour suivre la progression par étapes dans un flow multi-écrans, l'autre pour afficher des indicateurs d'occupation en place. ## Indicateurs de progression \{#progress-indicators\} ### Styles d'indicateur \{#indicator-styles\} Un élément **Progress** indique à l'utilisateur sa position dans un flow multi-écrans. La catégorie propose trois variantes visuelles : - **Linear** — Une barre unique qui se remplit au fur et à mesure que l'utilisateur avance. - **Segmented** — Des barres séparées pour chaque étape, qui se remplissent une par une. - **Connectors** — Des cercles numérotés reliés par des lignes (ex. : Étape 1, Étape 2, Étape 3 dans l'ordre). ### Associer les étapes aux écrans \{#match-steps-to-screens\} Par défaut, l'indicateur de progression suit tous les écrans du flow. Pour le limiter à un sous-ensemble, sélectionnez les écrans dans la liste déroulante **Screens**. Vous pouvez aussi ouvrir l'écran à exclure et décocher la case **Include screen in progress indicator**. Désactivez **One segment per screen** si vous souhaitez contrôler plus finement le nombre d'étapes. :::warning La position de l'étape suit l'ordre de la liste d'écrans, pas l'ordre dans lequel l'utilisateur les voit réellement. Dans les flows non linéaires, l'étape affichée par l'indicateur peut sauter en avant ou revenir en arrière. ::: ### États des étapes \{#step-states\} Chaque étape possède trois états : **Completed**, **Current** et **Upcoming**. Sélectionnez une étape dans l'indicateur de progression pour modifier le style d'un état dans le panneau de droite. Utilisez **Apply changes to all states** pour appliquer vos modifications aux deux autres états. La modification d'une étape affecte toutes les étapes du même indicateur. ### Mise en page et positionnement \{#layout-and-positioning\} L'indicateur de progression est un élément global : vous ne pouvez pas le placer dans un [conteneur](builder-containers). Son positionnement n'est pas non plus configurable — il utilise un positionnement absolu par défaut. Lorsque l'utilisateur fait défiler l'écran, l'indicateur reste en place et le contenu défile dessous. Pour gérer l'espace autour de l'indicateur, utilisez les contrôles **Margin** et **Padding** de la section **Spacing** plutôt que de déplacer l'élément. Si la mise en page semble incorrecte, ajustez les marges ou le padding de l'indicateur et de l'élément voisin. ## Chargements \{#loaders\} Un **Loader** est un élément animé qui indique qu'une opération est en cours — par exemple, le traitement des réponses d'un quiz pour préparer un plan personnalisé. La catégorie propose trois modèles : - **Spinner** — Un indicateur circulaire animé. - **Spinner with label** — Un indicateur circulaire avec une légende (ex. : « Chargement... »). - **Loader** — Une barre horizontale qui se remplit au fil de l'avancement. {/* - **Loader with label** — A horizontal bar with a caption and percentage (e.g., "Analyzing... 47%"). */} :::warning Un loader nécessite un **déclencheur** pour apparaître et disparaître. Ouvrez l'onglet **Interactions** pour configurer cette logique — par exemple, l'afficher après que l'utilisateur a soumis un quiz. ::: --- # File: onboarding-variables --- --- title: "Variables" description: "Utilisez des variables pour afficher des données dynamiques dans vos flows." --- Les variables vous permettent d'afficher du contenu dynamique dans vos flows — prix des produits, détails des offres et autres données qui se mettent à jour en fonction du contexte de chaque utilisateur. Utilisez-les pour contrôler la visibilité des éléments et personnaliser le contenu des écrans. Pour ouvrir le panneau des variables, cliquez sur l'icône **{ }** dans le panneau gauche. Le panneau comporte trois onglets : - **[Custom](#custom-variables)** : Variables que vous créez et gérez vous-même. - **[Product](#product-variables)** : Variables intégrées qui récupèrent les données localisées sur les produits et les offres depuis le store. - **[Element](#element-variables)** : Variables liées aux états des éléments sur le canvas. ## Variables personnalisées \{#custom-variables\} ### Créer une variable personnalisée \{#create-a-custom-variable\} 1. Dans le panneau des variables, cliquez sur **+**. 2. Saisissez un nom pour la variable. 3. Sélectionnez un type : String, Number ou Boolean. 4. Définissez une valeur initiale. C'est la valeur que la variable contient au démarrage du flow. 5. Cliquez sur **Create variable**. :::tip Utilisez des points dans les noms pour regrouper les variables liées — par exemple, `user.score` ou `user.goal`. ::: ### Mettre à jour une variable via une interaction \{#update-a-variable-via-an-interaction\} :::link Consultez l'article [Actions](onboarding-actions) pour plus de détails. ::: Vous pouvez mettre à jour la valeur d'une variable à l'exécution en ajoutant une action **Set up variables** à n'importe quel élément. 1. Sélectionnez un élément sur le canvas. 2. Dans l'onglet **Interactions**, cliquez sur **Add trigger**. 3. Sélectionnez **On tap** et cliquez sur **Add action**. Dans le menu déroulant **Action type**, sélectionnez **Set up variables**. 4. Cliquez sur **Add variable**. Sélectionnez la variable et définissez la nouvelle valeur. :::tip Par exemple, vous pouvez affecter une valeur différente à `user.goal` selon la réponse de quiz sélectionnée par un utilisateur, puis utiliser cette variable pour le rediriger vers un écran différent. ::: ## Variables de produit \{#product-variables\} Les variables de produit récupèrent des données localisées directement depuis les stores. Utilisez-les dans des champs de texte pour afficher des prix, titres et détails d'offres localisés, ou dans des conditions pour afficher ou masquer du contenu selon l'éligibilité aux offres. | Variable | Description | Exemple | | :--- | :--- | :--- | | `prod_title` | Titre localisé du produit | Premium Subscription | | `prod_price` | Prix localisé pour une période de facturation | $9.99 | | `prod_price_per_day` | Prix de l'abonnement divisé par le nombre de jours dans la période de facturation. Vide pour les produits qui ne sont pas des abonnements. | $0.33 | | `prod_price_per_week` | Prix de l'abonnement divisé par le nombre de semaines dans la période de facturation. Vide pour les produits qui ne sont pas des abonnements. | $2.33 | | `prod_price_per_month` | Prix de l'abonnement ajusté sur un mois. Vide pour les produits qui ne sont pas des abonnements. | $9.99 | | `prod_price_per_year` | Prix de l'abonnement ajusté sur un an. Vide pour les produits qui ne sont pas des abonnements. | $119.88 | | `offer_price` | Prix localisé d'une offre de lancement ou promotionnelle. Vide si l'utilisateur n'est éligible à aucune offre. | $0.99 | | `offer_billing_period` | Période de facturation localisée d'une offre. Identique à `offer_full_duration` pour les offres d'essai gratuit et de paiement anticipé. Vide si l'utilisateur n'est pas éligible. | 1 week | | `offer_full_duration` | Durée totale localisée d'une offre. Vide si l'utilisateur n'est pas éligible. | 1 month | | `is_free_trial` | Renvoie `true` si l'utilisateur est éligible à une offre avec essai gratuit. | true | | `is_pay_up_front` | Renvoie `true` si l'utilisateur est éligible à une offre de paiement anticipé. | true | | `is_pay_as_you_go` | Renvoie `true` si l'utilisateur est éligible à une offre de paiement à l'utilisation. | true | :::tip Utilisez `is_free_trial`, `is_pay_up_front` et `is_pay_as_you_go` avec la visibilité conditionnelle pour afficher ou masquer des éléments selon l'offre à laquelle un utilisateur est éligible. Par exemple, affichez une chronologie d'essai gratuit uniquement lorsque `is_free_trial` est `true`. ::: Les valeurs des variables d'offre dépendent du type d'offre auquel l'utilisateur est éligible. Pour illustrer, prenons un abonnement hebdomadaire appelé « Premium Subscription » à 5 $, avec trois offres possibles : - **Pay As You Go** : 3 premières semaines à 3 $ (facturé par semaine), puis 5 $/semaine. - **Pay Up Front** : 3 premières semaines à 8 $ (facturé immédiatement), puis 5 $/semaine. - **Free Trial** : Première semaine gratuite, puis 5 $/semaine. Dans cet exemple, `prod_title` renvoie « Premium Subscription » et `prod_price` renvoie 5 $. Les valeurs des variables d'offre dépendent de l'offre à laquelle l'utilisateur est éligible : | Variable | Pay As You Go | Pay Upfront | Free Trial | | :--- | :--- | :--- | :--- | | `offer_price` | $3 | $8 | $0 | | `offer_billing_period` | 1 week | 3 weeks | 1 week | | `offer_full_duration` | 3 weeks | 3 weeks | 1 week | Pour les offres Pay Upfront et Free Trial, `offer_billing_period` et `offer_full_duration` renvoient la même valeur. Pour Pay As You Go, elles diffèrent car la période de facturation est d'une semaine mais la durée totale est de trois semaines. :::note Pour en savoir plus sur les offres et leur configuration, consultez [Offers](offers). ::: ## Variables d'élément \{#element-variables\} Les variables d'élément capturent les choix de l'utilisateur — ce qu'il a sélectionné dans les quiz, l'onglet sur lequel il se trouve et si le bouton d'essai est activé. Les types de variables d'élément dépendent du groupe : - **Single choice** : Quiz à choix unique et onglets : - `selected_id` : ID d'élément à utiliser dans les conditions - `selected_title` : Titre d'élément à utiliser dans le texte dynamique - **Multi-choice** : Quiz à choix multiple : - `selected_ids` : ID d'éléments à utiliser dans les conditions - `selected_titles` : Titres d'éléments à utiliser dans le texte dynamique - **Toggle** : Bouton d'essai : - `is_selected` : Valeur booléenne Les cas d'utilisation courants incluent : - Afficher un contenu différent selon que le bouton d'essai est activé ou non. - [Rediriger les utilisateurs vers différents écrans](onboarding-navigation-branching) selon leurs réponses au quiz ## Utiliser des variables dans le texte \{#use-variables-in-text\} Pour insérer une variable dans un élément texte : 1. Sélectionnez un élément texte sur le canvas. 2. Dans l'onglet **Design**, trouvez le champ **Content** et rédigez votre texte. 3. Cliquez sur l'icône **{ }** dans le champ. 4. Sélectionnez une variable dans la liste. :::tip Vous pouvez également utiliser des variables dans d'autres éléments : - Utilisez des variables dans les liens et alertes pour les rendre dynamiques - Créez des conditions dynamiques basées sur des variables. Par exemple, la condition peut être `if experience.current > experience.target, navigate to...` ::: ### Mettre en forme les variables \{#style-variables\} Il n'est pas possible d'appliquer une mise en forme de texte enrichi à une variable seule. Sélectionner une variable dans le champ **Content** et appliquer du gras, de l'italique, du souligné, du barré ou un changement de couleur n'a aucun effet. Les paramètres de texte enrichi s'appliquent uniquement au bloc de texte entier. Pour mettre en forme le texte, utilisez la section **Typography** de l'onglet **Design**, ou appliquez un [style de texte](onboarding-text#set-up-text-styles) enregistré. ### Réutiliser du contenu entre les écrans \{#reuse-content-across-screens\} Certains contenus se répètent dans votre flow — un libellé de bouton comme « Continuer », un appel à l'action récurrent, ou une mention légale affichée sur plusieurs écrans. Il en va de même pour les textes plus longs, comme une description de fonctionnalité réutilisée sur plusieurs écrans. Plutôt que de saisir ce contenu dans chaque élément, stockez-le dans une variable personnalisée. Cela s'avère utile quand vous redirigez différents utilisateurs vers différents écrans mais souhaitez conserver une formulation cohérente entre eux. 1. [Créez une variable personnalisée](#create-a-custom-variable) de type String et définissez sa valeur initiale sur le texte à réutiliser. Par exemple, nommez-la `button.navigation` et définissez la valeur sur `Continue`. 2. Insérez cette variable dans le champ **Content** de chaque élément où le texte doit apparaître. Pour modifier le texte partout, mettez à jour la valeur initiale de la variable une seule fois. Chaque élément qui utilise la variable se met à jour automatiquement, vous n'avez donc pas à modifier chaque écran manuellement. --- # File: onboarding-element-visibility --- --- title: "Visibilité conditionnelle" description: "Afficher ou masquer des éléments selon des conditions." --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Vous pouvez contrôler l'affichage d'un élément en lui ajoutant une condition. Un élément conditionnel n'est visible que pour les utilisateurs qui satisfont aux critères définis. :::important Si vous affichez ou masquez un élément via l'[action](onboarding-actions) **Show** ou **Hide**, celle-ci remplace la condition de **Visibility** définie sur cet élément. Utilisez les conditions de **Visibility** pour les éléments dont l'affichage doit toujours dépendre d'un critère fixe. Utilisez les actions lorsque la visibilité doit changer en fonction d'une interaction de l'utilisateur — par exemple, afficher un bouton une fois qu'il a répondu à une question de quiz. ::: Pour ajouter une condition à un élément : 1. Sélectionnez l'élément dans le canevas ou le panneau des calques. 2. Dans la section **Visibility** du panneau de droite, sélectionnez **Conditional**. 3. Configurez la condition en choisissant un type de propriété parmi trois onglets : - **Custom** : variables que vous créez et gérez ; leurs valeurs peuvent être mises à jour via les interactions de l'utilisateur. Voir [Variables](onboarding-variables) pour plus de détails. - **Products** : propriétés des produits de votre flow, comme le prix ou le nom. - **Elements** : états des autres éléments du flow, par exemple si un bouton de période d'essai est actif. 4. Saisissez la **Value** à faire correspondre. 5. Cliquez sur l'opérateur pour le modifier si nécessaire. 6. (Facultatif) Cliquez sur **Add condition** pour ajouter d'autres conditions. Utilisez le sélecteur pour exiger que toutes les conditions soient remplies, ou au moins l'une d'elles. --- # File: paywall-dark-mode --- --- title: "Mode sombre" description: "Configurez le mode sombre pour les flows dans Adapty afin d'améliorer l'expérience utilisateur." --- Les flows Adapty prennent en charge le mode sombre nativement. Par défaut, les styles de couleur ont une alternative claire et une alternative sombre — lorsque vous appliquez un style de couleur à un élément, le flow utilise la bonne valeur selon le mode actuel de l'appareil. Adapty fournit un ensemble de styles de couleur préconfigurés, et vous pouvez créer les vôtres. ## Configurer les styles de couleur \{#configure-color-styles\} Chaque **style de couleur** définit une alternative claire et une alternative sombre. Quand un élément utilise un style nommé, il bascule automatiquement entre les deux. Vous pouvez gérer les styles de couleur dans **Style** > **Colors** sur la gauche. Pour ajouter un style de couleur : 1. Dans **Style** > **Colors**, cliquez sur **Create style**. 2. Sélectionnez les alternatives de couleur claire et sombre. Pour renommer un style, cliquez sur **⋮** à côté de celui-ci et sélectionnez **Rename**. ## Définir le thème de la barre d'état \{#set-the-status-bar-theme\} Si **Status bar** est activée dans le panneau **Screen settings**, vous pouvez définir son thème indépendamment : sélectionnez **Light**, **Dark** ou **Auto** dans les options **Status bar theme**. ## Prévisualiser les modes clair et sombre \{#preview-light--dark-modes\} Pour prévisualiser l'apparence de votre flow dans chaque mode, utilisez le bouton bascule soleil/lune en bas de la zone de prévisualisation. ## Supprimer le mode sombre \{#remove-dark-mode\} Pour supprimer entièrement la prise en charge du mode sombre, dans le panneau **Style** > **Colors**, cliquez sur **⋮** > **Delete dark theme**. --- # File: paywall-localization --- --- title: "Localisation" description: "Localisez vos paywalls et onboardings pour plusieurs langues." --- Dans un monde multiculturel, il est essentiel d'adapter votre produit à chaque pays. Vous pouvez le faire grâce aux localisations de paywall. Pour chaque paywall, vous pouvez créer des versions dans différentes langues afin de répondre aux besoins de marchés locaux spécifiques. Selon l'outil que vous utilisez pour concevoir vos flows, l'ajout d'une locale varie : 1. [Ajouter une locale dans l'Adapty Flow Builder](add-paywall-locale-in-adapty-paywall-builder) : si vous créez des flows dans l'Adapty Flow Builder, vous pouvez localiser tous les éléments directement dans le builder, y compris les textes et les médias. Pour contrôler quelle localisation est affichée, passez une locale dans la méthode `getFlow`. 2. [Ajouter une locale dans le Remote Config](add-remote-config-locale) : Adapty peut également vous aider à gérer les localisations du Remote Config sans redéployer l'application. --- # File: add-paywall-locale-in-adapty-paywall-builder --- --- title: "Ajouter une langue dans le Flow Builder" description: "Ajoutez du contenu localisé dans le Flow Builder d'Adapty pour toucher vos utilisateurs dans leur langue." --- Localiser vos flows les rend disponibles en plusieurs langues. Dans le Flow Builder, la localisation est organisée par écran, chacun affichant un pourcentage de complétion pour suivre l'avancement des traductions. :::tip Finalisez la configuration de votre flow dans la langue par défaut avant d'ajouter d'autres langues. ::: ## Ajouter et configurer une localisation \{#add-and-set-up-localization\} 1. Dans le panneau de gauche, cliquez sur Localizations. Puis cliquez sur **Add locale**. Sélectionnez les langues à ajouter. 2. Chaque langue ajoutée apparaît sous forme de colonne dans le tableau de localisation, pré-remplie avec les valeurs de la langue par défaut. 3. Pour vous concentrer uniquement sur ce qui manque, activez le bouton **Missing only** dans le panneau de gauche. Le tableau filtrera alors uniquement les lignes non traduites. ## Définir la langue par défaut \{#set-the-default-locale\} La langue par défaut contient votre contenu source et sert de secours pour toute traduction manquante. Chaque flow démarre avec l'anglais comme langue par défaut et unique. L'icône d'épingle Pin indique la langue par défaut. Vous ne pouvez pas supprimer la langue par défaut, sauf si une autre langue est d'abord définie comme langue par défaut. Pour changer la langue par défaut, ouvrez le menu contextuel Context menu dans l'en-tête de colonne de la langue cible, puis sélectionnez **Set as default**. ## Exporter et importer pour une traduction externe \{#export-and-import-for-external-translation\} Vous pouvez exporter le fichier de localisation pour le partager avec des traducteurs, puis importer les résultats traduits. Dans la barre d'outils supérieure, cliquez sur **Import / Export**. ### Format du fichier exporté \{#export-file-format\} L'export produit un fichier `.tsv` (valeurs séparées par des tabulations) avec une ligne par élément traduisible. Les colonnes sont : | Colonne | Description | |--------|-------------| | `Screen` | L'écran auquel appartient l'élément (ex. : `Welcome`, `Quiz`) | | `Element` | Identifiant d'élément généré automatiquement dans cet écran. Vous pouvez le modifier dans **Interactions** > **Element ID**. | | `Property` | Le type de propriété (ex. : `content`) | | `[default_locale]` | Le code de la langue par défaut (ex. : `en`) | | `[locale]` | Une colonne par langue ajoutée (ex. : `fr`, `es`) | Exemple : ``` Screen Element Property en fr es Welcome title content Turn words into art Transformez les mots en art Welcome subtitle content Create stunning images in seconds with AI Créez des images en quelques secondes Quiz quiz-title content What will you create? ``` :::note Laissez les colonnes de locale vides pour les lignes non traduites — Adapty les traitera comme manquantes. ::: ### Exigences du fichier d'importation \{#import-file-requirements\} - **Format** : `.tsv` (valeurs séparées par des tabulations) - **En-têtes** : doivent inclure `Screen`, `Element`, `Property` et au moins une colonne de langue - **Noms des colonnes de langue** : doivent correspondre aux codes de langue déjà ajoutés au flow. L'importation d'un fichier avec des codes de langue absents du flow génère une erreur. - **Importation partielle** : vous pouvez n'inclure qu'un sous-ensemble de lignes ; les lignes absentes du fichier conservent leurs valeurs actuelles ### Limitations \{#limitations\} - Le processus d'exportation supprime les variables des chaînes de caractères. Si vous réimportez ces données, vous devrez rajouter les variables manuellement. - Le fichier exporté ne contient que des chaînes de caractères — pour localiser les médias, voir [Localiser les images et vidéos](#localize-images-and-videos). ## Traduire manuellement \{#translate-manually\} Vous pouvez aussi saisir des traductions directement dans n'importe quelle cellule du tableau de localisation. Pour gérer une ligne spécifique, ouvrez son menu contextuel Context menu : - **Reset to default** : Rétablit la traduction de la ligne aux valeurs de la langue par défaut. ## Localiser les images et les vidéos \{#localize-images-and-videos\} Les images et les vidéos peuvent être localisées en téléchargeant des fichiers différents pour chaque locale. 1. Activez la locale cible — sous le canevas ou dans le panneau de localisation. 2. Sélectionnez l'élément image / vidéo. 3. Téléchargez le fichier localisé dans le panneau des propriétés. Les éléments média sans fichier localisé afficheront le fichier de la locale par défaut. ## Prévisualiser la localisation \{#preview-the-localization\} Pour vérifier vos traductions, changez la locale active dans le Flow Builder et passez en revue chaque écran. --- # File: add-flow-remote-config-locale --- --- title: "Localiser un flow avec Remote Config" description: "Ajoutez des langues au Remote Config d'un flow pour servir des valeurs différentes selon la langue ou la région." --- Le Remote Config d'un flow peut contenir un payload JSON distinct pour chaque langue. À l'exécution, le SDK renvoie le payload correspondant à la langue de l'utilisateur, ce qui vous permet de servir du contenu traduit, des images différentes ou d'autres valeurs spécifiques à une langue sans publier de nouvelle version de l'application. ## Ajouter une langue \{#add-a-locale\} Pour ajouter une langue au Remote Config d'un flow : 1. Ouvrez le flow dans Flow Builder. 2. Cliquez sur l'icône Remote Config au-dessus de l'aperçu de l'écran. 3. Cliquez sur **Add locale** au-dessus de l'éditeur. 4. Remplissez la boîte de dialogue : - **Code** : Le code de la langue, par exemple `en`, `fr` ou `de`. - **Name** : Le nom d'affichage, par exemple English ou French. Adapty ajoute une nouvelle colonne dans l'éditeur JSON pour cette langue. ## Modifier les valeurs par langue \{#edit-values-per-locale\} La colonne de chaque langue accepte ses propres données au format JSON. Utilisez les mêmes clés dans toutes les colonnes et traduisez les valeurs pour chaque langue. Par exemple, la colonne anglaise : ```json showLineNumbers { "title": "Try for free!", "cta": "Continue", "trial_days": 7 } ``` Et la colonne espagnole : ```json showLineNumbers { "title": "¡Prueba gratis!", "cta": "Continuar", "trial_days": 7 } ``` Les colonnes sont indépendantes — modifier l'une n'affecte pas les autres. ## Lire la langue correspondante dans votre application \{#read-the-matching-locale-in-your-app\} Le SDK expose une entrée `AdaptyRemoteConfig` par langue dans `AdaptyFlow.remoteConfigs`. Choisissez l'entrée dont le champ `locale` correspond à votre utilisateur, puis lisez son `dictionary` ou `jsonString` pour utiliser les valeurs à l'exécution. ## Sauvegarder ou déplacer des langues \{#back-up-or-move-locales\} Utilisez le menu **Import/Export** au-dessus de l'éditeur pour sauvegarder votre Remote Config ou le copier d'un flow à un autre. Le fichier JSON exporté contient le payload de toutes les langues en une seule fois. Consultez [Personnaliser un flow avec Remote Config](customize-flow-with-remote-config) pour le format du fichier. --- # File: customize-flow-with-remote-config --- --- title: "Personnaliser un flow avec Remote Config" description: "Personnalisez votre flow Flow Builder avec un payload JSON Remote Config." --- :::important Ce guide concerne le Remote Config pour Flow Builder. Pour les paywalls classiques créés sans Flow Builder, consultez [Concevoir un paywall avec Remote Config](customize-paywall-with-remote-config). ::: Remote Config vous permet de stocker un payload JSON personnalisé que le SDK lit au moment de l'exécution. Utilisez-le pour définir des valeurs comme les titres, les images, les polices, les couleurs ou les feature flags sans publier une nouvelle version de l'application. ## Utiliser le Remote Config \{#work-with-remote-config\} Pour ouvrir le Remote Config d'un flow, cliquez sur l'icône Remote Config au-dessus de l'aperçu de l'écran dans l'éditeur de flow. Dans la vue **JSON**, vous pouvez saisir n'importe quelle donnée au format JSON. L'éditeur affiche une colonne par locale ajoutée : :::warning Si le Remote Config contient du JSON invalide, vous ne pourrez ni **sauvegarder** ni **publier** le flow. Consultez [Sauvegarder et publier des flows](builder-save-publish#troubleshooting) pour la liste complète des problèmes qui bloquent l'aperçu et la publication. ::: Vous pouvez ensuite accéder à ces données depuis le SDK via le tableau `remoteConfigs` de `AdaptyFlow`. Adapty stocke une entrée `AdaptyRemoteConfig` par locale ; sélectionnez celle qui correspond à la locale de l'utilisateur et lisez soit le `dictionary` parsé, soit le `jsonString` brut pour ajuster votre flow au moment de l'exécution. Voici quelques exemples d'utilisation d'un Remote Config. <Tabs> <TabItem value="Titles" label="Titres" default> ```json showLineNumbers { "screen_title": "Today only: Subscribe, and get 7 days for free!" } # Test titles or other texts ``` </TabItem> <TabItem value="Images" label="Images"> ```json showLineNumbers { "background_image": "https://adapty.io/media/paywalls/bg1.webp" } # Test images on your flow ``` </TabItem> <TabItem value="Fonts" label="Polices"> ```json showLineNumbers { "font_family": "San Francisco", "font_size": 16 } # Test fonts ``` </TabItem> <TabItem value="Color" label="Couleur"> ```json showLineNumbers { "subscribe_button_color": "purple" } # Test colors of buttons, texts etc. ``` </TabItem> <TabItem value="HTML" label="HTML"> ```json showLineNumbers { "photo_gallery": "https://adapty.io/media/paywalls/link-to-html-snippet.html" } # Any HTML code that can be displayed in the flow ``` </TabItem> <TabItem value="Soft/Hard Paywall" label="Soft/Hard Paywall"> ```json showLineNumbers { "hard_paywall": true } # By setting it to true, you disallow skipping the paywall without subscribing # You have to handle this logic in your app ``` </TabItem> <TabItem value="Translations" label="Traductions"> ```json showLineNumbers { "title": { "en": "Try for free!", "es": "¡Prueba gratis!", "ru": "Попробуй бесплатно!" } } ``` </TabItem> </Tabs> Vous pouvez combiner ces patterns comme vous le souhaitez, ou définir vos propres clés pour tester d'autres textes, mises en page ou comportements. Ensuite, [créez un placement](create-placement) et ajoutez-y le flow. Puis affichez le flow dans votre application : [iOS](present-remote-config-paywalls) ou [Android](present-remote-config-paywalls-android). ## Ajouter une locale \{#add-a-locale\} Pour localiser votre flow, cliquez sur **Add locale** au-dessus de l'éditeur et sélectionnez des locales. Adapty ajoute une nouvelle colonne à l'éditeur pour cette locale. Modifiez chaque colonne indépendamment — au moment de l'exécution, le SDK retourne l'entrée `AdaptyRemoteConfig` dont la `locale` correspond à la sélection de l'utilisateur. ## Importer et exporter du JSON \{#import-and-export-json\} Utilisez le menu **Import/Export** au-dessus de l'éditeur pour sauvegarder, partager ou modifier en masse votre Remote Config pour toutes les locales en même temps. - **Export JSON** : Télécharge un fichier JSON unique contenant toutes les locales. - **Import JSON** : Charge un fichier JSON dans le même format. Le fichier importé remplace le Remote Config actuel. Le fichier utilise les codes de locale comme clés de premier niveau, avec le payload de chaque locale comme valeur : ```json showLineNumbers { "en": { "title": "Get Premium", "cta": "Continue", "trial_days": 7, "features": ["sync", "export", "ai"] }, "fr": { "title": "Passez à Premium", "cta": "Continuer", "trial_days": 7, "features": ["synchronisation", "exportation", "IA"] } } ``` Chaque bloc de locale suit la même structure JSON que vous saisiriez directement dans une colonne de locale. --- # File: paywall-device-compatibility-preview --- --- title: "Prévisualiser les flows" description: "Prévisualisez la compatibilité des flows sur différents appareils pour une expérience optimisée." --- Vous disposez de deux façons de prévisualiser votre flow sur différents types d'écrans : - **Prévisualisation sur les appareils** : Vérifiez l'apparence de votre flow sur de vrais appareils à n'importe quelle étape du développement. - **Prévisualisation dans l'Adapty Dashboard** : Prévisualisez votre flow pendant sa conception. ## Aperçu sur les appareils \{#preview-on-devices\} Pour prévisualiser votre flow sur un vrai appareil : 1. Téléchargez l'application mobile Adapty pour [iOS](https://apps.apple.com/us/app/adapty/id6739359219) ou [Android](https://play.google.com/store/apps/details?id=io.adapty.dashboard). 2. Dans le flow builder, cliquez sur **Test on device**. 3. Sélectionnez la langue du flow. 4. Scannez le QR code avec l'appareil photo ou ouvrez le lien. Votre flow s'ouvrira dans l'application mobile Adapty. :::note En mode test, Adapty ne peut pas accéder à vos produits dans les stores, donc les prix affichés dans le flow ne sont pas réels. ::: ### Résolution des problèmes \{#troubleshooting\} Vous ne pouvez pas publier ni prévisualiser votre flow si l'un des problèmes suivants est présent. - Une interaction avec une configuration incomplète. Cas courants : - Une action **Open URL** sans URL cible. - Une action **Navigate to screen** sans destination — se produit aussi lorsque l'écran de destination est supprimé après la configuration de l'action. - Une **action conditionnelle** sans opérateur ni valeur. - Une action **Set Variable** sans assignation de variable/valeur. - Une action **Purchase** sans produit (store intégré) ou sans URL de paywall web (paiement web). - Une action **Custom** sans ID d'action. - Une action **Show alert** avec un Titre ou un Message vide. - Une action **Show** ou **Hide** sans élément sélectionné. - Un **écran sans éléments**. - Un élément produit **sans produit associé** — peut survenir si vous supprimez le produit référencé. - Un JSON de **Remote Config** invalide qui bloque l'ensemble du processus de diffusion — vous ne pouvez même pas enregistrer le brouillon. ## Aperçu dans l'Adapty Dashboard \{#preview-in-the-adapty-dashboard\} :::tip Pour vous assurer que votre flow est prêt à publier, [prévisualisez-le sur un vrai appareil](#preview-on-devices) et vérifiez qu'il s'affiche sans erreurs. ::: Vous pouvez prévisualiser votre flow sur différents types d'écrans depuis la zone d'aperçu dans le flow builder. Cela vous permet de vous assurer que votre flow s'affiche correctement sur tous les appareils et toutes les tailles d'écran. Grâce aux contrôles d'aperçu situés sous la prévisualisation, vous pouvez : - Sélectionner l'appareil sur lequel prévisualiser votre flow. - Basculer entre les modes d'aperçu horizontal et vertical. - Basculer entre les modes clair et sombre. - Changer de locale. :::tip - Prévisualisez toujours les différentes langues, car la longueur des mots varie selon les langues et la mise en page peut s'en trouver modifiée. - Pour prévisualiser les variables personnalisées, définissez des valeurs initiales. Par exemple, si vous ajoutez une variable `name`, vous pouvez lui donner la valeur initiale `Jane Doe` pour la prévisualiser. ::: --- # File: builder-save-publish --- --- title: "Enregistrer et publier des flows" description: "Enregistrez des flows comme brouillons et publiez-les pour vos utilisateurs" --- Le [Flow Builder](adapty-flow-builder) distingue l'enregistrement de la publication. Les brouillons conservent votre travail dans l'Adapty Dashboard, et la publication rend la version actuelle disponible aux utilisateurs via le SDK. Cet article explique ces deux actions et quand les utiliser. ## Enregistrer un flow comme brouillon \{#save-a-flow-as-a-draft\} :::warning Un [Remote Config](customize-flow-with-remote-config) invalide vous empêche d'enregistrer le brouillon. ::: Le Flow Builder sauvegarde automatiquement votre progression toutes les minutes. Pour enregistrer un brouillon manuellement, cliquez sur **Save draft** en haut à droite du Flow Builder, ou appuyez sur **Cmd/Ctrl + S**. Les brouillons sont privés au Dashboard. Ils ne changent pas ce que voient les utilisateurs dans votre application, même si le flow est déjà assigné à un [placement](placements). ## Publier un flow \{#publish-a-flow\} La publication rend la version actuelle de votre flow disponible aux utilisateurs via le SDK. Une fois publié, la nouvelle version remplace toute version précédemment publiée du même flow. :::note Pour ajouter un flow à un [placement](placements), publiez-le d'abord. Un flow en statut Draft ne peut pas être ajouté. ::: Pour publier votre flow, cliquez sur **Publish to Live** en haut à droite du Flow Builder. Ce qui se passe ensuite dépend de si le flow est déjà assigné à un placement : - **Flow déjà dans un placement** : les utilisateurs voient la nouvelle version dès leur prochaine requête vers ce placement. - **Flow non assigné à un placement** : ajoutez le flow à un [placement](create-placement) pour commencer à le montrer aux utilisateurs. :::tip Un flow est prêt à être publié dès que chaque action, écran et élément produit est entièrement configuré. Consultez la section [Résolution des problèmes](#troubleshooting) pour les erreurs les plus courantes. ::: :::warning Les [polices personnalisées](using-custom-fonts-in-flow-builder) ne sont pas embarquées avec le flow — vous devez ajouter chaque fichier de police à votre bundle d'application. Sans le fichier, les utilisateurs voient la police système de secours. Pour changer une police sur un flow publié sans casser les versions plus anciennes : dupliquez le flow, modifiez la police dans la copie, et ciblez la copie vers une [audience](add-audience-paywall-ab-test) sur les versions de l'application qui incluent la police. ::: ## Statut d'un flow \{#flow-status\} Chaque flow affiche un statut dans la liste des flows. Le statut reflète où en est le flow dans le cycle de vie d'enregistrement et de publication. | Statut | Signification | | :----- | :------ | | **Draft** | Le flow n'a jamais été publié. Seul un brouillon existe, donc les utilisateurs ne le voient pas encore. Vous devez d'abord publier le brouillon pour l'ajouter à un [placement](placements). | | **Dirty** | Le flow a été publié, mais il contient des modifications enregistrées qui ne sont pas encore publiées. Les utilisateurs voient toujours la dernière version publiée jusqu'à la prochaine publication. | | **Publishing** | Une publication est en cours. | | **Failed** | La dernière tentative de publication a échoué. Les utilisateurs continuent de voir la dernière version publiée, si elle existe. | | **Published** | La dernière version enregistrée est en ligne. Il n'y a aucune modification non publiée. | | **Archived** | Le flow a été supprimé. | ## Résolution des problèmes \{#troubleshooting\} Vous ne pouvez pas publier ni prévisualiser votre flow si l'un des problèmes suivants est présent. - Une interaction avec une configuration incomplète. Cas courants : - Une action **Open URL** sans URL cible. - Une action **Navigate to screen** sans destination — se produit aussi lorsque l'écran de destination est supprimé après la configuration de l'action. - Une **action conditionnelle** sans opérateur ni valeur. - Une action **Set Variable** sans assignation de variable/valeur. - Une action **Purchase** sans produit (store intégré) ou sans URL de paywall web (paiement web). - Une action **Custom** sans ID d'action. - Une action **Show alert** avec un Titre ou un Message vide. - Une action **Show** ou **Hide** sans élément sélectionné. - Un **écran sans éléments**. - Un élément produit **sans produit associé** — peut survenir si vous supprimez le produit référencé. - Un JSON de **Remote Config** invalide qui bloque l'ensemble du processus de diffusion — vous ne pouvez même pas enregistrer le brouillon. Prévisualisez votre flow dans l'[application Adapty](paywall-device-compatibility-preview) pour détecter d'éventuels problèmes avant la publication. Si le flow ne se charge pas dans la prévisualisation, consultez le message d'erreur pour plus de détails. --- # File: flow-metrics --- --- title: "Métriques de flow" description: "Suivez et analysez les métriques de performance des flows pour améliorer les revenus d'abonnement." --- Adapty collecte une série de métriques pour vous aider à mesurer la performance de vos flows. Contrairement aux métriques de paywall, les métriques de flow incluent le suivi des complétions, ce qui vous permet de voir où les utilisateurs abandonnent à travers les écrans du flow. Toutes les métriques sont mises à jour en temps réel, sauf les vues, qui sont actualisées toutes les quelques minutes. Ce document présente les métriques disponibles, leurs définitions et leur mode de calcul. :::important Le revenu d'un flow est calculé à partir de toutes les transactions survenues après que le flow a été affiché. ::: Les métriques de flow sont disponibles dans la liste des flows, offrant une vue d'ensemble de la performance de tous vos flows. Cette vue consolidée présente des métriques agrégées pour chaque flow, vous permettant de comparer leur efficacité et d'identifier les axes d'amélioration. Pour une analyse plus granulaire de chaque flow, accédez aux métriques détaillées du flow. Vous y trouverez des métriques complètes spécifiques au flow sélectionné, offrant un aperçu plus approfondi de sa performance. ## Contrôles des métriques \{#metrics-controls\} Le système affiche les métriques en fonction de la période sélectionnée et les organise selon le paramètre de la colonne de gauche avec trois niveaux d'indentation. Pour les flows publiés, les métriques couvrent la période allant de la date de publication du flow jusqu'à la date actuelle. Les flows en brouillon et archivés sont inclus dans le tableau des métriques, mais si aucune donnée n'est disponible, ils apparaissent sans métriques affichées. ### Options d'affichage des données de métriques \{#view-options-for-metrics-data\} La page du flow propose deux options d'affichage des données de métriques : - Vue par placement : les métriques sont regroupées par [placements](placements) associés au flow. Utilisez cette vue pour comparer les performances du même flow sur différents placements. - Vue par audience : les métriques sont regroupées par [audience](audience) cible du flow. Utilisez cette vue pour évaluer les métriques spécifiques à différents segments d'audience. Le menu déroulant en haut de la page du flow vous permet de sélectionner la vue souhaitée. ### Filtrer les métriques par date d'installation \{#filter-metrics-by-install-date\} La case **Filter metrics by install date** vous permet d'analyser les données en fonction de la date à laquelle les utilisateurs ont installé votre application, plutôt qu'en fonction de la date des transactions ou des vues. C'est utile pour mesurer la performance d'acquisition utilisateur pour une cohorte spécifique. ### Plages de temps \{#time-ranges\} Vous pouvez analyser les données de métriques en utilisant une plage de temps, ce qui vous permet de vous concentrer sur des durées spécifiques comme des jours, des semaines, des mois ou des plages de dates personnalisées. ### Filtres et regroupements \{#filters-and-groups\} Adapty propose des outils de filtrage et de personnalisation de l'analyse des métriques pour répondre à vos besoins. La page des métriques vous donne accès à diverses plages de temps, options de regroupement et possibilités de filtrage. - Filtrer par : Attribution (source, groupe d'annonces, ensemble d'annonces, création, campagne), Pays, Store. - Regrouper par : Flow (par défaut), Pays ou Store. Les options de regroupement n'apparaissent dans le menu déroulant que lorsqu'il existe des données pour cette dimension — par exemple, si toutes les vues du flow proviennent d'un seul pays, Pays ne sera pas proposé. Vous trouverez plus d'informations sur les contrôles, filtres, options de regroupement disponibles et leur utilisation dans [cette documentation](controls-filters-grouping-compare-proceeds). ### Graphique d'une métrique unique \{#single-metric-chart\} La section graphique affiche vos données sous forme de diagramme à barres simple. Le graphique vous permet de voir rapidement : - Les chiffres exacts pour chaque métrique. - Les données spécifiques à chaque période. Un total apparaît à côté du graphique, vous donnant une vue d'ensemble en un coup d'œil. Cliquez sur l'icône en forme de flèche pour développer le graphique. ### Récapitulatif des métriques totales \{#total-metrics-summary\} À côté du graphique de métrique unique se trouve une section de récapitulatif des métriques totales. Cette section affiche les valeurs cumulées des métriques sélectionnées à un moment précis. Vous pouvez changer la métrique affichée via un menu déroulant. ## Définitions des métriques \{#metrics-definitions\} ### Vues et vues uniques \{#views--unique-views\} Les **vues** comptent le nombre de fois où les utilisateurs démarrent votre flow (atteignent le premier écran). Si quelqu'un le démarre deux fois, cela compte comme deux vues mais une seule vue unique. Cette métrique vous aide à comprendre la fréquence d'affichage de votre flow. ### Complétions et complétions uniques \{#completions--unique-completions\} Les **complétions** comptent le nombre de fois où les utilisateurs atteignent le dernier écran de votre flow. Si quelqu'un le complète deux fois, cela compte comme deux complétions mais une seule complétion unique. ### Taux de complétions uniques \{#unique-completions-rate\} Le nombre de complétions uniques divisé par le nombre de vues uniques. Utilisez cette métrique pour comprendre comment les utilisateurs progressent dans le flow et identifier où ils abandonnent. :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: ### Revenu \{#revenue\} Le **revenu** affiche vos gains totaux en USD provenant des achats et renouvellements attribués au flow. Il s'agit du montant avant toute déduction, y compris la commission de l'App Store / Play Store. ### Proceeds \{#proceeds\} Les [**proceeds**](analytics-cohorts#revenue-vs-proceeds) correspondent à ce que vous recevez après que l'App Store / Play Store a prélevé sa commission, mais avant les taxes. :::important Informez Adapty si votre application est inscrite à un programme de commission réduite. Pour garantir des calculs corrects, indiquez votre statut dans le [programme Small Business](app-store-small-business-program) et le [programme de frais de service réduits](google-reduced-service-fee) dans vos [paramètres d'application](general). ::: ### Net proceeds \{#net-proceeds\} Vos gains finaux après déduction des commissions du store et des taxes. ### ARPPU \{#arppu\} L'ARPPU est le revenu moyen par utilisateur payant. Il est calculé en divisant le revenu total par le nombre d'utilisateurs payants uniques. Exemple : 15 000 $ de revenu / 1 000 utilisateurs payants = 15 $ d'ARPPU. ### ARPU \{#arpu\} L'ARPU est le revenu moyen par utilisateur ayant visionné le flow. Il est calculé en divisant le revenu total par le nombre de vues uniques. ### ARPAS \{#arpas\} L'ARPAS est le revenu moyen par abonné actif. Il est calculé en divisant le revenu total par le nombre d'abonnés ayant activé un essai ou un abonnement. Exemple : 5 000 $ de revenu / 1 000 abonnés = 5 $ d'ARPAS. ### CR achats et CR achats uniques \{#cr-purchases--unique-cr-purchases\} Le **taux de conversion vers les achats** indique quel pourcentage des vues du flow aboutit à un achat. Par exemple, 10 achats sur 100 vues représentent un taux de conversion de 10 %. Le **CR achats uniques** mesure quel pourcentage d'utilisateurs uniques qui voient votre flow finissent par effectuer un achat, en comptant chaque utilisateur une seule fois, quel que soit le nombre de fois où il le voit. ### CR essais et CR essais uniques \{#cr-trials--unique-cr-trials\} Le **taux de conversion vers les essais** indique quel pourcentage des vues du flow aboutit au démarrage d'un essai. Par exemple, 10 essais sur 100 vues représentent un taux de conversion de 10 %. Le **CR essais uniques** mesure quel pourcentage d'utilisateurs uniques qui voient votre flow démarrent un essai, en comptant chaque utilisateur une seule fois, quel que soit le nombre de fois où il le voit. ### Achats \{#purchases\} Les **achats** comptabilisent toutes les transactions sur votre flow, à l'exception des renouvellements. Cela inclut : - Les nouveaux achats directs. - Les conversions d'essais activés sur le flow. - Les changements de plan (mises à niveau, rétrogradations, changements de niveau). - Les restaurations d'abonnement sur le flow, par exemple lorsqu'un abonnement est rétabli après expiration sans renouvellement automatique. Cette métrique vous donne une vue complète de la nouvelle activité transactionnelle générée par votre flow. ### Essais \{#trials\} Les **essais** comptent le nombre d'utilisateurs qui ont démarré des périodes d'essai gratuites via votre flow. Utilisez cette métrique pour suivre l'efficacité de votre offre d'essai à attirer les utilisateurs avant qu'ils décident de payer. ### Essais annulés \{#trials-cancelled\} Les **essais annulés** indiquent combien d'utilisateurs ont désactivé le renouvellement automatique pendant leur période d'essai. Cela vous indique combien de personnes ont décidé de ne pas poursuivre avec un abonnement payant après avoir essayé votre service. ### Remboursements \{#refunds\} Les **remboursements** comptent le nombre d'achats et d'abonnements qui ont été remboursés, quelle qu'en soit la raison. ### Taux de remboursement \{#refund-rate\} Le **taux de remboursement** indique le pourcentage des premiers achats remboursés. Exemple : 5 remboursements sur 1 000 premiers achats = 0,5 % de taux de remboursement. Les renouvellements ne sont pas pris en compte dans ce calcul. --- # File: fallback-flows --- --- title: "Flows de secours" description: "Configurez des flows de secours locaux dans Adapty pour que votre flow reste visible lorsque l'appareil est hors ligne." --- Pour maintenir une expérience utilisateur fluide, il est important de configurer des **versions de secours** de vos [flows](adapty-flow-builder). Lorsque votre application demande un flow, le SDK Adapty contacte nos serveurs pour récupérer sa configuration. Si l'appareil ne peut pas joindre Adapty (problème réseau, panne de serveur), le SDK bascule sur les données locales : - Si l'utilisateur a déjà vu le flow une fois, le SDK utilise la copie en cache. - Si aucun cache n'existe, le SDK charge un fichier de configuration de secours inclus dans l'application. Adapty génère automatiquement ces fichiers de secours. Le bundle de secours du flow est partagé avec les paywalls — un seul fichier JSON par plateforme contient les variantes de secours pour les deux. Le SDK lit la section dont il a besoin. :::important Les fallbacks de flow sont inclus dans le bundle **Adapty SDK 4.0+**. Si vous sélectionnez une version antérieure du SDK dans la fenêtre de téléchargement, le fichier ne contient que des variantes de paywall et d'onboarding — sans flows. Assurez-vous que votre application utilise une version du SDK compatible avec les flows avant de vous appuyer sur un fallback de flow. ::: ## Avant de commencer \{#before-you-start\} 1. Créez un [flow](adapty-flow-builder) dans le Flow Builder. 2. [Créez un placement](create-placement) pour le flow. ## Télécharger le fichier de secours \{#download-the-fallback-file\} 1. Ouvrez la page **[Placements](https://app.adapty.io/placements)**. 2. Cliquez sur le bouton **Fallbacks** en haut à droite. 3. Sélectionnez votre plateforme cible dans le menu déroulant. 4. Choisissez la version du SDK qui correspond à celle embarquée dans votre application. Sélectionnez **Adapty SDK v4.0.0 and higher** (ou une option ultérieure) pour recevoir un bundle qui inclut les flows. Le navigateur télécharge un fichier JSON par plateforme — par exemple, `ios_4_0_0_fallback.json`. <details> <summary>Exemple d'entrée de fallback de flow (cliquez pour développer)</summary> ```json "PLACEMENT_ID": { "data": [ { "developer_id": "PLACEMENT_ID", "variation_id": "cb1c0ef8-aecd-4a53-a6f3-b98266e66884", "flow_id": "daf25858-3fa2-4981-8500-9c8a30e5b7e6", "flow_name": "FLOW_NAME", "flow_version_id": "FLOW_VERSION_ID", "placement_audience_version_id": "a9eb3ab8-3178-477d-84d4-ef9d3978e48b", "audience_name": "All Users", "ab_test_name": "", "cross_placement_info": null, "weight": 100, "variations": [ { "variation_id": "cb1c0ef8-aecd-4a53-a6f3-b98266e66884", "paywall_id": "PAYWALL_ID", "paywall_name": "PAYWALL_NAME", "ab_test_name": "", "products": [], "revision": 1, "custom_payload": null, "weight": 100 } ], "remote_configs": [] } ], "meta": { "placement": { "developer_id": "PLACEMENT_ID", "is_tracking_purchases": true, "audience_name": "All Users", "placement_audience_version_id": "a9eb3ab8-3178-477d-84d4-ef9d3978e48b", "revision": 0, "ab_test_name": "" } } } ``` La structure exacte peut changer entre les versions du SDK. Utilisez toujours le fichier généré par Adapty pour votre version du SDK plutôt que de le créer manuellement. </details> ## Après le téléchargement \{#after-the-download\} Ajoutez le fichier à votre code d'application, puis suivez le guide de configuration propre à votre plateforme. Les mêmes API qui chargent les paywalls de secours chargent également les fallbacks de flow dès que votre application utilise une version du SDK compatible avec les flows : - [iOS](ios-use-fallback-paywalls) - [Android](android-use-fallback-paywalls) - [React Native](react-native-use-fallback-paywalls) - [Capacitor](capacitor-use-fallback-paywalls) ## Limitations \{#limitations\} Les flows de secours sont codés en dur et stockés localement, ils ne bénéficient donc pas de toutes les capacités dynamiques des flows en direct : - **Une seule variante par placement.** Si un placement comporte plusieurs flows (audiences différentes, variantes de test A/B), le fichier de secours utilise la variante ayant le poids le plus élevé, ou l'audience la plus large. - **Pas de test A/B.** Un test A/B de flow en direct est résolu côté serveur ; le secours sert toujours une seule variante choisie. - **Pas de mises à jour à distance.** Mettre à jour le fichier de secours nécessite une nouvelle version de l'application. Pour les mises à jour que vous feriez normalement via Remote Config, utilisez plutôt le flow en direct. --- # File: product --- --- title: "Produits" description: "Explorez les paramètres de produits d'Adapty pour configurer et optimiser vos achats intégrés et abonnements." --- Un produit est tout article ou contenu disponible à l'achat dans une application mobile. Cela peut inclure divers biens numériques tels que des objets virtuels, des abonnements, des fonctionnalités supplémentaires ou des mises à niveau de contenu que les utilisateurs peuvent acheter pour enrichir leur expérience dans l'application. Par exemple, dans un jeu, les produits peuvent inclure de la monnaie virtuelle, des bonus ou des extensions. Dans une application de productivité, les produits peuvent inclure des fonctionnalités premium ou l'accès à du contenu exclusif. Ces produits sont gérés et vendus via le système d'achat intégré fourni par la plateforme (par exemple, l'App Store d'Apple ou le Google Play Store). Dans Adapty, vous pouvez regrouper des produits similaires de l'App Store et du Play Store en un seul produit interne. Cela vous permet d'utiliser un seul produit Adapty sur toutes les plateformes, plutôt que d'utiliser les produits de chaque éditeur séparément. :::note Liste de vérification pour afficher correctement les produits dans votre application mobile 1. [Créez des produits dans l'Adapty Dashboard](create-product). 2. [Créez un paywall dans l'Adapty Dashboard et ajoutez-y des produits](create-paywall) 3. Affichez les paywalls en utilisant les placements auxquels ils appartiennent dans votre application mobile : - [iOS](ios-quickstart-paywalls) - [Android](android-quickstart-paywalls) - [React Native](react-native-quickstart-paywalls) - [Flutter](flutter-quickstart-paywalls) - [Unity](unity-quickstart-paywalls) ::: Une fois vos produits créés dans l'Adapty Dashboard, ils sont visibles dans la section **[Products](https://app.adapty.io/products)**. <img src="/assets/shared/img/poducts-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: create-product --- --- title: "Créer un produit" description: "Guide étape par étape pour créer de nouveaux produits d'abonnement dans Adapty pour une meilleure gestion des revenus." --- La façon de créer des produits dans Adapty dépend de si vous les avez déjà dans les stores : - **[Si les produits n'existent pas encore dans l'App Store et/ou Google Play, créez-les dans Adapty et publiez-les directement dans les stores](#create-product-and-push-to-store)**. - **[Si les produits existent déjà dans l'App Store et/ou Google Play, créez-les dans Adapty et connectez les produits existants des stores.](#create-product-and-connect-existing-store-products)** :::tip Vous pouvez également créer des produits de façon programmatique via la [CLI développeur](developer-cli-reference#adapty-products-create). ::: ## Créer un produit et le publier dans le store \{#create-product-and-push-to-store\} :::warning Avant de commencer, assurez-vous d'avoir configuré l'intégration avec les stores dont vous avez besoin : - [App Store](initial_ios) - [Google Play](initial-android) Si vous avez configuré l'intégration App Store il y a un certain temps, vérifiez également que vous avez [ajouté la clé API App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key). ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/qUpC2XG-r5E?si=7Komyv4_PUQ4FaEH" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Pour ajouter un nouveau produit à votre application : 1. Accédez à **[Products](https://app.adapty.io/products)** depuis le menu principal d'Adapty. <img src="/assets/shared/img/products-tab.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur **Create product** en haut à droite. Adapty prend en charge tous les types de produits : abonnements, non-consommables \(y compris à vie\) et consommables. 3. Sélectionnez **Create a new product and push to stores**. <img src="/assets/shared/img/push-to-stores.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Renseignez les informations suivantes : - **Product name** : saisissez le nom du produit tel qu'il apparaîtra dans le tableau de bord Adapty. Ce nom est avant tout une référence pour vous, choisissez donc celui qui vous convient le mieux dans l'Adapty Dashboard. - **Access Level** : sélectionnez le [niveau d'accès](access-level) auquel appartient le produit. Le niveau d'accès détermine les fonctionnalités débloquées après l'achat. Cette liste ne contient que les niveaux d'accès déjà créés. Le niveau d'accès `premium` est créé par défaut dans Adapty, mais vous pouvez également [en ajouter d'autres](access-level). - **Subscription duration** : sélectionnez la durée de l'abonnement dans la liste. - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual** : la durée de l'abonnement. - **Lifetime** : utilisez la durée à vie pour les produits qui débloquent les fonctionnalités premium de l'application de façon permanente. - **Non-Subscriptions** : pour les produits qui ne sont pas des abonnements et n'ont donc pas de durée, utilisez les non-abonnements. Ils peuvent débloquer des fonctionnalités supplémentaires, des produits consommables, etc. - **Consumables** : les articles consommables peuvent être achetés plusieurs fois et s'épuisent au fil de l'utilisation de l'application. Les exemples typiques sont la monnaie virtuelle et les bonus en jeu. Notez que les produits consommables n'affectent pas les niveaux d'accès. Pour accorder un niveau d'accès à partir d'un achat unique, utilisez **Non-Subscriptions** à la place. - **Price (USD)** : le prix du produit en USD. Ce prix servira de base pour calculer et définir automatiquement les prix dans tous les pays. Vous pourrez [personnaliser le prix pour différents pays et régions](edit-product#set-country-specific-prices) ultérieurement. <img src="/assets/shared/img/create-product-push.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Save & Continue**. 6. Configurez les informations du produit pour l'App Store si vous prévoyez d'y publier : - **Product ID** : créez un identifiant unique et permanent pour le produit. - **Product group** : sélectionnez un groupe de produits existant que vous avez créé dans App Store Connect, ou cliquez sur **Create new Product Group** et définissez son nom. Une fois qu'Adapty l'a créé, vous pouvez le sélectionner dans la liste déroulante. - **Screenshot** : téléchargez une capture d'écran de l'achat intégré montrant clairement l'article ou le service proposé. Cette capture d'écran est utilisée uniquement pour la révision App Store et n'est pas affichée sur l'App Store. Consultez les exigences de taille et de format [ici](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/). <img src="/assets/shared/img/push-app-store.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur **Push data to App Store**. :::warning S'il s'agit de votre premier produit pour cette application, vous devez le soumettre manuellement pour révision dans App Store Connect. Cela ne sera plus nécessaire par la suite. Une fois la révision terminée, le statut du produit dans Adapty se mettra à jour automatiquement. ::: 8. Configurez les informations du produit pour Google Play si vous prévoyez d'y publier : - **Base Product ID** : créez un identifiant unique et permanent pour le produit. - **Subscription** : sélectionnez un groupe d'abonnements existant que vous avez créé dans Google Play Console, ou cliquez sur **Create new Product Group** et définissez son nom et son identifiant. Une fois qu'Adapty l'a créé, vous pouvez le sélectionner dans la liste déroulante. :::note Le délai de grâce et la période de suspension de compte seront automatiquement définis selon les valeurs par défaut du Play Store. Vous pourrez les modifier ultérieurement dans Google Play Console. ::: <img src="/assets/shared/img/push-google-play.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Cliquez sur **Push data to Play Store**. 10. Pour iOS, configurez l'offre de lancement – essai gratuit – en sélectionnant sa **Free duration** dans la liste déroulante. Pour cette configuration initiale, vous pouvez ajouter un essai gratuit d'introduction. Une fois le produit principal approuvé par les stores, vous pourrez [ajouter d'autres offres](offers) (par exemple, promotionnelles, de reconquête) en liant leurs identifiants existants depuis votre console de store. <img src="/assets/shared/img/intro.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Les offres de lancement ne se synchronisent pas automatiquement avec Google Play. Contrairement à l'App Store, Google Play ne dispose pas d'un type d'« offre de lancement » distinct — les essais gratuits et les offres à tarif réduit sont tous configurés en tant qu'**offres** sur un plan de base. [Créez l'offre dans Google Play Console et liez-la à votre produit Adapty](google-play-offers). ::: 11. Enfin, cliquez sur **Save** pour confirmer la création du produit. ## Créer un produit et connecter des produits existants des stores \{#create-product-and-connect-existing-store-products\} :::warning Avant de commencer, assurez-vous d'avoir : - Configuré l'intégration avec les stores dont vous avez besoin : - [App Store](initial_ios) - [Google Play](initial-android) - Créé des produits dans les stores dont vous avez besoin : - [App Store](app-store-products) - [Google Play](android-products) **Si vous n'avez aucun produit créé**, suivez le guide [Publier dans les stores](#create-product-and-push-to-store) pour les créer simultanément dans Adapty et dans les stores. ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/nlkdKCF0SwY?si=VVigzHcpv3waKJmI" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> Pour ajouter un nouveau produit à votre application : 1. Accédez à **[Products](https://app.adapty.io/products)** depuis le menu principal d'Adapty. <img src="/assets/shared/img/products-tab.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur **Create product** en haut à droite. Adapty prend en charge tous les types de produits : abonnements, non-consommables \(y compris à vie\) et consommables. 3. Sélectionnez **Connect an existing store product**. <img src="/assets/shared/img/existing-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Renseignez les informations suivantes : - **Product name** : saisissez le nom du produit tel qu'il apparaîtra dans le tableau de bord Adapty. Ce nom est avant tout une référence pour vous, choisissez donc celui qui vous convient le mieux dans l'Adapty Dashboard. - **Access Level ID** : sélectionnez le [niveau d'accès](access-level) auquel appartient le produit. Le niveau d'accès détermine les fonctionnalités débloquées après l'achat. Cette liste ne contient que les niveaux d'accès déjà créés. Le niveau d'accès `premium` est créé par défaut dans Adapty, mais vous pouvez également [en ajouter d'autres](access-level). - **Subscription duration** : sélectionnez la durée de l'abonnement dans la liste. - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual** : la durée de l'abonnement. - **Lifetime** : utilisez la durée à vie pour les produits qui débloquent les fonctionnalités premium de l'application de façon permanente. - **Non-Subscriptions** : pour les produits qui ne sont pas des abonnements et n'ont donc pas de durée, utilisez les non-abonnements. Ils peuvent débloquer des fonctionnalités supplémentaires, des produits consommables, etc. - **Consumables** : les articles consommables peuvent être achetés plusieurs fois et s'épuisent au fil de l'utilisation de l'application. Les exemples typiques sont la monnaie virtuelle et les bonus en jeu. Notez que les produits consommables n'affectent pas les niveaux d'accès. Pour accorder un niveau d'accès à partir d'un achat unique, utilisez **Non-Subscriptions** à la place. - **Price (USD)** : le prix du produit en USD. Si votre produit est déjà dans le store, cette valeur n'affectera pas son prix réel ; vous pouvez sélectionner n'importe quelle valeur dans la liste. Vous pourrez ensuite [personnaliser les prix pour différentes régions](edit-product#set-country-specific-prices) directement depuis le tableau de bord Adapty. <img src="/assets/shared/img/product-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Continue**. 6. Configurez les informations du produit pour chaque store : - **App Store :** - **App Store Product ID :** cet identifiant unique permet d'accéder à votre produit sur les appareils. Sélectionnez-le dans la liste. Si vous ne le voyez pas, vérifiez sa configuration dans App Store Connect et assurez-vous qu'il est correct et qu'il appartient à cette application. - **Play Store :** - **Google Play Product ID :** il s'agit de l'identifiant du produit dans le Play Store. Sélectionnez-le dans la liste. Si vous ne le voyez pas, vérifiez sa configuration dans Google Play Console et assurez-vous qu'il est correct et qu'il appartient à cette application. - **Base Plan ID :** cet identifiant définit le plan de base du produit dans le Play Store. Lorsque vous ajoutez l'identifiant d'un produit d'abonnement sur le Play Store, vous devez fournir un identifiant de plan de base. Un plan de base définit les détails essentiels d'un abonnement : la période de facturation, le type de renouvellement (automatique ou prépayé) et le prix associé. Notez que dans Adapty, chaque combinaison d'un même abonnement avec différents plans de base est traitée comme un produit distinct. - **Legacy fallback product** : un produit de secours utilisé exclusivement pour les applications utilisant d'anciennes versions du SDK Adapty (version 2.5 et antérieures). En marquant un produit comme rétrocompatible dans Google Play Console, Adapty peut déterminer s'il peut être acheté par d'anciennes versions du SDK. Pour ce champ, indiquez la valeur au format suivant : `<subscription_id>:<base_plan_id>`. - **Stripe** : - **Stripe Product ID** : identifiant unique d'un produit dans Stripe. - **Stripe Price ID** : dans Stripe, les objets de prix contiennent bien plus que le montant ; ils couvrent également le comportement fiscal, les paliers de volume et les intervalles d'abonnement. Comme un seul produit peut avoir plusieurs prix, indiquez l'identifiant de prix correct lors de la création d'un produit dans Adapty. - **Paddle** : - **Paddle Product ID** : identifiant unique d'un produit dans Paddle. - **Paddle Price ID** : dans Paddle, les objets de prix contiennent bien plus que le montant ; ils couvrent également le comportement fiscal, les paliers de volume et les intervalles d'abonnement. Comme un seul produit peut avoir plusieurs prix, indiquez l'identifiant de prix correct lors de la création d'un produit dans Adapty. 7. **Facultatif :** vous pouvez ajouter des produits depuis n'importe quel store personnalisé en cliquant sur **Add custom store**. Dans la fenêtre **Manage custom store info**, vous pouvez sélectionner un store personnalisé existant ou en ajouter un nouveau et y associer un produit. Gardez à l'esprit qu'Adapty ne suit que les transactions de l'App Store, Google Play et Stripe. Pour les stores personnalisés, vous devrez soumettre les transactions via la méthode Set transaction de l'API côté serveur d'Adapty. 8. Cliquez sur **Save product** pour finaliser la création du produit. La synchronisation du statut des produits peut prendre jusqu'à cinq minutes ; attendez qu'ils se mettent à jour dans le tableau. 9. Vous pouvez [créer des offres](create-offer) pour le produit si nécessaire. Pour ajouter des offres, cliquez sur **Yes, add offers**. Sinon, cliquez sur **No, thanks**. :::note Les offres de lancement sont créées dans Adapty uniquement lors de la publication d'un produit dans le store. Lors d'une importation ou pour des produits déjà créés, les offres de lancement ne sont pas synchronisées et n'apparaissent pas dans Adapty, mais fonctionneront tout de même correctement dans l'application. ::: ## Étapes suivantes \{#next-steps\} Félicitations ! Vous avez ajouté vos produits dans Adapty. Et maintenant ? - Si vous n'avez pas encore configuré les offres de lancement ou promotionnelles, vous pouvez le [faire maintenant](offers). - Si vous ne souhaitez pas le faire ou l'avez déjà fait, passez à la [configuration des paywalls](quickstart-paywalls) pour activer les achats intégrés. - Si vous souhaitez apporter des ajustements aux produits du store (par exemple, définir des prix régionaux ou configurer le délai de grâce), faites-le dans App Store Connect ou Google Play Console. - Découvrez comment [modifier des produits](edit-product) ultérieurement. --- # File: edit-product --- --- title: "Modifier un produit" description: "Modifiez et gérez vos produits d'abonnement dans Adapty pour un meilleur suivi des revenus." --- Dans Adapty, vous pouvez modifier le nom de votre produit, son niveau d'accès, les prix par région et les identifiants de store associés, et consulter le journal d'audit pour suivre les modifications de prix. La durée de l'abonnement n'est pas modifiable après la création du produit ; vous devez donc créer un nouveau produit pour la changer. :::warning Bien que vous puissiez modifier n'importe quel produit, il est essentiel de s'assurer que les modifications apportées à des produits déjà utilisés dans des paywalls en production n'entraînent pas d'incohérences dans vos analyses. **Il n'est pas recommandé de modifier le niveau d'accès, l'App Store Product ID et le Play Store Product ID**, car cela peut nuire à la clarté des analyses. Ne les modifiez que si vous avez commis une erreur, comme une faute de frappe dans l'identifiant du produit. Si vous n'utilisez plus le produit et souhaitez le remplacer par un autre, nous vous conseillons vivement de créer un nouveau produit et de mettre à jour les paywalls et les tests A/B en conséquence. ::: ## Modifier un produit \{#edit-product\} Pour modifier le produit : 1. Accédez à **[Products](https://app.adapty.io/products)** depuis le menu principal d'Adapty. 2. Cliquez sur la ligne du produit dans le tableau, ou cliquez sur les trois points à côté du produit et sélectionnez **Edit**. 3. Dans la fenêtre **Edit** qui s'ouvre, effectuez les modifications souhaitées. Pour plus de détails sur les options disponibles dans cette fenêtre, consultez la section [Créer un produit](create-product). 4. Cliquez sur **Save**. :::warning Les modifications que vous apportez dans App Store Connect ou Google Play Console ne sont pas synchronisées avec Adapty. Le prix affiché dans Adapty est défini lors de la création du produit et ne se met pas à jour si vous modifiez le prix dans le store. Cela n'affecte pas vos analyses de revenus — Adapty récupère les données de revenus directement depuis les stores. Le champ de prix dans le tableau de bord est fourni à titre indicatif uniquement. ::: :::note Si vous modifiez le niveau d'accès, le changement s'applique uniquement aux nouveaux abonnements. Pour les abonnés existants, le niveau d'accès actuel reste inchangé et se met à jour automatiquement lors du prochain renouvellement de l'abonnement. ::: <img src={require('./img/edit-product.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Définir des prix par pays \{#set-country-specific-prices\} Vous pouvez définir des prix différents selon les régions directement dans le tableau de bord Adapty, et ces prix par pays seront appliqués automatiquement à vos produits dans App Store Connect et/ou Google Play Console. Pour définir des prix par pays : 1. [Ouvrez le produit pour le modifier](#edit-product). 2. Cliquez sur **Download** pour exporter vos prix actuels depuis les stores dans le bon format, ou créez un nouveau fichier CSV. <img src={require('./img/download-prices.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Mettez à jour les prix dans le fichier CSV. Respectez le [format](#csv-file-format). Si vous laissez le prix d'un pays inchangé ou ne l'incluez pas du tout dans le fichier, rien ne se passera. Lors du téléversement du CSV, Adapty compare les prix et ne met à jour que ceux qui diffèrent. 4. Dans la fenêtre **Edit**, cliquez sur **Upload** et sélectionnez le fichier CSV. <img src={require('./img/upload-prices.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Si vous souhaitez que les modifications s'appliquent également aux abonnés existants, cochez **Apply to existing subscribers**. 6. Vérifiez les modifications qui seront appliquées et cliquez sur **Save changes**. <img src={require('./img/country-level-price.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Format du fichier CSV \{#csv-file-format\} :::tip Vous pouvez réutiliser le même fichier CSV si vous avez des produits similaires dans une application ou si vous souhaitez appliquer les mêmes prix dans différentes applications. ::: La façon la plus simple de modifier les prix dans un CSV est de [télécharger un fichier avec les prix actuels et de le modifier directement](#set-country-specific-prices). Cependant, si vous le faites vous-même, votre fichier doit contenir les colonnes suivantes : - `region_name` - `region_code` - `app_store_currency` - `app_store_requested_price` - `play_store_currency` - `play_store_requested_price` Exemple : ``` region_name,region_code,app_store_currency,app_store_requested_price,play_store_currency,play_store_requested_price United States,US,,8.99,,8.99 United Arab Emirates,AE,USD,8.99,AED,39.99 Germany,DE,USD,8.99,USD,8.99 ``` ## Consulter le journal d'audit \{#view-audit-log\} Adapty enregistre toutes les modifications de prix pour chaque produit, ce qui vous permet de suivre qui a effectué des modifications et à quel moment. Pour consulter le journal d'audit : 1. Accédez à **[Products](https://app.adapty.io/products)** depuis le menu principal d'Adapty. 2. Cliquez sur les trois points à côté du produit et sélectionnez **Audit log**. Le tableau du journal d'audit affiche chaque modification de prix avec la date, le nom et le rôle du membre de l'équipe, ainsi que le nombre de modifications. Pour télécharger un détail CSV complet d'un événement, cliquez sur l'icône de téléchargement dans la ligne correspondante. <img src={require('./img/audit-log.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: delete-product --- --- title: "Supprimer un produit" description: "Découvrez comment supprimer un produit d'abonnement dans Adapty sans perturber les revenus de votre application." --- Vous ne pouvez supprimer que les produits qui ne sont pas utilisés dans des paywalls. Pour supprimer le produit : 1. Accédez à **[Products](https://app.adapty.io/products)** depuis le menu principal d'Adapty. 2. Cliquez sur le bouton **3-dot** à côté du produit et sélectionnez **Delete**. <img src="/assets/shared/img/delete-product.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Saisissez le nom du produit que vous êtes sur le point de supprimer. <img src="/assets/shared/img/b945add-delete_product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Delete forever**. --- # File: add-product-to-paywall --- --- title: "Ajouter un produit à un paywall" description: "Apprenez à ajouter et gérer des produits sur les paywalls dans Adapty." --- Pour rendre un produit visible et sélectionnable dans un [paywall](paywalls) par les utilisateurs de votre application, suivez ces étapes : 1. Lors de la [configuration d'un paywall](create-paywall), cliquez sur **Add product** sous le titre **Products**. 2. Dans la liste déroulante qui s'affiche, sélectionnez les produits qui seront présentés à vos clients. La liste ne contient que les produits déjà créés. L'ordre des produits est conservé côté SDK, il est donc important de définir l'ordre souhaité lors de la configuration du paywall. Vous pouvez également spécifier une offre pour un produit si vous le souhaitez. <img src="/assets/shared/img/0479b51-ad_product_to_paywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Create as draft** ou **Save and publish** selon le statut du paywall. Gardez à l'esprit qu'après la création, il n'est pas recommandé de modifier, d'ajouter ou de supprimer des produits d'un paywall, car cela peut affecter les métriques du paywall. --- # File: virtual-currencies --- --- title: "Monnaies virtuelles" description: "Définissez des monnaies intégrées dans Adapty, liez-les à des produits pour créditer automatiquement des points, et suivez le solde de chaque utilisateur." --- <CustomDocCardList ids={['virtual-currency-quickstart', 'create-virtual-currency', 'virtual-currency-balance']} /> Accordez à vos utilisateurs une monnaie virtuelle — tokens IA, crédits ou pièces — lorsqu'ils achètent des produits ou renouvellent des abonnements. Définissez une monnaie une seule fois, associez-la aux produits qui doivent la distribuer, et Adapty crédite chaque utilisateur automatiquement en tenant à jour son solde. Votre application lit et dépense ce solde via l'[API côté serveur](getting-started-with-server-side-api) — par exemple, pour facturer des tokens par génération. ## Comment ça fonctionne \{#how-it-works\} 1. [Créez une devise virtuelle](create-virtual-currency) : Ouvrez **Products** et cliquez sur l'onglet **Virtual currency**. Cliquez sur **New virtual currency**. Définissez une devise avec un code, un nom et une description facultative. 2. **Associez la devise à des produits** : Reliez la devise à des produits à achat unique ou en abonnement, et définissez le nombre de crédits accordés pour chaque achat. 3. **Les crédits sont accordés automatiquement** : Lorsqu'un utilisateur achète un produit à achat unique associé ou renouvelle un abonnement associé, Adapty ajoute les crédits configurés à son solde. 4. **Lisez et dépensez le solde** : Votre application lit le solde de chaque utilisateur et accorde ou dépense des crédits via l'API côté serveur. 5. **Suivez chaque modification** : Chaque changement de solde est répertorié sur le [profil de l'utilisateur](virtual-currency-balance). Pour un guide complet — de la configuration de la devise à l'utilisation des crédits via l'API — suivez le [guide de démarrage rapide sur la monnaie virtuelle](virtual-currency-quickstart). ## Cas d'usage \{#use-cases\} | Type d'application | Comment utiliser les monnaies virtuelles | |----------|-------------------------------| | **Applications IA** (génération d'images, de vidéos ou de texte) | Facturer des crédits par génération. Inclure un quota mensuel de crédits dans l'abonnement et vendre des packs de crédits en tant que produits à achat unique. | | **Applications de courtes séries et de vidéos** | Facturer des pièces pour déverrouiller un épisode. Accorder aux abonnés un quota récurrent de pièces et vendre des packs de pièces en tant que produits à achat unique. | | **Apprentissage des langues et éducation** | Donner aux utilisateurs gratuits un quota limité de cœurs ou de vies via l'API côté serveur. Accorder un quota plus important, ou ignorer entièrement la vérification du solde, avec un abonnement payant. | | **Jeux mobiles** | Utiliser deux monnaies en parallèle (souple et forte) : accorder de l'or pour les parties via l'API côté serveur, vendre des gemmes contre de l'argent et convertir entre les deux dans une transaction atomique unique. | | **Applications de productivité** | Mesurer les actions coûteuses, comme l'OCR ou les exports, avec des crédits. Donner aux utilisateurs gratuits un petit quota, en accorder davantage avec un abonnement, et vendre des packs de crédits pour les traitements en lot. | :::tip Pour les allocations d'abonnement, activez l'[expiration des crédits](create-virtual-currency#link-products). Quand les crédits inutilisés sont réinitialisés à chaque renouvellement, l'allocation reste une raison de conserver l'abonnement, et les utilisateurs intensifs achètent des packs de crédits plutôt que d'épuiser un stock accumulé. ::: ## Limitations \{#limitations\} - **L'accès multi-appareils nécessite une identification** : un solde appartient à un seul profil. Un utilisateur anonyme ne conserve son solde que sur l'installation où il l'a gagné ; il est donc perdu en cas de réinstallation ou d'ouverture sur un autre appareil. Identifiez vos utilisateurs pour rendre un solde disponible sur tous les appareils et après chaque réinstallation. Voir [Soldes, profils et appareils](virtual-currency-balance#balances-profiles-and-devices). - **Côté serveur uniquement** : il n'existe pas encore de méthode SDK pour lire ou dépenser un solde, votre application a donc besoin d'un backend. Celui-ci lit les soldes et accorde ou dépense des crédits via l'API côté serveur. - **Jusqu'à 20 devises par application** : vous pouvez créer jusqu'à 20 monnaies virtuelles dans une seule application. --- # File: virtual-currency-quickstart --- --- title: "Démarrage rapide avec la monnaie virtuelle" description: "Configurez une monnaie virtuelle de bout en bout : créez une devise en tokens, accordez des tokens avec un abonnement et dépensez-les via l'API côté serveur." --- :::link Article principal : [Monnaies virtuelles](virtual-currencies) ::: Ce guide de démarrage rapide configure une devise en tokens de bout en bout : un abonnement accorde 1 000 tokens par mois aux utilisateurs, et les actions payantes dans votre app coûtent des tokens. Adapty gère chaque solde, votre backend n'a qu'à les lire et les dépenser. 1. Suivez le guide [Créer une monnaie virtuelle](create-virtual-currency) pour créer une devise `TOKENS`. Liez-la à votre abonnement Pro et définissez **Credit per cycle** à 1 000. Pour vendre des tokens supplémentaires, liez également des produits de packs de tokens en achat unique. 2. Appelez [List virtual currency balances](api-adapty/operations/listVirtualCurrencyBalances) pour lire le solde de l'utilisateur, par exemple avant de lancer une génération : ```bash title="Read balances" curl https://api.adapty.io/api/v2/server-side-api/vc/balances/ \ -H "Authorization: Api-Key {your secret key}" \ -H "adapty-customer-user-id: user-42" ``` La réponse liste toutes les devises de l'utilisateur, par exemple 1 000 `TOKENS` : ```json title="Response" { "data": [ { "code": "TOKENS", "name": "Tokens", "balance": 1000, "held": 0, "available": 1000 } ] } ``` 3. Quand l'utilisateur lance une génération, dépensez les tokens en appelant [Create virtual currency transaction](api-adapty/operations/createVirtualCurrencyTransaction) avec un `amount` négatif. Dans cet exemple, une génération d'image coûte 100 tokens : ```bash title="Spend tokens" curl -X POST https://api.adapty.io/api/v2/server-side-api/vc/transactions/ \ -H "Authorization: Api-Key {your secret key}" \ -H "adapty-customer-user-id: user-42" \ -H "Content-Type: application/json" \ -d '{"items": [{"currency_code": "TOKENS", "amount": -100}]}' ``` La transaction est atomique et retourne le solde mis à jour. Si l'utilisateur ne peut pas couvrir le coût, la requête renvoie `insufficient_balance` et rien ne change. Incluez un en-tête `Idempotency-Key` pour relancer les requêtes en toute sécurité. 4. Pour lancer une offre de reconquête, accordez des tokens via le même endpoint avec un `amount` positif. Les crédits accordés de cette façon n'expirent jamais. 5. Consultez chaque modification dans le [profil](virtual-currency-balance) de l'utilisateur ou dans l'[historique des transactions](api-adapty/operations/listVirtualCurrencyTransactions) pour auditer l'économie à tout moment. --- # File: create-virtual-currency --- --- title: "Créer une devise virtuelle" description: "Créez une devise virtuelle dans Adapty, associez-la à des produits pour que les achats accordent des crédits, et définissez si ces crédits expirent." --- :::link Article principal : [Devises virtuelles](virtual-currencies) ::: Pour vendre des crédits en devise virtuelle, définissez une devise virtuelle une seule fois, puis associez-la à vos produits. Cela se fait en deux étapes — toutes deux décrites dans cet article. Une fois qu'un produit est associé, chaque achat ou renouvellement accorde des crédits automatiquement. ## Créer une devise virtuelle \{#create-a-virtual-currency\} Dans l'Adapty Dashboard, ouvrez **Products** > [**Virtual currency**](https://app.adapty.io/virtual-currency). Pour créer une devise virtuelle : 1. Cliquez sur **New virtual currency**. Le panneau s'ouvre à l'étape **General**. 2. Renseignez les détails de la devise : - **Code** : L'identifiant unique et **permanent** de la devise dans votre application, par exemple `COINS`. Il identifie la devise dans l'API côté serveur et suit le solde de chaque utilisateur. Utilisez des lettres latines, des chiffres et des underscores, jusqu'à 32 caractères. Les lettres minuscules sont automatiquement converties en majuscules. - **Name** : Le nom d'affichage, par exemple `Gold`. Vous pouvez le modifier ultérieurement. - **Description** : Une note facultative sur la devise. 3. Cliquez sur **Continue** pour passer à l'étape **Link Products**. :::important Vous ne pouvez pas modifier le **Code** de la devise après sa création. Vous pouvez toutefois modifier le **Name** après coup. ::: Lorsque vous introduisez une nouvelle devise, le solde de départ de chaque profil utilisateur est 0. ## Associer des produits \{#link-products\} Associez un produit à une devise virtuelle afin qu'un achat ou un renouvellement accorde des crédits dans cette devise. Vous pouvez associer un produit à plusieurs devises, et une devise à plusieurs produits. Vous pouvez associer des produits maintenant, lors de l'étape **Link Products**, ou les ajouter plus tard en modifiant la devise. Durant l'étape **Link Products**, la section **Associated products** liste les produits qui accordent cette devise. Pour en ajouter un, cliquez sur **Add associated products**, puis choisissez un produit. Chaque attribution s'ajoute au solde de l'utilisateur plutôt que de le remplacer, ce qui permet aux crédits de différents produits de s'accumuler. Les paramètres de crédit dépendent du type de produit : - **Les produits d'abonnement** ont trois paramètres de crédit : - **Credit per cycle** (requis) : Les crédits accordés à chaque renouvellement, y compris le renouvellement qui convertit un essai en abonnement payant. - **Credit on trial start** (optionnel) : Un montant distinct accordé une seule fois au début d'un essai gratuit. - **Credits expire at the end of each billing cycle** (bouton bascule) : Lorsqu'il est activé, Adapty remet les crédits non utilisés à 0 à chaque renouvellement, avant d'accorder les crédits du nouveau cycle. Lorsqu'il est désactivé, les crédits s'accumulent d'un cycle à l'autre et n'expirent jamais. - **Produits à achat unique** : Définissez le **Credit amount**, soit le nombre de crédits accordés par achat. Les crédits issus d'achats uniques n'expirent jamais. Cliquez sur **Save** pour créer la devise avec ses associations de produits. Les associations de produits ne s'appliquent qu'aux événements futurs. Un produit nouvellement associé accorde des crédits à partir de son prochain achat ou renouvellement. Adapty n'attribue pas automatiquement la devise aux abonnés actuels — ils doivent d'abord renouveler leur abonnement. Lorsque vous supprimez une association, les attributions futures cessent, mais les crédits déjà accordés sont conservés. Lorsque le bouton d'expiration est activé, les crédits à expiration suivent le cycle de vie de l'abonnement : - Pendant la nouvelle tentative de facturation ou le délai de grâce, Adapty n'accorde aucun nouveau crédit. - Après une annulation, les crédits restent jusqu'à la fin de la période payante. - Lorsque l'abonnement expire, Adapty remet les crédits restants à 0. ## Étapes suivantes \{#next-steps\} Une fois la devise créée et les produits associés, les achats accordent des crédits automatiquement. À partir de là : - Suivez le solde de chaque utilisateur sur la page [Virtual currency balance](virtual-currency-balance). - Accordez, dépensez et consultez les soldes en temps réel via l'API côté serveur : [Create virtual currency transaction](api-adapty/operations/createVirtualCurrencyTransaction) et [List virtual currency balances](api-adapty/operations/listVirtualCurrencyBalances). Pour un exemple concret, suivez le [Virtual currency quickstart](virtual-currency-quickstart). --- # File: virtual-currency-balance --- --- title: "Solde de devise virtuelle" description: "Consultez les soldes de devises virtuelles d'un utilisateur sur son profil et examinez chaque changement de solde dans l'historique des événements." --- :::link Article principal : [Devises virtuelles](virtual-currencies) ::: Chaque profil utilisateur dans [Profiles/CRM](profiles-crm) affiche le solde de devises virtuelles de cet utilisateur, ainsi qu'un historique de chaque modification. ## Consulter les soldes dans un profil utilisateur \{#view-balances-in-a-user-profile\} Ouvrez le [profil](https://app.adapty.io/profiles/users) de l'utilisateur. La carte **Virtual currency** liste toutes les devises que l'utilisateur possède. Chaque ligne affiche : - Le **code** de la devise, par exemple `COINS`. - Le **solde** actuel, sous forme de nombre entier. Les soldes se mettent à jour au fur et à mesure que l'utilisateur gagne, dépense ou reçoit des crédits. Un solde ne peut pas descendre en dessous de 0 : une transaction qui tente de dépenser plus que ce que l'utilisateur possède échoue avec `insufficient_balance` et ne modifie rien. Un profil sans solde affiche une carte vide. Pour lire un solde depuis votre propre code, appelez [List virtual currency balances](api-adapty/operations/listVirtualCurrencyBalances) dans l'API côté serveur. ## Consulter l'historique des modifications de solde \{#review-balance-changes-in-the-event-history\} Chaque modification de solde apparaît dans l'historique des événements du profil, du plus récent au plus ancien. Chaque entrée indique la nature du changement et liste les devises concernées. L'historique affiche trois types d'événements liés aux devises virtuelles : - **Virtual currency credited** : un achat, un renouvellement ou le début d'un essai a crédité des points. - **Virtual currency transaction** : un appel API côté serveur a crédité ou débité le solde. - **Virtual currency expired** : des crédits avec expiration ont été réinitialisés à la fin d'un cycle de facturation ou à l'expiration de l'abonnement. Chaque entrée liste, pour chaque devise modifiée : - **Monnaie virtuelle** : Le nom et le code de la monnaie, par exemple `Gold Coins (COINS)`. - **Montant** : La variation signée — positive pour un crédit, négative pour un débit. - **Solde après** : Le solde de la monnaie une fois la modification appliquée. Un événement peut modifier plusieurs monnaies à la fois — par exemple, une seule [transaction](api-adapty/operations/createVirtualCurrencyTransaction) qui débite une monnaie et en crédite une autre pour les convertir. ## Soldes, profils et appareils \{#balances-profiles-and-devices\} Un solde appartient toujours à un seul [profil](profiles-crm) et ne peut jamais être transféré vers un autre. Adapty ne partage pas les soldes entre profils, contrairement aux [niveaux d'accès qui peuvent être partagés entre comptes utilisateurs](profiles-crm#sharing-paid-access-between-user-accounts). En pratique, cela signifie que : - **Utilisateurs identifiés** : Un identifiant utilisateur personnalisé renvoie toujours au même profil, donc l'utilisateur voit le même solde sur chaque appareil où il se connecte, et le conserve après avoir réinstallé votre application. - **Utilisateurs anonymes** : Un profil anonyme peut accumuler et dépenser des crédits, mais il est lié à une seule installation de l'application sur un seul appareil. Lorsque le même utilisateur réinstalle votre application, ou l'ouvre sur un autre appareil sans se connecter, Adapty crée un nouveau profil anonyme avec un solde nul. Les crédits restent sur l'ancien profil, auquel l'utilisateur ne peut plus accéder. Pour gérer une économie de monnaie virtuelle entre les appareils et après les réinstallations, identifiez vos utilisateurs. Vous pouvez les identifier dans le code de l'application via le SDK (voir [Identifier les utilisateurs](ios-quickstart-identify) dans le guide de démarrage rapide) ou depuis votre backend via l'[API côté serveur](getting-started-with-server-side-api). L'identification tardive d'un utilisateur a son propre inconvénient : si un utilisateur accumule des crédits de façon anonyme puis se connecte avec un identifiant utilisateur qui appartient déjà à un autre profil, l'appareil bascule vers ce profil et son solde. Les crédits accumulés anonymement restent sur l'ancien profil et deviennent inaccessibles. Si l'identifiant utilisateur est nouveau, il est associé au profil actuel et l'utilisateur conserve son solde. Pour plus de sécurité, identifiez les utilisateurs avant qu'ils puissent gagner ou acheter des crédits. Dans les appels à l'[API côté serveur](getting-started-with-server-side-api), identifiez le profil avec l'en-tête `adapty-profile-id` ou `adapty-customer-user-id` — les deux renvoient à un seul et même profil. Pour les profils anonymes, utilisez `adapty-profile-id`. --- # File: offers --- --- title: "Offres" description: "Configurez et gérez les offres d'abonnement dans Adapty pour améliorer vos conversions." --- Les offres dans l'App Store et Google Play Store sont des promotions spéciales, des essais gratuits ou des remises pour les achats intégrés. Elles permettent d'attirer de nouveaux utilisateurs, de réengager les abonnés perdus et d'augmenter les conversions. ## Activer les offres dans votre application \{#enable-offers-in-your-app\} Pour traiter les offres, Adapty nécessite la configuration suivante : 1. Créer des offres dans le store : - [App Store](app-store-offers) - [Google Play](google-play-offers) 2. Pour l'App Store : [importez votre clé d'achat intégré depuis App Store Connect vers Adapty](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers). 3. [Ajoutez les offres dans Adapty et affichez-les dans un flow ou un paywall](create-offer). :::note Les offres de lancement sur iOS sont appliquées automatiquement si l'utilisateur est éligible. Ne les ajoutez pas dans Adapty. ::: --- # File: offers-in-stores --- --- title: "Ajouter des essais et offres promo dans les stores" description: "Configurez les offres App Store et Google Play pour améliorer la monétisation et la rétention de votre application." --- Pour commencer, vous devez configurer les offres dans le store. Consultez les guides correspondant à votre plateforme : - [App Store](app-store-offers) - [Google Play](google-play-offers) --- # File: app-store-offers --- --- title: "Offres dans l'App Store" description: "Configurez et gérez les offres de l'App Store pour améliorer la rétention des utilisateurs." --- :::info Configurez vos [produits store](quickstart-products) avant de suivre ce guide. ::: Les offres de l'App Store sont des promotions, essais ou remises spéciaux pour les abonnements à renouvellement automatique. Elles incluent des remises et des offres groupées qui permettent d'attirer de nouveaux utilisateurs et d'augmenter la conversion. Il existe quatre types d'offres dans l'App Store, et Adapty les prend tous en charge : - **[Offres de lancement](#introductory-offers) pour les nouveaux utilisateurs** : - Périodes d'abonnement gratuites ou à tarif réduit - Seuls les nouveaux utilisateurs sont éligibles (ceux qui n'ont jamais activé une offre de lancement ni souscrit à un abonnement) - Vous n'avez pas besoin de les associer aux produits dans Adapty. Adapty applique les offres automatiquement pour les utilisateurs éligibles qui achètent le produit. - **Offres [promotionnelles](#promotional-offers) et [de reconquête](#win-back-offers)** : - Adapty applique ces offres automatiquement au moment de l'achat, mais vous devez d'abord configurer les offres dans vos produits et paywalls. - Les offres promotionnelles incluent des périodes d'abonnement gratuites, des remises en pourcentage et des remises à prix fixe. N'importe quel utilisateur peut être éligible. - Les offres de reconquête incluent des périodes d'abonnement gratuites ou des remises en pourcentage. Seuls les utilisateurs ayant résilié sont éligibles. - **Codes d'offre** : Pour plus d'informations, consultez [Utiliser des codes d'offre sur iOS](making-purchases#redeem-offer-codes-in-ios). :::important Pour utiliser les offres de l'App Store, téléchargez votre [clé d'abonnement](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) sur l'Adapty Dashboard. ::: ## Offres de lancement \{#introductory-offers\} Adapty applique automatiquement les offres de lancement sur iOS si l'utilisateur est éligible. Pour activer les offres de lancement sur les produits que vous vendez, il vous suffit de les créer dans App Store Connect : 1. Ouvrez votre application dans App Store Connect et accédez à **Monetization > Subscriptions**. 2. Sélectionnez un groupe d'abonnements et naviguez jusqu'à l'abonnement souhaité. L'abonnement doit avoir une durée configurée. 3. Cliquez sur **View all Subscription Pricing** et passez à l'onglet **Introductory offers**. Cliquez sur **Set up introductory offer**. 4. Sélectionnez les pays et régions où l'offre de lancement sera disponible. 5. Sélectionnez les dates de début et de fin de l'offre de lancement. Si l'offre n'a pas de date de fin précise, sélectionnez **No end date**. Cliquez sur **Next**. 6. Sélectionnez le type d'offre de lancement. Selon votre choix, vous devrez également définir la durée et le prix de l'offre. Pour en savoir plus, consultez la [documentation Apple](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-introductory-offers-for-auto-renewable-subscriptions). 7. Vérifiez votre sélection et cliquez sur **Confirm**. Une fois cette configuration terminée, vous n'avez rien à faire dans Adapty. L'offre s'active pour les utilisateurs éligibles qui achètent le produit. Assurez-vous de n'afficher un paywall avec ce produit qu'aux utilisateurs éligibles à l'offre. ## Offres promotionnelles \{#promotional-offers\} Adapty applique automatiquement les offres promotionnelles si les utilisateurs sont éligibles. Configurez d'abord vos offres dans App Store Connect, puis ajoutez-les à un produit et un paywall dans Adapty : 1. Ouvrez votre application dans App Store Connect et accédez à **Monetization > Subscriptions** depuis le menu de gauche. 2. Sélectionnez un groupe d'abonnements et naviguez jusqu'à l'abonnement souhaité. L'abonnement doit avoir une durée configurée. 3. Cliquez sur **View all Subscription Pricing** et passez à l'onglet **Promotional offers**. Cliquez sur **Set up promotional offer**. 4. Renseignez les détails de l'offre promotionnelle. Ces valeurs ne pourront pas être modifiées après la création et seront réutilisées, choisissez-les donc avec soin. - **Promotional offer reference name** : Le nom de l'offre promotionnelle. Il ne sera pas visible par vos utilisateurs. - **Promotional offer identifier** : Le code d'identification de l'offre promotionnelle. Vous l'utiliserez pour ajouter l'offre dans Adapty. 5. Sélectionnez le type d'offre promotionnelle. Le type détermine si les utilisateurs paient un prix réduit ou bénéficient d'une période gratuite. Pour une remise, sélectionnez **Pay as you go** ou **Pay up front**. Pour une période d'abonnement gratuite, sélectionnez **Free**. Définissez ensuite la durée et le prix de l'offre. Pour en savoir plus, consultez la [documentation Apple](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-promotional-offers-for-auto-renewable-subscriptions). 6. Si nécessaire, définissez des prix différents pour différents pays et régions, puis cliquez sur **Next**. 7. Vérifiez votre choix et cliquez sur **Confirm**. 8. [Ajoutez l'offre promotionnelle](create-offer) dans Adapty. ## Offres de reconquête \{#win-back-offers\} :::important Pour créer une offre de reconquête, votre abonnement doit d'abord être approuvé par l'App Review. ::: Adapty applique automatiquement les offres de reconquête si les utilisateurs sont éligibles. Configurez d'abord vos offres dans App Store Connect, puis ajoutez-les à un produit et un paywall dans Adapty : 1. Ouvrez votre application dans App Store Connect et accédez à **Monetization > Subscriptions** depuis le menu de gauche. 2. Sélectionnez un groupe d'abonnements et naviguez jusqu'à l'abonnement souhaité. L'abonnement doit avoir une durée configurée. 3. Cliquez sur **View all Subscription Pricing** et passez à l'onglet **Win-back offers**. Cliquez sur **Create offer**. 4. Renseignez les détails de l'offre de reconquête. Ces valeurs ne pourront pas être modifiées après la création. - **Reference name** : Le nom de l'offre. Il ne sera pas visible par vos utilisateurs. - **Offer identifier** : Le code d'identification de l'offre. Vous l'utiliserez pour ajouter l'offre dans Adapty. 5. Configurez le type, la durée et le prix de l'offre. Pour en savoir plus, consultez la [documentation Apple](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-win-back-offers). 6. Vérifiez votre choix et cliquez sur **Confirm**. 7. [Ajoutez l'offre](create-offer) dans Adapty. ## Étapes suivantes \{#next-steps\} Une fois vos offres ajoutées, poursuivez la configuration : - Si vous avez également des **applications Google Play**, configurez les [offres Google Play](google-play-offers). - Si vous avez des **offres promotionnelles ou de reconquête**, [ajoutez-les dans Adapty](create-offer). - Si vous n'avez que des **offres de lancement** et aucune offre promotionnelle ou de reconquête, vous êtes prêt. La section [Comment Adapty fonctionne avec les offres](create-offer#how-adapty-works-with-offers) peut néanmoins vous être utile. --- # File: google-play-offers --- --- title: "Offres dans Google Play" description: "Configurez les offres Google Play pour améliorer la monétisation et la rétention de votre application." --- Dans Google Play, les offres de tout type (essais gratuits ou paiements réduits) sont ajoutées sous forme d'**offres**. Pour créer une offre, vous devez d'abord créer un abonnement et ajouter un plan de base à renouvellement automatique. Les offres sont toujours créées pour des plans de base dans des abonnements. Dans la capture d'écran ci-dessous, vous pouvez voir un abonnement `premium_access`(1) avec deux plans de base : `1-month` (2) et `1-year` (3). <img src="/assets/shared/img/c0b1dfa-001930-November-03-XYnbieeu.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour créer une offre dans Google Play Console : 1. Cliquez sur **Add offer** et choisissez le plan de base dans la liste. <img src="/assets/shared/img/75a5d69-eb0bc9a-001931-November-03-eQdthUMx.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Saisissez l'ID de l'offre. Il sera utilisé ultérieurement dans les analyses et sur l'Adapty Dashboard, alors donnez-lui un nom explicite. <img src="/assets/shared/img/ff282c2-c0b1dfa-001930-November-03-XYnbieeu.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Choisissez les critères d'éligibilité : 1. **New customer acquisition** : l'offre sera disponible uniquement pour les nouveaux abonnés n'ayant pas déjà utilisé cette offre. C'est l'option la plus courante et celle à utiliser par défaut. 2. **Upgrade** : cette offre sera disponible pour les clients qui passent d'un autre abonnement. Utilisez-la quand vous souhaitez promouvoir des plans plus chers auprès de vos abonnés existants, par exemple des clients passant du niveau bronze au niveau gold de votre abonnement. 3. **Developer determined** : vous pouvez contrôler depuis le code de l'application qui peut utiliser cette offre. Soyez prudent en production pour éviter toute fraude potentielle : les clients pourraient activer un abonnement gratuit ou réduit à répétition. Un bon cas d'usage pour ce type d'offre est la reconquête des abonnés résiliés. <img src="/assets/shared/img/ee302dc-a506e5a-001934-November-03-TVBLOz2L.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Ajoutez jusqu'à deux phases tarifaires à votre offre. Il existe trois types de phases disponibles : 1. **Free trial** : l'abonnement peut être utilisé gratuitement pendant une durée configurée (minimum 3 jours). C'est l'offre la plus courante. 2. **Single payment** : l'abonnement est moins cher si les clients paient à l'avance. Par exemple, un plan mensuel coûte normalement 9,99 $, mais avec ce type d'offre, les trois premiers mois coûtent 19,99 $, soit une réduction de 30 %. 3. **Discounted recurring payment** : l'abonnement est moins cher pendant les `n` premières périodes. Par exemple, un plan mensuel coûte normalement 9,99 $, mais avec ce type d'offre, chacun des trois premiers mois coûte 4,99 $, soit une réduction de 50 %. Une offre peut comporter deux phases. Dans ce cas, la première phase doit être un Free trial, et la seconde est soit un Single payment, soit un Discounted recurring payment. Elles sont appliquées dans cet ordre. <img src="/assets/shared/img/d6267f3-a48f79e-001936-November-03-A13wutRh.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Veuillez noter que les paywalls créés avec le Paywall Builder d'Adapty n'afficheront que la première phase d'une offre d'abonnement Google à plusieurs phases. Cependant, rassurez-vous : lorsqu'un utilisateur achète le produit, toutes les phases de l'offre seront appliquées telles que configurées dans Google Play. ::: 5. Activez l'offre pour l'utiliser dans l'application. <img src="/assets/shared/img/d3fc09b-f149ba6-001937-November-03-MO9Gz3ap.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Passez à l'[ajout de l'offre dans Adapty](create-offer). :::note Les IDs d'offre peuvent être identiques pour différents plans de base. ::: ## Étapes suivantes \{#next-steps\} Une fois les offres ajoutées, poursuivez la configuration : - Si vous avez **des applications sur l'App Store également**, consultez le [guide App Store](app-store-offers). - Si vous avez **des applications uniquement sur Google Play**, suivez [ce guide](create-offer) pour ajouter des offres dans Adapty. --- # File: create-offer --- --- title: "Ajouter des offres à Adapty" description: "Créez et gérez des offres d'abonnement spéciales avec les outils d'Adapty." --- Adapty vous permet de proposer des essais ou des réductions aux nouveaux abonnés, aux abonnés existants ou aux abonnés perdus. Une fois que vous les avez configurées dans App Store Connect ou Google Play Console, vous devez les ajouter à Adapty en deux étapes : 1. [Ajoutez des offres aux produits dans Adapty en utilisant les identifiants d'offre issus des stores.](#1-add-offer-to-product-in-adapty) 2. [Affichez l'offre dans un flow ou un paywall.](#2-display-offer) :::warning Les offres de lancement (App Store) sont appliquées automatiquement si l'utilisateur est éligible. Ne les ajoutez pas aux produits dans Adapty. Ce guide explique comment configurer les offres promotionnelles (App Store), les offres de reconquête (App Store) et toutes les offres Google Play. ::: ## 0. Avant de commencer \{#before-you-start\} Avant de configurer des offres dans Adapty, assurez-vous que : 1. Vous avez créé toutes les offres dont vous avez besoin dans le store : - [App Store](app-store-offers) - [Google Play](google-play-offers) 2. Vous avez créé les [produits](create-product) dans Adapty et ajouté leurs identifiants. 3. Pour l'App Store : Vous avez importé [la clé d'achat intégré pour les offres promotionnelles](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers). ## 1. Ajouter une offre à un produit dans Adapty \{#1-add-offer-to-product-in-adapty\} Une fois votre offre promotionnelle (pour le Play Store et l'App Store) ou votre offre de reconquête (pour l'App Store) configurée dans les stores, l'ajouter à Adapty est simple : 1. Ouvrez [**Products**](https://app.adapty.io/products) depuis le menu principal d'Adapty. Trouvez le produit auquel vous souhaitez ajouter une offre. 2. Trouvez le produit auquel vous souhaitez ajouter une offre. Dans la colonne **Actions**, cliquez sur le bouton **3-dot** à côté du produit et sélectionnez **Edit**. 3. Dans la fenêtre **Edit product**, cliquez sur **+** et sélectionnez **Add offers**. 4. Cliquez sur **Add offer**. 5. Renseignez ensuite les détails de l'offre pour le produit. Voici les champs disponibles pour l'offre : - **Offer name** : Donnez un nom à l'offre pour l'identifier facilement dans Adapty. Utilisez le nom qui vous convient. - **App Store Offer type** : Sélectionnez le type d'offre App Store que vous ajoutez : Promotional ou Win-back. (Les offres de lancement n'ont pas besoin d'être ajoutées — elles s'appliquent automatiquement si elles sont disponibles.) - **App Store Offer ID** : C'est l'identifiant unique de l'offre [que vous avez défini dans l'App Store](app-store-products). - **Play Store Offer ID** : De même, c'est l'identifiant unique de l'offre [que vous avez défini dans le Play Store](android-products). :::tip Si le champ **App Store Offer ID** ou **Play Store Offer ID** n'est pas actif, passez à l'onglet **Products** et sélectionnez un ID de produit. ::: 6. (optionnel) Ajoutez d'autres offres si nécessaire en cliquant sur **Add offer**. 7. Cliquez sur **Save** pour ajouter les offres au produit. ## 2. Afficher l'offre \{#2-display-offer\} Une fois une offre associée à un produit, présentez-la là où les utilisateurs voient ce produit — dans un flow ou dans un paywall. ### Ajouter une offre à un flow \{#add-offer-to-flow\} Dans le [Flow Builder](adapty-flow-builder), une offre est associée à un produit dans un élément Produits. Commencez par ajouter l'élément produit et assignez-lui des produits — voir [Configurer les achats](paywall-product-block). Pour associer une offre : 1. Sur le canvas, sélectionnez la carte produit qui doit afficher l'offre. 2. Dans le panneau de droite, sous **Product**, sélectionnez le produit, puis choisissez l'offre dans le menu déroulant **Select offer (optional)**. ### Ajouter une offre à un paywall \{#add-offer-to-paywall\} :::info Vous ne pouvez pas ajouter d'offres à des paywalls en statut **live**. Si vous souhaitez ajouter une offre à un paywall existant, [dupliquez-le](duplicate-paywalls) et configurez les produits dans un nouveau paywall. ::: Pour rendre une offre visible et sélectionnable dans un [paywall](paywalls) pour les utilisateurs de votre application, suivez ces étapes : 1. Lors de la création ou de la modification d'un paywall, dans l'onglet **General**, ajoutez un produit auquel vous venez d'ajouter l'offre. 2. Choisissez une offre que vous avez créée précédemment pour ce produit dans la liste **Offer**. La liste n'est disponible que pour les produits qui ont des offres. 3. Si nécessaire, ajoutez d'autres produits et offres, mais vous ne pouvez ajouter qu'une seule offre par produit. ## Fonctionnement d'Adapty avec les offres \{#how-adapty-works-with-offers\} Voici comment les offres fonctionnent dans Adapty : - Lorsqu'un utilisateur est éligible à une offre, Adapty applique automatiquement l'offre que vous avez configurée au moment de l'achat. - Si un produit dispose à la fois d'une offre de lancement et d'offres promotionnelles configurées dans l'App Store, les utilisateurs éligibles recevront d'abord l'offre de lancement. Une fois sa période terminée, si l'utilisateur est toujours éligible à l'offre promotionnelle et que vous avez configuré cette offre dans Adapty, elle sera appliquée lorsqu'il tentera d'acheter à nouveau le produit. - Si vous souhaitez contrôler davantage la façon dont les offres sont appliquées, ou si vous devez vendre votre produit sans offres dans certains cas, vous disposez de plusieurs options : - Configurer les critères d'éligibilité dans l'App Store ou la Google Play Console - Créer un produit séparé sans offres dans l'App Store ou la Google Play Console - Créer un produit séparé sans offres dans Adapty, ajouter des paywalls contenant les deux variantes du produit à un [placement](placements), et utiliser des [segments](segments) d'audience pour contrôler quel paywall est affiché à chaque utilisateur. Par exemple, vous pouvez créer des segments basés sur le **Subscription product** ou le **Paid access level**, ou utiliser des [attributs personnalisés](profiles-crm) pour implémenter votre propre logique. --- # File: access-level --- --- title: "Niveaux d'accès" description: "Découvrez les niveaux d'accès dans Adapty et comment les configurer pour la gestion des utilisateurs." --- Les niveaux d'accès vous permettent de contrôler ce que les utilisateurs peuvent faire dans votre application mobile sans avoir à coder en dur des identifiants de produits spécifiques. Chaque produit définit la durée pendant laquelle l'utilisateur bénéficie d'un certain niveau d'accès. Ainsi, chaque fois qu'un utilisateur effectue un achat, Adapty accorde l'accès à l'application pour une période spécifique (pour les abonnements) ou de façon permanente (pour les achats à vie). Lorsque vous créez une application dans l'Adapty Dashboard, le niveau d'accès `premium` est automatiquement généré. Il s'agit du niveau d'accès par défaut, qui ne peut pas être supprimé. Vous pouvez avoir plusieurs niveaux d'accès par application. Voici quelques exemples illustrant leur utilité : - Dans une application de presse où vous vendez des abonnements à différents sujets indépendamment, vous pouvez créer des niveaux d'accès tels que `sports` et `science`. - Dans une application de fitness proposant des vidéos d'entraînement enregistrées via un abonnement classique (utilisant le niveau d'accès `premium` par défaut), les utilisateurs peuvent opter pour une formule plus coûteuse donnant accès à des séances en direct avec un coach. Dans ce cas, vous pouvez créer un niveau `live_coach_access`. - Dans une application d'apprentissage des langues, vous pouvez choisir de créer un niveau d'accès pour chaque langue disponible. :::note Les niveaux d'accès peuvent être partagés ou transférés entre les profils d'un utilisateur ; le solde d'une monnaie virtuelle ne le peut pas — il reste lié à un seul profil. Voir [Soldes, profils et appareils](virtual-currency-balance#balances-profiles-and-devices). ::: Pour commencer à travailler avec les niveaux d'accès dans Adapty, accédez à **[Products](https://app.adapty.io/access-levels)** depuis le menu principal d'Adapty, puis sélectionnez l'onglet **Access levels**. La liste **Access levels** affiche tous les niveaux d'accès, y compris celui `premium` ajouté automatiquement et ceux que vous avez ajoutés dans Adapty. <img src="/assets/shared/img/access-level-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: create-access-level --- --- title: "Créer un niveau d'accès" description: "Créez et assignez des niveaux d'accès dans Adapty pour une meilleure segmentation des utilisateurs." --- Les niveaux d'accès vous permettent de contrôler ce que les utilisateurs de votre application peuvent faire sans coder en dur des identifiants de produits spécifiques. Chaque produit définit la durée pendant laquelle l'utilisateur bénéficie d'un certain niveau d'accès. Ainsi, chaque fois qu'un utilisateur effectue un achat, Adapty lui accorde l'accès à l'application pour une période spécifique (pour les abonnements) ou indéfiniment (pour les achats à vie). Lorsque vous créez une application dans l'Adapty Dashboard, le niveau d'accès `premium` est automatiquement généré. Il s'agit du niveau d'accès par défaut, qui ne peut pas être supprimé. :::tip Vous pouvez également créer des niveaux d'accès par programmation via le [Developer CLI](developer-cli-reference#adapty-access-levels-create). ::: Pour créer un nouveau niveau d'accès : 1. Accédez à **[Products](https://app.adapty.io/access-levels)** depuis le menu principal d'Adapty, puis sélectionnez l'onglet **Access levels**. <img src="/assets/shared/img/access-level-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur **Create access level**. <img src="/assets/shared/img/b8646ca-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Create access level**, attribuez-lui un identifiant. Cet identifiant servira de référence dans votre application mobile, permettant l'accès aux fonctionnalités supplémentaires lors d'un achat. Il permet également de distinguer un niveau d'accès des autres au sein de l'application. Assurez-vous qu'il est clair et facile à comprendre. 4. Cliquez sur **Create access level** pour confirmer la création du niveau d'accès. --- # File: assigning-access-level-to-a-product --- --- title: "Associer un niveau d'accès à un produit" description: "Associez des niveaux d'accès aux produits pour optimiser la gestion des abonnements." --- Chaque [produit](product) doit être associé à un niveau d'accès pour que les utilisateurs reçoivent le contenu correspondant après leur achat. Adapty détermine automatiquement la durée de l'abonnement, qui sert ensuite de date d'expiration pour le niveau d'accès. Dans le cas d'un produit à accès à vie, si un client l'achète, le niveau d'accès reste actif indéfiniment, sans date d'expiration. Pour associer un niveau d'accès à un produit : 1. Lors de la [configuration d'un produit](create-product), sélectionnez le niveau d'accès dans la liste **Access Level ID**. <img src="/assets/shared/img/access-level-product.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur **Save**. --- # File: give-access-level-to-specific-customer --- --- title: "Accorder un niveau d'accès à un client spécifique" description: "Attribuez des niveaux d'accès spécifiques aux clients grâce aux outils avancés d'Adapty." --- Vous pouvez ajuster manuellement le niveau d'accès d'un client directement depuis l'Adapty Dashboard. C'est particulièrement utile dans les scénarios de support. Par exemple, si vous souhaitez prolonger l'utilisation premium d'un utilisateur d'une semaine supplémentaire pour le remercier d'avoir laissé un avis fantastique. ## Accorder un niveau d'accès à un client spécifique depuis l'Adapty Dashboard \{#give-access-level-to-a-specific-customer-in-the-adapty-dashboard\} 1. Accédez à **[Profiles and Segments](https://app.adapty.io/placements)** depuis le menu principal d'Adapty. <img src="/assets/shared/img/profiles-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le client auquel vous souhaitez accorder l'accès. 3. Cliquez sur **Add access level**. <img src="/assets/shared/img/add-access-level.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Sélectionnez le niveau d'accès à accorder et la date à laquelle il doit expirer pour ce client. 5. Cliquez sur **Apply**. ## Accorder un niveau d'accès à un client spécifique via l'API \{#give-access-level-to-a-specific-customer-via-api\} Vous avez également la possibilité d'accorder un niveau d'accès à un client depuis votre serveur via l'API Adapty. C'est pratique si vous proposez des bonus pour les parrainages ou d'autres événements liés à vos produits. Retrouvez plus de détails sur la page [Accorder un niveau d'accès via l'API côté serveur](api-adapty/operations/grantAccessLevel). --- # File: local-access-levels --- --- title: "Niveaux d'accès locaux" description: "Gérez les niveaux d'accès en cas de pannes temporaires." --- :::important Notez les points suivants : - Les niveaux d'accès locaux sont pris en charge dans le SDK Adapty à partir de la version 3.12. - Par défaut, les niveaux d'accès locaux sont désactivés sur Android pour des raisons de sécurité supplémentaire. Si vous en avez besoin, activez-les lors de l'activation du SDK : [Android](sdk-installation-android#enable-local-access-levels), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#enable-local-access-levels-android). ::: Chaque produit que vous configurez est associé à un [**niveau d'accès**](access-level). Lorsque vos utilisateurs effectuent un achat, le SDK Adapty attribue le niveau d'accès au [profil](profiles-crm) de l'utilisateur. Vous devez donc utiliser ce niveau d'accès pour déterminer si les utilisateurs peuvent accéder au contenu payant dans l'application. Le SDK Adapty est très fiable, et il est très rare que ses serveurs soient indisponibles. Cependant, même dans ce cas exceptionnel, vos utilisateurs ne s'en apercevront pas. Si un utilisateur effectue un achat mais qu'Adapty ne peut pas recevoir de réponse, le SDK bascule vers la vérification des achats directement dans le store. Le niveau d'accès est donc accordé localement dans l'application, sans aucune configuration supplémentaire. Le SDK gère cela automatiquement en arrière-plan, et les utilisateurs accèdent à ce pour quoi ils ont payé, exactement comme d'habitude. Voici comment fonctionnent les niveaux d'accès locaux : - Lorsque les utilisateurs sont à nouveau en ligne, les informations de transaction sont automatiquement transmises aux serveurs Adapty, qui appliquent alors les transactions au profil utilisateur et renvoient le profil mis à jour au SDK. - Les données mises à jour n'apparaissent pas dans les analyses Adapty tant qu'elles n'ont pas été transmises. - Les niveaux d'accès locaux ne fonctionnent que lorsque les serveurs Adapty sont hors service. Sinon, le SDK utilise les données en cache disponibles. - Les niveaux d'accès locaux ne fonctionnent pas pour les produits consommables, sauf lorsqu'un produit consommable se voit attribuer un type d'abonnement (mensuel, annuel, hebdomadaire, etc.) dans le tableau de bord Adapty. --- # File: placements --- --- title: "Placements" description: "Gérez les placements dans Adapty pour optimiser la visibilité des flows et paywalls et augmenter les revenus." --- Avec le système de placements d'Adapty, vous pouvez créer et exécuter des [flows](adapty-flow-builder), des [paywalls](paywalls), des [onboardings](onboardings) et des [tests A/B](ab-tests) à différents moments du parcours utilisateur dans votre application, comme le flow d'onboarding, les paramètres de l'application, etc. Ces points sont appelés **Placements**. Un placement dans votre application peut gérer plusieurs flows, paywalls, onboardings ou tests A/B simultanément, chacun destiné à un groupe d'utilisateurs spécifique, que nous appelons [Audiences](audience). Vous pouvez également expérimenter avec des flows, des paywalls et des onboardings en les remplaçant les uns par les autres au fil du temps, sans publier de nouvelle version de l'application. La seule chose que vous codez en dur dans l'application mobile est l'identifiant du placement. ## Liste des placements \{#placements-list\} Il existe trois types de placements : - **Placements de flows** - **Placements de paywalls** - **Placements d'onboardings** Pour afficher tous vos placements, accédez à **Placements** depuis le menu principal d'Adapty. Vous les verrez classés dans les onglets **Paywalls**, **Onboardings** et **Flows**. Chaque onglet offre une vue d'ensemble des différents emplacements du parcours utilisateur où des flows, paywalls, onboardings ou tests A/B peuvent apparaître. Chaque élément de la liste correspond à un placement spécifique, ce qui facilite la gestion et la modification. Vous pouvez modifier les détails d'un placement, l'associer au flow, paywall, onboarding ou test A/B souhaité pour une audience donnée, ou supprimer les placements inutiles. Les chiffres dans le tableau reflètent les analyses des placements depuis leur activation. <img src="/assets/shared/img/placements-list.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Depuis cette page, vous pouvez : - [Créer un nouveau placement](create-placement) - [Modifier un placement existant](edit-placement) - [Supprimer un placement existant](delete-placement) - Télécharger les [flows](fallback-flows), [paywalls](fallback-paywalls) ou onboardings de secours locaux. Ces fichiers sont utilisés lorsqu'un utilisateur ouvre l'application sans connexion au backend Adapty (pas de connexion internet, ou dans le cas rare où le backend est indisponible) et qu'il n'y a pas de cache sur l'appareil. Le même téléchargement **Fallbacks** couvre à la fois les flows et les paywalls — la version du SDK que vous sélectionnez dans la boîte de dialogue de téléchargement détermine si le bundle inclut des flows (SDK 4.0+) ou uniquement des paywalls. --- # File: choose-meaningful-placements --- --- title: "Choisir des placements pertinents" description: "Optimisez les placements de flows et de paywalls avec Adapty pour améliorer l'engagement des utilisateurs et les revenus." --- Lorsque vous [créez des placements](create-placement), il est essentiel de réfléchir au parcours logique de votre application et à l'expérience utilisateur que vous souhaitez offrir. La plupart des applications devraient avoir au maximum 5 [placements](placements) sans pour autant sacrifier la capacité à mener des expériences. Voici un exemple de structure possible pour vos placements : <img src="/assets/shared/img/placement-flows.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. **Flow d'onboarding :** Cette étape représente la première interaction de vos utilisateurs avec votre application. C'est une excellente occasion de leur présenter la proposition de valeur de votre app en combinant ici des placements de flow, d'onboarding et de paywall. Plus de 80 % des abonnements sont activés pendant le parcours d'onboarding, il est donc primordial de mettre en avant les abonnements les plus rentables à cette étape. Avec Adapty, vous pouvez facilement proposer différents [flows](adapty-flow-builder), [onboardings](onboardings) et [paywalls](paywalls) selon les audiences, et lancer des tests A/B pour trouver la meilleure option pour votre application. Par exemple, vous pouvez lancer un test A/B pour les utilisateurs américains en leur affichant des abonnements plus coûteux 50 % du temps. 2. **Paramètres de l'application :** Si l'utilisateur ne s'est pas abonné pendant l'onboarding, vous pouvez créer un placement de flow ou de paywall au sein de l'application. Cela peut se faire dans les paramètres de l'app ou après qu'un utilisateur a accompli une action cible spécifique. Les utilisateurs déjà dans l'app ayant tendance à réfléchir davantage avant de s'abonner, les produits proposés ici peuvent être légèrement moins chers qu'à l'étape d'onboarding. 3. **Promo :** Si l'utilisateur ne s'est toujours pas abonné après avoir vu le flow ou le paywall à plusieurs reprises, cela peut indiquer que les prix sont trop élevés pour lui ou qu'il hésite à s'engager. Dans ce cas, vous pouvez lui proposer une offre spéciale avec l'abonnement le plus abordable, voire un produit à accès à vie. Cela peut convaincre les utilisateurs sensibles aux prix ou sceptiques vis-à-vis des abonnements de passer à l'achat. La plupart des applications suivront une logique et des placements similaires, en accompagnant le parcours utilisateur aux étapes clés où des flows, paywalls, onboardings ou tests A/B peuvent être affichés pour stimuler les conversions et les revenus. Vous pouvez les configurer dans chaque placement afin d'expérimenter et d'optimiser vos stratégies de monétisation. --- # File: create-placement --- --- title: "Créer un placement" description: "Créez et gérez des placements dans Adapty pour améliorer les performances des flows et des paywalls." --- Un [placement](placements) est un endroit précis dans votre application mobile où vous pouvez afficher un flow, un paywall, un onboarding ou un test A/B. Par exemple, un choix d'abonnement peut apparaître dans un flow de démarrage, tandis qu'un produit consommable (comme des pièces d'or) pourrait s'afficher quand un utilisateur manque de pièces dans un jeu. Vous pouvez afficher les mêmes flows, paywalls, onboardings ou tests A/B — ou des versions différentes — dans divers placements ou pour différents segments d'utilisateurs, appelés « audiences » dans Adapty. Consultez la section [Choisir des placements pertinents](choose-meaningful-placements) pour des conseils sur le choix du bon placement. :::tip Vous pouvez également créer des placements par programmation via le [Developer CLI](developer-cli-reference#adapty-placements-create). ::: :::info Bien que la création d'un placement soit similaire pour les flows, les paywalls et les onboardings, il n'est pas possible de créer un seul placement qui serve plusieurs types à la fois — chaque type de placement traite des métriques différentes. ::: ## Créer et configurer un placement \{#create-and-configure-a-placement\} 1. Accédez à **[Placements](https://app.adapty.io/placements)** depuis le menu principal d'Adapty. Passez à l'onglet **Flows**, **Paywalls** ou **Onboardings** selon le type de placement que vous souhaitez créer. 2. Cliquez sur **Create placement**. <img src="/assets/shared/img/create-placement-2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Saisissez un **Placement name**. Il s'agit d'un identifiant interne dans l'Adapty Dashboard. Vous pouvez le modifier ultérieurement si nécessaire. 4. Saisissez un **Placement ID**. Vous utiliserez cet identifiant dans le SDK Adapty pour appeler les [flows](adapty-flow-builder), [paywalls](paywalls), [onboardings](onboardings) et [tests A/B](ab-tests) du placement. Vous ne pourrez pas le modifier par la suite, car il est unique pour chaque placement. Assignez ensuite un flow, un paywall, un onboarding ou un test A/B au placement. Adapty prend en charge les [audiences](audience) — des segments d'utilisateurs basés sur des [segments](segments) — afin d'afficher des contenus différents à différents groupes d'utilisateurs. Si vous n'avez pas besoin de ciblage, l'audience par défaut *All users* couvre tout le monde. :::note Pour continuer, assurez-vous d'avoir créé un flow, un paywall, un onboarding ou un test A/B à exécuter, ainsi qu'une audience à spécifier. ::: 1. Dans la fenêtre **Placements/ Your placement**, ajoutez un flow, un paywall, un onboarding ou un test A/B à afficher pour l'audience par défaut *All users*. Pour ce faire, cliquez sur le bouton **Run flow**, **Run paywall** ou **Run A/B test** (l'intitulé dépend du type de placement), puis sélectionnez le flow, le paywall, l'onboarding ou le test A/B souhaité dans la liste déroulante. 2. Si vous souhaitez utiliser plusieurs audiences dans le placement pour créer un contenu personnalisé adapté à différents groupes d'utilisateurs, cliquez sur le bouton **Add audience** et choisissez le segment d'utilisateurs souhaité dans la liste. <Zoom> <img src="/docs/img/placement-add-audience.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ajoutez maintenant le flow, le paywall, l'onboarding ou le test A/B à afficher pour cette audience. 4. Ajoutez autant d'audiences que nécessaire. 5. Si vous avez plusieurs audiences, vérifiez qu'elles disposent des bonnes priorités. 6. Cliquez sur le bouton **Save and publish button**. Une fois votre placement enregistré et publié, vous avez tout ce qu'il vous faut — utilisez le **Placement ID** dans le code de votre application pour le récupérer et l'afficher. ## Étapes suivantes \{#next-steps\} Afficher les paywalls dans votre application : [iOS](ios-present-paywalls) | [Android](android-present-paywalls) | [React Native](react-native-present-paywalls) | [Flutter](flutter-present-paywalls) | [Unity](unity-present-paywalls) | [Kotlin Multiplatform](kmp-present-paywalls) | [Capacitor](capacitor-present-paywalls) Afficher les onboardings dans votre application : [iOS](ios-present-onboardings) | [Android](android-present-onboardings) | [React Native](react-native-present-onboardings) | [Flutter](flutter-present-onboardings) | [Unity](unity-present-onboardings) | [Kotlin Multiplatform](kmp-present-onboardings) | [Capacitor](capacitor-present-onboardings) --- # File: edit-placement --- --- title: "Modifier un placement" description: "Découvrez comment modifier les placements dans Adapty pour optimiser la visibilité des flows, paywalls et onboardings et améliorer l'engagement des utilisateurs." --- Un [placement](placements) désigne un emplacement précis dans votre application mobile où un flow, un paywall, un onboarding ou un test A/B peut être affiché. Par exemple, un choix d'abonnement peut apparaître dans un flow de démarrage, tandis qu'un produit consommable (comme des pièces d'or) peut être présenté lorsqu'un utilisateur n'a plus de pièces dans un jeu. Vous avez la possibilité d'afficher les mêmes flows, paywalls, onboardings ou tests A/B sur plusieurs placements ou segments d'utilisateurs, appelés audiences dans Adapty. Pour modifier un placement existant : 1. Accédez à **[Placements](https://app.adapty.io/placements)** depuis le menu principal d'Adapty. Passez à l'onglet **Flows**, **Paywalls** ou **Onboardings** selon le type de placement que vous souhaitez modifier. 2. Cliquez sur le placement à modifier. 3. Cliquez sur **Edit placement** en haut à droite. 4. Effectuez les modifications souhaitées. Pour plus de détails sur les options disponibles dans cette fenêtre, consultez la section [Créer un placement](create-placement). 5. Cliquez sur le bouton **Save and publish** pour confirmer les modifications. --- # File: export-placements --- --- title: "Exporter un placement" description: "Découvrez comment exporter des placements dans Adapty pour optimiser la visibilité des flows et des paywalls ainsi que l'engagement des utilisateurs." --- Lorsque vous travaillez avec plusieurs flows, paywalls et onboardings, il est important de suivre lesquels sont affichés à quels utilisateurs. Vous pouvez exporter tous vos paramètres de [placement](placements) dans un fichier CSV pour voir quel flow/paywall/onboarding apparaît pour chaque audience et vérifier votre configuration après avoir effectué des modifications ou lancé des expériences. :::tip Si vous le préférez, vous pouvez [exporter les placements via l'API server-side](api-export-analytics/operations/retrievePlacementInfo). ::: Pour exporter des placements de flows, de paywalls ou d'onboardings : 1. Accédez à **[Placements](https://app.adapty.io/placements)** dans le menu principal. Passez à l'onglet **Flows**, **Paywalls** ou **Onboardings** — les placements de chaque type sont exportés séparément. 2. Cliquez sur **Export to CSV**. <img src="/assets/shared/img/export-placement.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Le fichier CSV exporté contient les informations suivantes sur vos placements : - ID du placement - Nom du placement - Nom de l'audience - Nom du segment - Nom du test A/B cross-placement - Nom du test A/B - Nom du flow, nom du paywall ou nom de l'onboarding (selon l'onglet depuis lequel vous avez exporté) :::note Les tests A/B cross-placement ne sont pas pris en charge pour les placements de flows, donc cette colonne sera vide dans les exports de flows. ::: --- # File: delete-placement --- --- title: "Supprimer un placement" description: "Découvrez comment supprimer un placement dans Adapty sans affecter les performances de votre flow ou de votre paywall." --- Un [placement](placements) désigne un emplacement précis dans votre application mobile où un flow, un paywall, un onboarding ou un test A/B peut être affiché. :::danger Même si vous pouvez supprimer n'importe quel placement, il est essentiel de vous assurer que vous ne supprimez pas un placement activement utilisé dans votre application mobile. Supprimer un placement de flow ou de paywall actif entraînera l'affichage permanent d'un paywall de secours local si vous en avez [configuré un](fallback-paywalls), et vous ne pourrez plus jamais le remplacer par un flow ou un paywall dynamique dans les versions déjà publiées de l'application. ::: Pour supprimer un placement existant : 1. Accédez à **[Placements](https://app.adapty.io/placements)** depuis le menu principal d'Adapty. Basculez vers l'onglet **Flows**, **Paywalls** ou **Onboardings** selon le type de placement que vous souhaitez supprimer. 2. Cliquez sur le bouton **3 points** à côté du placement et sélectionnez l'option **Delete**. <img src="/assets/shared/img/delete-placement.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Delete placement** qui s'ouvre, saisissez le nom du produit que vous êtes sur le point de supprimer. <img src="/assets/shared/img/8177c51-delete_placement.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur le bouton **Delete forever** pour confirmer la suppression. --- # File: audience --- --- title: "Audiences" description: "Apprenez à segmenter et gérer les audiences dans Adapty pour des offres d'abonnement ciblées." --- Les **audiences** dans Adapty sont des groupes d'utilisateurs basés sur des [segments](segments), vous permettant de personnaliser les flows, paywalls, onboardings ou tests A/B pour des groupes d'utilisateurs spécifiques. Vous pouvez définir ces segments à l'aide de filtres pour vous assurer que les bons utilisateurs voient le bon flow, paywall ou onboarding dans votre application. Dans Adapty, un **placement** est l'endroit où vous pouvez afficher des flows, paywalls, onboardings ou tests A/B. Lorsque vous ajoutez une audience à un placement, vous ciblez des groupes d'utilisateurs spécifiques avec du contenu personnalisé. Par exemple, vous pouvez afficher différents flows ou paywalls selon l'âge, l'appareil ou le statut d'abonnement d'un utilisateur. Si un utilisateur appartient à plusieurs groupes, vous pouvez choisir quel groupe est prioritaire et décider ainsi quel contenu il verra. Dans l'exemple ci-dessous, nous avons un flow d'onboarding à afficher dans votre placement avec l'identifiant `Onboarding`. Dans le code de votre application, vous accéderez au placement en utilisant cet identifiant. Si l'utilisateur appartient à l'audience « Yoga beginners », il verra le premier paywall. Ceux qui n'appartiennent pas à l'audience « Yoga beginners » verront le second paywall. <img src="/assets/shared/img/6bf7797-1_1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour afficher un flow, un paywall, un onboarding ou un test A/B à une audience spécifique, procédez comme suit : 1. [Créez un segment d'utilisateurs](segments#creation). Vous pouvez ignorer cette étape si vous souhaitez afficher le flow, le paywall ou le test A/B à tous les utilisateurs. Dans ce cas, utilisez l'audience « All users » créée par défaut. 2. [Ajoutez ce segment comme audience à un placement et définissez quel flow, paywall ou test A/B doit lui être affiché](add-audience-paywall-ab-test). L'audience « All users » est automatiquement ajoutée à chaque placement ; vous n'avez qu'à préciser quel flow, paywall ou test A/B doit être affiché. 3. [Définissez les bonnes priorités](change-audience-priority) si vous avez plus d'une audience dans un placement. Cela garantit que les utilisateurs appartenant à plusieurs audiences verront le contenu le plus pertinent. Lorsqu'un utilisateur fait partie de plusieurs audiences, le contenu de l'audience ayant la priorité la plus haute sera affiché. 4. <InlineTooltip tooltip="Afficher le flow ou le paywall associé à ce placement dans le code de l'application mobile">[iOS](ios-quickstart-paywalls), [Android](android-quickstart-paywalls), [React Native](react-native-quickstart-paywalls), [Flutter](flutter-quickstart-paywalls) et [Unity](unity-quickstart-paywalls)</InlineTooltip>. --- # File: add-audience-paywall-ab-test --- --- title: "Ajouter une audience et un flow, paywall ou test A/B à un placement" description: "Exécutez des tests A/B sur des flows et des paywalls pour différents segments d'audience dans Adapty." --- Les **audiences** dans Adapty sont des groupes d'utilisateurs définis par des [segments](segments). Elles vous permettent d'afficher des flows, des paywalls, des onboardings et des tests A/B aux utilisateurs concernés. Créez des segments avec des filtres pour vous assurer que chaque groupe reçoit le bon contenu. Lorsque vous ajoutez une audience à un [placement](placements), vous ciblez des flows, des paywalls, des onboardings ou des tests A/B vers un groupe d'utilisateurs spécifique. Associer une audience à un placement garantit que les bons utilisateurs voient le bon contenu au bon moment dans leur parcours applicatif. Ouvrez le placement où vous souhaitez ajouter un flow, un paywall, un onboarding ou un test A/B, ou créez-en un nouveau dans le menu [Placements](https://app.adapty.io/placements). :::note Pour continuer, assurez-vous d'avoir créé un flow, un paywall, un onboarding ou un test A/B à exécuter, ainsi qu'une audience à spécifier. ::: 1. Dans la fenêtre **Placements/ Your placement**, ajoutez un flow, un paywall, un onboarding ou un test A/B à afficher pour l'audience par défaut *All users*. Pour ce faire, cliquez sur le bouton **Run flow**, **Run paywall** ou **Run A/B test** (l'intitulé dépend du type de placement), puis sélectionnez le flow, le paywall, l'onboarding ou le test A/B souhaité dans la liste déroulante. 2. Si vous souhaitez utiliser plusieurs audiences dans le placement pour créer un contenu personnalisé adapté à différents groupes d'utilisateurs, cliquez sur le bouton **Add audience** et choisissez le segment d'utilisateurs souhaité dans la liste. <Zoom> <img src="/docs/img/placement-add-audience.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ajoutez maintenant le flow, le paywall, l'onboarding ou le test A/B à afficher pour cette audience. 4. Ajoutez autant d'audiences que nécessaire. 5. Si vous avez plusieurs audiences, vérifiez qu'elles disposent des bonnes priorités. 6. Cliquez sur le bouton **Save and publish button**. --- # File: change-audience-priority --- --- title: "Modifier la priorité des audiences dans un placement" description: "Ajustez les priorités des audiences dans Adapty pour cibler les utilisateurs avec des offres personnalisées." --- Lorsque vous avez différentes audiences dans un [placement](placements), un utilisateur peut appartenir à plusieurs audiences à la fois. Par exemple, si vous avez défini des audiences comme « Débutants », « Coureurs » et une audience générale comme « Tous les utilisateurs », il est essentiel de déterminer quelle audience prendre en compte en premier lorsqu'un utilisateur entre dans plusieurs catégories. <img src="/assets/shared/img/afee54f-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans ce cas, on s'appuie sur la priorité des audiences. La priorité des audiences est un ordre numérique où #1 est la plus haute. Elle définit l'ordre dans lequel les audiences sont évaluées. En termes simples, la priorité des audiences aide Adapty à décider quelle audience appliquer en premier pour sélectionner le paywall, l'onboarding ou le test A/B à afficher. Si la priorité d'une audience est faible, les utilisateurs qui y sont éligibles pourraient être ignorés et redirigés vers une autre audience de priorité plus élevée. Les audiences interplacements, c'est-à-dire celles créées pour les [tests A/B interplacements](ab-tests#ab-test-types), ont toujours la priorité sur les audiences classiques. L'audience « Tous les utilisateurs » a toujours la priorité la plus basse, car c'est une audience de secours qui inclut tous ceux qui ne correspondent à aucune autre audience. Pour ajuster les priorités des audiences d'un placement : 1. Lors de la création ou de la modification d'un placement, cliquez sur **Edit priority**. Ce bouton n'est visible que si au moins trois audiences sont ajoutées au placement (« Tous les utilisateurs » et deux autres). Si vous en avez moins, l'ordre est évident — l'audience « Tous les utilisateurs » vient en dernier. <img src="/assets/shared/img/edit-priority.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la fenêtre **Edit audience priorities** qui s'ouvre, faites glisser-déposer les audiences pour les réorganiser dans le bon ordre. <img src="/assets/shared/img/reorder_audiences.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur le bouton **Save**. --- # File: placement-metrics --- --- title: "Métriques de placement" description: "Analysez les métriques de placement dans Adapty pour améliorer les performances de vos paywalls." --- Avec Adapty, vous pouvez créer et gérer plusieurs placements dans votre application, chacun associé à des paywalls ou des tests A/B distincts. Cette flexibilité vous permet de cibler des segments d'utilisateurs spécifiques, d'expérimenter différentes offres ou modèles de tarification, et d'optimiser la stratégie de monétisation de votre application. Pour recueillir des informations précieuses sur les performances de vos placements et l'engagement des utilisateurs avec vos offres, Adapty suit diverses interactions utilisateur et transactions liées aux paywalls affichés. Ce système d'analyse robuste capture des métriques telles que les vues, les vues uniques, les achats, les essais, les remboursements, les taux de conversion et les revenus. Les métriques collectées sont mises à jour en temps réel et sont accessibles et analysables via le tableau de bord convivial d'Adapty. Vous pouvez personnaliser la plage de temps pour l'analyse, appliquer des filtres selon différents paramètres et comparer les métriques entre différents placements, segments d'utilisateurs ou produits. Les métriques de placement sont disponibles dans la liste des placements, où vous pouvez obtenir une vue d'ensemble des performances de tous vos placements. Cette vue de haut niveau fournit des métriques agrégées pour chaque placement, vous permettant de comparer leurs performances et d'identifier des tendances. Pour une analyse plus détaillée de chaque placement, vous pouvez accéder aux métriques de détail du placement. Sur cette page, vous trouverez des métriques complètes spécifiques au placement sélectionné. Ces métriques offrent des informations plus approfondies sur les performances d'un placement particulier, vous permettant d'évaluer son efficacité et de prendre des décisions basées sur les données. <img src="/assets/shared/img/3e711fc-CleanShot_2023-07-26_at_14.55.042x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Filtrer les métriques par date d'installation \{#filter-metrics-by-install-date\} Les métriques de paywall, d'essai et d'achat peuvent être regroupées selon deux dates différentes : - **La date de l'événement** — quand le paywall a été consulté, l'essai commencé ou l'achat effectué. - **La date d'installation** — quand l'utilisateur a ouvert l'application pour la première fois. Les deux vues peuvent afficher des chiffres très différents pour la même plage de dates. La case **Filter metrics by install date** contrôle laquelle le tableau de bord utilise : - **Décochée (par défaut)** : les métriques sont regroupées par date d'événement. - **Cochée** : les métriques sont regroupées par date d'installation. **Exemple.** Vous définissez la plage de dates du 1er au 30 avril et vous regardez les essais. - **Décochée** : affiche les essais qui ont *démarré* en avril, quelle que soit la date d'installation de ces utilisateurs. - **Cochée** : affiche les essais des utilisateurs qui se sont *installés* en avril, quelle que soit la date de début de leur essai. Utilisez la vue par date d'installation pour mesurer les performances d'acquisition d'utilisateurs pour une cohorte spécifique. Utilisez la vue par date d'événement pour mesurer l'activité d'un paywall ou d'un onboarding sur une période donnée. ### Contrôles des métriques \{#metrics-controls\} Le système affiche les métriques en fonction de la période sélectionnée et les organise selon le paramètre de la colonne de gauche avec quatre niveaux d'indentation. #### Options d'affichage pour les données de métriques \{#view-options-for-metrics-data\} La page des métriques de placement propose deux options d'affichage : par paywall et par audience. <img src="/assets/shared/img/9d26b32-Export-1690376094858.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans la vue par paywall, les métriques sont regroupées par placements associés au paywall. Cela permet aux utilisateurs d'analyser les métriques selon différents placements. Dans la vue par audience, les métriques sont regroupées par audience cible du paywall. Les utilisateurs peuvent évaluer les métriques spécifiques à différents segments d'audience. #### Plages de temps \{#time-ranges\} Vous pouvez choisir parmi plusieurs périodes pour analyser les données de métriques, ce qui vous permet de vous concentrer sur des durées spécifiques comme des jours, des semaines, des mois ou des plages de dates personnalisées. <img src="/assets/shared/img/15d2c3e-CleanShot_2023-07-26_at_16.49.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: Adapty propose des outils puissants pour filtrer et personnaliser l'analyse des métriques selon vos besoins. La page des métriques vous donne accès à différentes plages de temps, options de regroupement et possibilités de filtrage. - ✅ Filtrer par : audience, paywall, groupe de paywalls, placement, pays, store. - ✅ Regrouper par : segment, store et produit #### Graphique de métrique unique \{#single-metrics-chart\} L'un des éléments clés de la page des métriques de placement est la section graphique, qui représente visuellement les métriques sélectionnées et facilite l'analyse. La section graphique de la page des métriques de placement comprend un graphique à barres horizontales qui représente visuellement les valeurs des métriques choisies. Chaque barre correspond à une valeur de métrique et est proportionnelle en taille, ce qui facilite la compréhension des données d'un coup d'œil. La ligne horizontale indique la période analysée, et la colonne verticale affiche les valeurs numériques des métriques. La valeur totale de toutes les métriques est affichée à côté du graphique. <img src="/assets/shared/img/4623c5b-Export-1690375597411.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> De plus, cliquer sur l'icône de flèche dans le coin supérieur droit de la section graphique développe la vue et affiche les métriques sélectionnées sur toute la ligne du graphique. #### Récapitulatif total des métriques \{#total-metrics-summary\} À côté du graphique de métrique unique, le récapitulatif total des métriques affiche les valeurs cumulées pour les métriques sélectionnées à un moment précis, avec la possibilité de changer la métrique affichée via un menu déroulant. <img src="/assets/shared/img/0f647cf-CleanShot_2023-07-26_at_14.55.492x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Définitions des métriques \{#metrics-definitions\} Exploitez toute la puissance des métriques de placement grâce à ces définitions complètes. Des revenus aux taux de conversion, obtenez des informations précieuses qui boosteront vos stratégies de monétisation et contribueront au succès de votre application. <img src="/assets/shared/img/771a0f0-Export-1690375049771.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: #### Revenus \{#revenue\} Cette métrique représente le montant total d'argent généré en USD à partir des achats et des renouvellements au sein de placements spécifiques. Notez que le calcul des revenus n'inclut pas la commission de l'App Store Apple ou du Google Play Store et est calculé avant déduction des frais. #### Produits nets \{#proceeds\} Cette métrique représente le montant réel reçu par le propriétaire de l'application en USD à partir des achats et des renouvellements au sein de placements spécifiques, après déduction de la commission applicable de l'App Store Apple ou du Google Play Store. Elle reflète le revenu net qui contribue directement aux gains de l'application. Pour plus d'informations sur le calcul des produits nets, consultez la [documentation](analytics-cohorts#revenue-vs-proceeds) Adapty. #### ARPPU \{#arppu\} ARPPU signifie « revenu moyen par utilisateur payant » et mesure le revenu moyen généré par utilisateur payant au sein de placements spécifiques. Il est calculé en divisant le revenu total par le nombre d'utilisateurs payants uniques. Par exemple, si le revenu total est de 15 000 $ et qu'il y a 1 000 utilisateurs payants, l'ARPPU est de 15 $. #### ARPAS \{#arpas\} L'ARPAS, ou revenu moyen par abonné actif, mesure le revenu moyen généré par abonné actif au sein de placements spécifiques. Il est calculé en divisant le revenu total par le nombre d'abonnés ayant activé un essai ou un abonnement. Par exemple, si le revenu total est de 5 000 $ et qu'il y a 1 000 abonnés, l'ARPAS est de 5 $. Cette métrique permet d'évaluer le potentiel de monétisation moyen par abonné. #### ARPU \{#arpu\} Pour les placements d'onboarding uniquement. L'ARPU est le revenu moyen par utilisateur ayant visionné l'onboarding. Il est calculé en divisant le revenu total par le nombre de spectateurs uniques. #### Taux de conversion unique vers les achats \{#unique-cr-to-purchases\} Le taux de conversion unique vers les achats est calculé en divisant le nombre d'achats au sein de placements spécifiques par le nombre de vues uniques. Il se concentre sur le ratio achats/vues uniques, fournissant des informations sur l'efficacité à convertir les visiteurs uniques en clients payants au sein de placements spécifiques. #### Taux de conversion vers les achats \{#cr-to-purchases\} Le taux de conversion vers les achats est calculé en divisant le nombre d'achats au sein de placements spécifiques par le nombre total de vues des paywalls. Il indique le pourcentage de vues au sein de placements spécifiques qui se traduisent par des achats, fournissant des informations sur l'efficacité de votre paywall à convertir les utilisateurs en clients payants. #### Taux de conversion unique vers les essais \{#unique-cr-to-trials\} Le taux de conversion unique vers les essais est calculé en divisant le nombre d'essais démarrés au sein de placements spécifiques par le nombre de vues uniques. Il mesure le pourcentage de vues uniques au sein de placements spécifiques qui se traduisent par des activations d'essai, fournissant des informations sur l'efficacité de votre paywall à convertir les visiteurs uniques en utilisateurs d'essai. #### Achats \{#purchases\} Les achats représentent le total cumulé de diverses transactions effectuées sur le paywall au sein de placements spécifiques. Les transactions suivantes sont incluses dans cette métrique (les renouvellements ne sont pas inclus) : - Les nouveaux achats effectués directement au sein de placements spécifiques. - Les conversions d'essais initialement activés au sein de placements spécifiques. - Les déclassements, mises à niveau et changements de niveau d'abonnements effectués au sein de placements spécifiques. - Les restaurations d'abonnements au sein de placements spécifiques, par exemple lorsqu'un abonnement est réactivé après expiration sans renouvellement automatique. En tenant compte de ces différents types de transactions, la métrique des achats offre une vue complète de l'activité globale d'acquisition et de monétisation au sein de placements spécifiques. #### Essais \{#trials\} La métrique des essais représente le nombre total d'essais activés au sein de placements spécifiques. Elle reflète le nombre d'utilisateurs ayant lancé des périodes d'essai via votre paywall dans ces placements. Cette métrique permet de suivre l'efficacité de votre offre d'essai et peut fournir des informations sur l'engagement des utilisateurs et la conversion des essais en abonnements payants. #### Essais annulés \{#trials-canceled\} La métrique des essais annulés représente le nombre d'essais au sein de placements spécifiques pour lesquels le renouvellement automatique a été désactivé. Cela se produit lorsque les utilisateurs se désinscrivent manuellement de l'essai, indiquant leur décision de ne pas poursuivre l'abonnement après la période d'essai. Le suivi des essais annulés fournit des informations précieuses sur le comportement des utilisateurs et vous permet de comprendre le taux auquel les utilisateurs optent pour quitter l'essai au sein de placements spécifiques. #### Remboursements \{#refunds\} La métrique des remboursements représente le nombre d'achats et d'abonnements remboursés au sein de placements spécifiques. Cela inclut les transactions qui ont été annulées ou remboursées pour diverses raisons, telles que les demandes des clients, les problèmes de paiement ou toute autre politique de remboursement applicable. #### Taux de remboursement \{#refund-rate\} Le taux de remboursement est calculé en divisant le nombre de remboursements au sein de placements spécifiques par le nombre de premiers achats (les renouvellements ne sont pas inclus). Par exemple, s'il y a 5 remboursements et 1 000 premiers achats, le taux de remboursement est de 0,5 %. #### Vues \{#views\} La métrique des vues représente le nombre total de fois que le paywall au sein de placements spécifiques a été consulté par des utilisateurs. Chaque fois qu'un utilisateur visite le paywall dans ces placements, cela est compté comme une vue distincte. Le suivi des vues vous aide à comprendre le niveau d'engagement et l'interaction des utilisateurs avec votre paywall, fournissant des informations sur le comportement des utilisateurs et l'efficacité du positionnement et de la conception de votre paywall dans des zones spécifiques de votre application. #### Vues uniques \{#unique-views\} La métrique des vues uniques représente le nombre d'instances uniques dans lesquelles le paywall au sein de placements spécifiques a été consulté par des utilisateurs. Contrairement aux vues totales, qui comptent chaque visite comme une vue distincte, les vues uniques ne comptent qu'une seule fois la visite de chaque utilisateur au paywall dans ces placements, quel que soit le nombre de fois où il y accède. Le suivi des vues uniques fournit une mesure plus précise de l'engagement des utilisateurs et de la portée de votre paywall au sein de placements spécifiques, car il se concentre sur les utilisateurs individuels plutôt que sur le nombre total de visites. #### Complétions et complétions uniques \{#completions--unique-completions\} Pour les placements d'onboarding uniquement. Les complétions comptabilisent le nombre de fois où les utilisateurs terminent votre placement d'onboarding, c'est-à-dire qu'ils passent du premier au dernier écran. Si quelqu'un le termine deux fois, cela compte comme deux **complétions** mais une seule **complétion unique**. #### Taux de complétions uniques \{#unique-completions-rate\} Pour les placements d'onboarding uniquement. Le nombre de complétions uniques divisé par le nombre de vues uniques. Cette métrique vous aide à comprendre comment les utilisateurs interagissent avec le placement d'onboarding et à apporter des modifications si vous constatez qu'ils l'ignorent. --- # File: paywalls --- --- title: "Paywalls" description: "Explorez le système de paywalls d'Adapty et les bonnes pratiques pour augmenter vos revenus." --- <CustomDocCardList ids={['create-paywall', 'paywall-metrics']} /> Dans Adapty, un **paywall** est un ensemble de produits configuré à distance que vous vendez dans votre application. Gérer les produits via un paywall vous permet de suivre les performances de différents ensembles de produits auprès de différents groupes d'utilisateurs et de contrôler la manière dont chaque produit est affiché. Vous affichez un paywall dans le code de votre propre application. Adapty propose deux fonctionnalités pour vous y aider : - **Remote config** : [Gérez les éléments du paywall](customize-paywall-with-remote-config) comme le texte et les médias dynamiquement depuis le tableau de bord, sans redéployer votre application. - **Méthodes d'achat du SDK** : Au lieu d'intégrer vous-même les API du store, utilisez une seule méthode du SDK Adapty qui gère la logique d'achat — voir <InlineTooltip tooltip="Déléguer la gestion des achats à Adapty">[iOS](making-purchases), [Android](android-making-purchases), [React Native](react-native-making-purchases), [Flutter](flutter-making-purchases) et [Unity](unity-making-purchases)</InlineTooltip>. <CustomDocCardList ids={['fallback-paywalls', 'paywall-localization', 'customize-paywall-with-remote-config', 'web-paywall']} /> --- # File: create-paywall --- --- title: "Créer un paywall" description: "Découvrez comment créer des paywalls à fort taux de conversion avec le Paywall Builder d'Adapty." --- Un [paywall](paywalls) est une configuration Adapty qui définit quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits dans votre application. Vous avez besoin d'un paywall quelle que soit la façon dont vous l'affichez : - [**Paywall Builder**](adapty-paywall-builder) : Concevez un écran dans l'éditeur no-code. Adapty l'affiche et gère les achats. - **Paywall personnalisé** : Implémentez votre propre interface et utilisez la configuration du paywall pour récupérer les produits. Une fois créé, assignez le paywall à un [placement](placements) — les placements contrôlent quel paywall les utilisateurs voient. Les produits d'un paywall en production sont fixes, donc ses métriques reflètent toujours la même combinaison, ce qui vous permet de comparer les performances entre différents produits et ensembles de prix. :::tip Vous pouvez également créer des paywalls par programmation en utilisant le [CLI développeur](developer-cli-reference#adapty-paywalls-create). ::: <details> <summary>Avant de commencer à créer des paywalls (cliquer pour développer)</summary> 1. [Créez au moins un produit](create-product). 2. (optionnel) [Créez une offre](create-offer). </details> ## Créer un paywall \{#create-paywall\} Pour créer un nouveau paywall dans Adapty Dashboard : 1. Accédez à [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. Cette page affiche une vue d'ensemble de tous vos paywalls et leurs métriques. 2. Cliquez sur **Create paywall**. 3. Sur la page **Paywalls / New paywall**, saisissez un **Paywall name** pour identifier ce paywall dans tout l'Adapty Dashboard. 4. Cliquez sur **Add product**. 5. Sélectionnez les produits à présenter à vos clients. :::note - L'ordre des produits dans cette liste sera conservé dans le SDK, arrangez donc les produits dans l'ordre souhaité. - Une fois qu'un paywall est affiché en production, vous ne pourrez plus modifier ses produits, car cela pourrait affecter les métriques du paywall. ::: 6. Si vous proposez des essais gratuits ou d'autres offres pour vos produits, ajoutez-les ici, sinon ils ne seront pas disponibles. Choisissez une offre que vous avez [créée précédemment](create-offer) pour ce produit dans la liste **Offer**. La liste n'est disponible que pour les produits qui ont des offres. 7. Cliquez sur **Create as a draft** pour confirmer la création du paywall. Votre paywall est maintenant créé ! <img src="/assets/shared/img/create-paywall.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '900px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étapes suivantes \{#next-steps\} Après avoir créé votre premier paywall : 1. Ajoutez-le à un [placement](placements). Les identifiants de placement seront les seules entités codées en dur. Vous les utiliserez pour récupérer les produits à vendre. 2. La façon dont vous travaillez ensuite avec le paywall dépend de votre implémentation : - Si vous souhaitez utiliser le [Adapty Paywall Builder](adapty-paywall-builder), concevez le paywall dans l'éditeur no-code. Adapty affichera le paywall et gérera la logique d'achat, tandis que vous n'aurez qu'à afficher le paywall dans le code de l'application. - Si vous avez un paywall personnalisé que vous souhaitez utiliser, consultez nos guides pour implémenter des achats intégrés avec Adapty pour votre plateforme : - [iOS](ios-implement-paywalls-manually) - [Android](android-implement-paywalls-manually) - [React Native](react-native-implement-paywalls-manually) - [Flutter](flutter-implement-paywalls-manually) - [Unity](unity-implement-paywalls-manually) - [Kotlin Multiplatform](kmp-implement-paywalls-manually) --- # File: customize-paywall-with-remote-config --- --- title: "Concevoir un paywall avec Remote Config" description: "Personnalisez votre paywall avec Remote Config dans Adapty pour un meilleur ciblage." --- :::important Ce guide porte sur Remote Config pour les paywalls classiques. Pour le Flow Builder, consultez [Personnaliser un flow avec Remote Config](customize-flow-with-remote-config). ::: Le Remote Config de paywall est un outil puissant qui offre des options de configuration flexibles. Il permet d'utiliser des charges JSON personnalisées pour adapter vos paywalls avec précision. Vous pouvez y définir divers paramètres tels que les titres, les images, les polices, les couleurs, et bien plus encore. <details> <summary>Avant de commencer à personnaliser un paywall (Cliquez pour développer)</summary> 1. [Créer un produit](create-product). 2. [Créer un paywall et y ajouter le produit](create-paywall). </details> Pour commencer à personnaliser un paywall avec Remote Config : 1. Ouvrez la section [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. 2. Cliquez sur le paywall pour l'ouvrir. <img src="/assets/shared/img/remote-config.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Passez à l'onglet **Remote config**. <img src="/assets/shared/img/remote-config-3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Remote Config propose 2 vues : - [Table](customize-paywall-with-remote-config#table-view-of-the-remote-config) - [JSON](customize-paywall-with-remote-config#json-view-of-the-remote-config) Les vues **Table** et **JSON** contiennent les mêmes éléments de configuration. La seule différence est une question de préférence, à ceci près que la vue Table propose un menu contextuel, ce qui peut s'avérer utile pour corriger des erreurs de localisation. Vous pouvez basculer entre les vues en cliquant sur l'onglet **Table** ou **JSON** à tout moment. Quelle que soit la vue choisie pour personnaliser votre paywall, vous pouvez ensuite accéder à ces données depuis le SDK via les propriétés `remoteConfig` ou `remoteConfigString` de `AdaptyPaywall`, et apporter des ajustements à votre paywall. Vous pouvez également mettre à jour les valeurs du Remote Config par programmation via l'[API côté serveur](api-adapty/operations/updatePaywall) afin de modifier dynamiquement les configurations de paywall sans intervention manuelle dans le tableau de bord. Voici quelques exemples d'utilisation d'un Remote Config. <Tabs groupId="current-os" queryString> <TabItem value="Titles" label="Titres" default> ```json showLineNumbers { "screen_title": "Today only: Subscribe, and get 7 days for free!" } # Test titles or others texts ``` </TabItem> <TabItem value="Images" label="Images" default> ```json showLineNumbers { "background_image": "https://adapty.io/media/paywalls/bg1.webp" } # Test images on your paywall ``` </TabItem> <TabItem value="Fonts" label="Polices" default> ```json showLineNumbers { "font_family": "San Francisco", "font_size": 16 } # Test fonts ``` </TabItem> <TabItem value="Color" label="Couleur" default> ```json showLineNumbers { "subscribe_button_color": "purple" } # Test colors of buttons, texts etc. ``` </TabItem> <TabItem value="HTML" label="HTML" default> ```json showLineNumbers { "photo_gallery": "https://adapty.io/media/paywalls/link-to-html-snippet.html" } # Any HTML code that can be displayed on the paywall ``` </TabItem> <TabItem value="Soft/Hard Paywall" label="Soft/Hard Paywall" default> ```json showLineNumbers { "hard_paywall": true } # By setting it to true, you disalow skipping paywall without subscribing # You have to handle this logic in your app ``` </TabItem> <TabItem value="Translations" label="Traductions" default> ```json showLineNumbers { "title": { "en": "Try for free!", "es": "¡Prueba gratis!", "ru": "Попробуй бесплатно!" } } ``` </TabItem> </Tabs> Vous pouvez combiner différentes options et créer les vôtres. Vous pouvez ainsi tester différents titres, textes, images, polices, couleurs, etc. ### Vue JSON du Remote Config \{#json-view-of-the-remote-config\} Dans la vue **JSON** du Remote Config, vous pouvez saisir n'importe quelle donnée au format JSON : <img src="/assets/shared/img/3356ff5-remote_config_JSON.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Vue Table du Remote Config \{#table-view-of-the-remote-config\} Si vous n'avez pas l'habitude de travailler avec du code et que vous devez corriger certaines valeurs du JSON, Adapty propose la vue **Table**. <img src="/assets/shared/img/4c27b2f-remote_config_table.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Il s'agit d'une copie de votre JSON sous forme de tableau, facile à lire et à comprendre. Un code couleur permet de distinguer les différents types de données. Pour ajouter une clé, cliquez sur le bouton **Add row**. Nous vérifions automatiquement la correspondance des valeurs et des types, et affichons une alerte si vos corrections risquent de produire un JSON invalide. <img src="/assets/shared/img/ef682d8-add_raw.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Les options supplémentaires de ligne sont surtout utiles pour les [localisations de paywall](add-remote-config-locale) : <img src="/assets/shared/img/17bcf80-remote_config_table_options.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Il est maintenant temps de [créer un placement](create-placement) et d'y ajouter le paywall. Ensuite, vous pourrez <InlineTooltip tooltip="afficher vos paywalls Remote Config">[iOS](present-remote-config-paywalls), [Android](present-remote-config-paywalls-android), [React Native](present-remote-config-paywalls-react-native), [Flutter](present-remote-config-paywalls-flutter), et [Unity](present-remote-config-paywalls-unity)</InlineTooltip> dans votre application mobile. --- # File: paywall-localization --- --- title: "Localisation" description: "Localisez vos paywalls et onboardings pour plusieurs langues." --- Dans un monde multiculturel, il est essentiel d'adapter votre produit à chaque pays. Vous pouvez le faire grâce aux localisations de paywall. Pour chaque paywall, vous pouvez créer des versions dans différentes langues afin de répondre aux besoins de marchés locaux spécifiques. Selon l'outil que vous utilisez pour concevoir vos flows, l'ajout d'une locale varie : 1. [Ajouter une locale dans l'Adapty Flow Builder](add-paywall-locale-in-adapty-paywall-builder) : si vous créez des flows dans l'Adapty Flow Builder, vous pouvez localiser tous les éléments directement dans le builder, y compris les textes et les médias. Pour contrôler quelle localisation est affichée, passez une locale dans la méthode `getFlow`. 2. [Ajouter une locale dans le Remote Config](add-remote-config-locale) : Adapty peut également vous aider à gérer les localisations du Remote Config sans redéployer l'application. --- # File: add-paywall-locale-in-adapty-paywall-builder --- --- title: "Ajouter une langue dans le Flow Builder" description: "Ajoutez du contenu localisé dans le Flow Builder d'Adapty pour toucher vos utilisateurs dans leur langue." --- Localiser vos flows les rend disponibles en plusieurs langues. Dans le Flow Builder, la localisation est organisée par écran, chacun affichant un pourcentage de complétion pour suivre l'avancement des traductions. :::tip Finalisez la configuration de votre flow dans la langue par défaut avant d'ajouter d'autres langues. ::: ## Ajouter et configurer une localisation \{#add-and-set-up-localization\} 1. Dans le panneau de gauche, cliquez sur Localizations. Puis cliquez sur **Add locale**. Sélectionnez les langues à ajouter. 2. Chaque langue ajoutée apparaît sous forme de colonne dans le tableau de localisation, pré-remplie avec les valeurs de la langue par défaut. 3. Pour vous concentrer uniquement sur ce qui manque, activez le bouton **Missing only** dans le panneau de gauche. Le tableau filtrera alors uniquement les lignes non traduites. ## Définir la langue par défaut \{#set-the-default-locale\} La langue par défaut contient votre contenu source et sert de secours pour toute traduction manquante. Chaque flow démarre avec l'anglais comme langue par défaut et unique. L'icône d'épingle Pin indique la langue par défaut. Vous ne pouvez pas supprimer la langue par défaut, sauf si une autre langue est d'abord définie comme langue par défaut. Pour changer la langue par défaut, ouvrez le menu contextuel Context menu dans l'en-tête de colonne de la langue cible, puis sélectionnez **Set as default**. ## Exporter et importer pour une traduction externe \{#export-and-import-for-external-translation\} Vous pouvez exporter le fichier de localisation pour le partager avec des traducteurs, puis importer les résultats traduits. Dans la barre d'outils supérieure, cliquez sur **Import / Export**. ### Format du fichier exporté \{#export-file-format\} L'export produit un fichier `.tsv` (valeurs séparées par des tabulations) avec une ligne par élément traduisible. Les colonnes sont : | Colonne | Description | |--------|-------------| | `Screen` | L'écran auquel appartient l'élément (ex. : `Welcome`, `Quiz`) | | `Element` | Identifiant d'élément généré automatiquement dans cet écran. Vous pouvez le modifier dans **Interactions** > **Element ID**. | | `Property` | Le type de propriété (ex. : `content`) | | `[default_locale]` | Le code de la langue par défaut (ex. : `en`) | | `[locale]` | Une colonne par langue ajoutée (ex. : `fr`, `es`) | Exemple : ``` Screen Element Property en fr es Welcome title content Turn words into art Transformez les mots en art Welcome subtitle content Create stunning images in seconds with AI Créez des images en quelques secondes Quiz quiz-title content What will you create? ``` :::note Laissez les colonnes de locale vides pour les lignes non traduites — Adapty les traitera comme manquantes. ::: ### Exigences du fichier d'importation \{#import-file-requirements\} - **Format** : `.tsv` (valeurs séparées par des tabulations) - **En-têtes** : doivent inclure `Screen`, `Element`, `Property` et au moins une colonne de langue - **Noms des colonnes de langue** : doivent correspondre aux codes de langue déjà ajoutés au flow. L'importation d'un fichier avec des codes de langue absents du flow génère une erreur. - **Importation partielle** : vous pouvez n'inclure qu'un sous-ensemble de lignes ; les lignes absentes du fichier conservent leurs valeurs actuelles ### Limitations \{#limitations\} - Le processus d'exportation supprime les variables des chaînes de caractères. Si vous réimportez ces données, vous devrez rajouter les variables manuellement. - Le fichier exporté ne contient que des chaînes de caractères — pour localiser les médias, voir [Localiser les images et vidéos](#localize-images-and-videos). ## Traduire manuellement \{#translate-manually\} Vous pouvez aussi saisir des traductions directement dans n'importe quelle cellule du tableau de localisation. Pour gérer une ligne spécifique, ouvrez son menu contextuel Context menu : - **Reset to default** : Rétablit la traduction de la ligne aux valeurs de la langue par défaut. ## Localiser les images et les vidéos \{#localize-images-and-videos\} Les images et les vidéos peuvent être localisées en téléchargeant des fichiers différents pour chaque locale. 1. Activez la locale cible — sous le canevas ou dans le panneau de localisation. 2. Sélectionnez l'élément image / vidéo. 3. Téléchargez le fichier localisé dans le panneau des propriétés. Les éléments média sans fichier localisé afficheront le fichier de la locale par défaut. ## Prévisualiser la localisation \{#preview-the-localization\} Pour vérifier vos traductions, changez la locale active dans le Flow Builder et passez en revue chaque écran. --- # File: add-remote-config-locale --- --- title: "Localiser les paywalls avec le Remote Config" description: "Ajoutez des paramètres régionaux au Remote Config pour personnaliser vos paywalls Adapty." --- Adapter vos paywalls à différentes langues est indispensable dans un monde multiculturel. La localisation vous permet de créer des expériences sur mesure pour les utilisateurs de régions spécifiques. Pour chaque paywall, vous pouvez ajouter des versions dans plusieurs langues, afin que votre produit résonne avec les audiences locales. Si vous n'utilisez pas le Paywall Builder d'Adapty pour concevoir vos paywalls, vous pouvez tout de même localiser vos paywalls personnalisés et gérer les localisations sans redéployer votre application : 1. Vous créez un Remote Config avec des variables dans le tableau de bord Adapty. Les variables peuvent représenter du texte, des médias ou d'autres types de contenu. 2. Vous définissez les valeurs des variables pour chaque langue. 3. Vous gérez les variables dans le code de l'application. 4. Lorsque vous récupérez un paywall avec des produits en envoyant un paramètre régional, vous obtenez les valeurs de variables appropriées. De cette façon, les localisations ne sont pas codées en dur dans le code de l'application, et vous pouvez les ajuster à tout moment. Que ce soit en vue tableau ou en format JSON, vous pouvez facilement modifier les paramètres pour chaque langue. Par exemple, traduire des clés de chaînes, basculer des valeurs booléennes (ex. : `TRUE` pour l'anglais, `FALSE` pour l'italien), ou même remplacer des images de fond. ## Configurer la localisation pour les paywalls avec Remote Config \{#set-up-localization-for-remote-configured-paywalls\} 1. Accédez à la section [**Paywalls**](https://app.adapty.io/paywalls) dans Adapty. 2. Cliquez sur le paywall pour l'ouvrir. 3. Allez dans l'onglet **Remote config**. <img src="/assets/shared/img/switch_to_remote_config.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur **Locales** et sélectionnez les langues que vous souhaitez prendre en charge. Enregistrez vos modifications pour ajouter ces paramètres régionaux au paywall. <img src="/assets/shared/img/add_locale.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez désormais traduire le contenu manuellement, utiliser l'IA, ou exporter le fichier de localisation pour des traducteurs externes. ## Traduire les paywalls avec l'IA \{#translate-paywalls-with-ai\} La traduction par IA est un moyen rapide et efficace de localiser votre paywall. Vous pouvez traduire les valeurs de type **String** et **List**. Par défaut, toutes les lignes sont sélectionnées (surlignées en violet). Les lignes déjà traduites sont marquées en vert et ne seront pas incluses dans la nouvelle traduction par défaut. Les lignes non sélectionnées ou non traduites apparaissent en gris. <img src="/assets/shared/img/localization-table.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/localization-json.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. Sélectionnez les lignes à traduire. Il est conseillé de décocher les lignes contenant des identifiants, des URLs et des variables pour éviter que l'IA ne les traduise. 2. Sélectionnez les langues pour la traduction. <img src="/assets/shared/img/localization-table-language.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **AI Translate** pour appliquer les traductions. Les lignes sélectionnées seront traduites et ajoutées au paywall, avec les lignes traduites marquées en vert. ## Exporter les fichiers de localisation pour traduction externe \{#exporting-localization-files-for-external-translation\} Bien que la localisation par IA soit une tendance de plus en plus répandue, vous préférerez peut-être une méthode plus fiable, comme faire appel à des traducteurs professionnels ou à une agence de traduction reconnue. Dans ce cas, vous pouvez exporter les fichiers de localisation pour les partager avec vos traducteurs, puis importer les résultats traduits dans Adapty. L'export via le bouton **Export** crée des fichiers `.json` individuels pour chaque langue, regroupés dans une seule archive. Si vous n'avez besoin que d'un seul fichier, vous pouvez l'exporter directement depuis le menu propre à la langue. <img src="/assets/shared/img/localization-single-export.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois les fichiers traduits reçus, utilisez le bouton **Import** pour les télécharger tous en même temps ou individuellement. Adapty validera automatiquement les fichiers pour s'assurer qu'ils correspondent au bon format. ### Format du fichier d'import \{#import-file-format\} Pour garantir un import réussi, le fichier d'import doit respecter les exigences suivantes : - **Nom et extension du fichier :** Le nom du fichier doit correspondre au paramètre régional qu'il représente et avoir une extension `.json`. Vous pouvez vérifier et copier le nom du paramètre régional dans Adapty Dashboard. Si le nom n'est pas reconnu, l'import échouera. <img src="/assets/shared/img/locale-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **JSON valide :** Le fichier doit être un JSON valide. Dans le cas contraire, l'import échouera. ## Localisation manuelle \{#manual-localization\} Parfois, vous souhaiterez peut-être ajuster des traductions, ajouter des images différentes pour des paramètres régionaux spécifiques, ou encore modifier directement des configurations Remote Config. 1. Choisissez l'élément à traduire et saisissez une nouvelle valeur. Vous pouvez mettre à jour les valeurs de type **String** et **List** ou remplacer des images par d'autres mieux adaptées au paramètre régional. <img src="/assets/shared/img/032b429-remote_config_localization.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Utilisez le menu contextuel du paramètre régional anglais pour résoudre efficacement les problèmes de localisation : - **Copy this value to all locales** : Écrase toutes les modifications effectuées dans les paramètres régionaux non-anglais pour la ligne sélectionnée, en les remplaçant par la valeur du paramètre régional anglais. - **Revert all row changes to original values** : Abandonne toutes les modifications effectuées au cours de la session en cours et restaure les valeurs à leur dernier état enregistré. <img src="/assets/shared/img/d7e70f1-remote_confi_loc_table_options.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Après avoir ajouté des paramètres régionaux à un paywall, veillez à implémenter correctement les codes de paramètres régionaux dans le code de votre application. Consultez <InlineTooltip tooltip="les guides sur l'utilisation des localisations et des codes de paramètres régionaux dans votre application">[iOS](localizations-and-locale-codes), [Android](android-localizations-and-locale-codes)</InlineTooltip> --- # File: web-paywall --- --- title: "Paywall web" description: "Configurez un paywall web pour être payé sans les frais et audits de l'App Store." --- :::important Avant de commencer, assurez-vous d'avoir la version requise du SDK installée : - **Paywall Builder ou paywalls personnalisés** : 3.6.1 ou ultérieur (iOS), 3.15 ou ultérieur (Android et multiplateforme) - **Flow Builder** : 4.0 ou ultérieur (toutes les plateformes) ::: Avec Adapty, vous pouvez créer un paywall ou un [flow](adapty-paywall-builder) avec un bouton qui redirige vos utilisateurs vers leur navigateur pour effectuer un paiement. Lorsqu'ils reviennent dans votre application après un achat réussi, l'abonnement s'active. Cela vous permet de contourner les frais du store tout en suivant les paiements de vos utilisateurs. :::tip L'App Store autorise les options de paiement externe uniquement aux États-Unis et au Japon. Pour utiliser un paywall exclusivement pour ces marchés, dupliquez votre paywall actuel et configurez un paywall web. Vous aurez ainsi deux paywalls presque identiques : un pour les États-Unis et le Japon, et un autre pour tous les autres. ::: ## Comment ça fonctionne \{#how-it-works\} Un paywall web est une URL unique générée pour chacun de vos paywalls intégrés à l'application. Elle s'ouvre dans le navigateur pour le paiement et fonctionne avec différents fournisseurs de paiement (Stripe, Paddle et autres), prenant en charge aussi bien une page simple avec un bouton Apple Pay que des flows plus complexes avec des offres supplémentaires. Les paywalls web fonctionnent de la manière suivante : 1. **Configurez l'apparence et le comportement de la page paywall web** dans l'éditeur de paywall web. 2. **Associez le paywall web** dans les paramètres du paywall. 3. Dans le paywall de votre application, **ajoutez un bouton** redirigeant les utilisateurs vers le navigateur. 4. Lorsque les utilisateurs appuient sur le bouton, le SDK Adapty **génère une URL unique**. 5. Les utilisateurs **accèdent à la page paywall web** et **paient** un abonnement via un moyen de paiement externe. 6. À leur retour dans l'application, le SDK Adapty **interroge les mises à jour du profil** pour confirmer l'activation de l'abonnement. 7. Adapty enregistre l'achat et surveille l'abonnement pour détecter tout changement de statut, comme les renouvellements ou les résiliations. ## Étape 1. Créer un paywall web \{#step-1-create-a-web-paywall\} 1. Préparez un paywall : - Pour activer les paiements externes sur un paywall existant, [dupliquez-le](duplicate-paywalls). Cela vous permet de montrer le web paywall à votre segment cible et l'original à tous les autres utilisateurs. - Pour partir de zéro, [créez](create-paywall) un nouveau paywall. 2. Sur la page Paywall, passez à l'onglet **Web paywall** et cliquez sur **Create web paywall**. Vous serez redirigé vers une nouvelle page. 3. Configurez le web paywall et connectez un moyen de paiement. :::tip Pour obtenir de l'aide sur la configuration de l'éditeur externe et la connexion d'un fournisseur de paiement, consultez le [guide de démarrage rapide](web-paywall-configuration). ::: 4. Retournez sur la page **Web paywall** et collez le lien du paywall. :::important Lorsque vous publiez votre paywall en production, assurez-vous d'utiliser le lien correct généré après la publication de votre web paywall. Le format du lien est `paywalls-....fnlfx.com`. ::: 5. Cliquez sur **Save**. ## Étape 2. Déclencher le paywall \{#step-2-trigger-the-paywall\} Pour utiliser votre paywall web, vous devez le déclencher, et la façon de procéder dépend de votre configuration : - Si vous utilisez le Flow builder, il vous suffit d'[ajouter un nouveau bouton](#step-2a-add-a-web-purchase-button) qui utilisera le lien que vous avez fourni pour suivre les achats et renvoyer les données à Adapty. - Si vous utilisez le SDK, vous devez configurer la méthode [`openWebPaywall`](#step-2b-call-the-sdk-method) pour gérer les paywalls web. ### Étape 2a. Ajouter un bouton d'achat web \{#step-2a-add-a-web-purchase-button\} Si vous utilisez le **Flow Builder**, vous devez ajouter un bouton de paywall web. Ce bouton utilisera le lien que vous avez fourni pour suivre les achats et renvoyer les données à Adapty. 1. Ouvrez le flow et ajoutez un bouton. Si vous utilisez un modèle ou un paywall existant, ajoutez un bouton de paywall web à côté du bouton d'achat existant. Vous pouvez le configurer de la même manière. 2. Dans le panneau **Interactions** à droite, cliquez sur **Add trigger**. Ensuite, assignez l'action **Purchase** à ce déclencheur. 3. Dans les paramètres de l'action, passez à l'onglet **Web payment**. Là, sélectionnez un produit et—optionnellement—une offre à associer au bouton d'achat web. 4. Collez le lien du paywall web dans le champ **Web paywall URL**. 5. Par défaut, les paywalls web s'ouvrent dans un navigateur intégré à l'application afin que les utilisateurs n'aient pas besoin de quitter votre app. Si vous souhaitez les ouvrir dans un navigateur externe, sélectionnez **Open in external browser**. ### Étape 2b. Appeler la méthode du SDK \{#step-2b-call-the-sdk-method\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. Consultez les guides spécifiques à chaque framework : - [iOS](ios-web-paywall) - [Android](android-web-paywall) - [React Native](react-native-web-paywall) - [Flutter](flutter-web-paywall) - [Unity](unity-web-paywalls) - [Kotlin Multiplatform](kmp-web-paywalls) - [Capacitor](capacitor-web-paywall) ## Étape 3. Configurer un placement \{#step-3-set-up-a-placement\} Étant donné que l'App Store n'autorise les options de paiement externe qu'aux États-Unis et au Japon, créez un segment d'utilisateurs distinct pour les utilisateurs iOS sur ces marchés et configurez un placement pour cibler différents paywalls selon les segments. Pour les utilisateurs Android, aucune restriction géographique ne s'applique — créez un segment Android distinct sans filtre de pays. 1. [Créez un nouveau segment](segments) avec les attributs suivants : - **Country from store account** : United States, Japan - **Platform** : iOS and iPadOS - **App version** : La dernière version utilisant le SDK Adapty. 2. [Créez](create-placement) un placement ou [modifiez](edit-placement) un placement existant. [Ajoutez une nouvelle audience](add-audience-paywall-ab-test) avec le paywall web et le segment créé. --- # File: web-paywall-configuration --- --- title: "Configuration du web paywall" --- Une fois que vous cliquez sur **Create web paywall** sur la page **Web paywall**, vous serez redirigé vers une page dédiée pour configurer le design du web paywall et le mode de paiement. ## Configurer un mode de paiement \{#set-up-a-payment-method\} Vous devez d'abord connecter un prestataire de paiement qui gérera les achats. Les options disponibles sont : - Stripe - Paddle - Paypal - Solidgate :::important Pour garantir un suivi précis des analyses du web paywall dans Adapty, vous devez [ajouter vos produits](product) avec les identifiants produit Stripe/Paddle/autre prestataire de paiement correspondants dans Adapty. ::: Pour configurer un prestataire de paiement : 1. Sur la page de liste des web paywalls, cliquez sur **Settings** et passez à l'onglet **Integrations**. 2. Sélectionnez un prestataire de paiement et suivez les instructions d'intégration affichées à l'écran. <img src="/assets/shared/img/web-paywall-configuration-1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ⚠️ Si vous choisissez Stripe, assurez-vous d'utiliser les clés de l'environnement **Test Mode** même si l'interface indique **Sandbox**. Sinon, votre web paywall ne fonctionnera pas. Les **Sandboxes** dans Stripe ne sont pas encore prises en charge. <img src="/assets/shared/img/web-paywall-configuration-stripe.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Configurer la vérification de domaine Apple Pay \{#set-up-apple-pay-domain-verification\} Dans **Settings > Domains**, sélectionnez votre prestataire de paiement principal pour la vérification de domaine. Vérifiez ensuite vos domaines de paywall auprès du prestataire concerné : **Stripe** : 1. Rendez-vous dans les [paramètres des domaines de méthode de paiement](https://dashboard.stripe.com/settings/payment_method_domains) et cliquez sur **Add a new domain**. 2. Ajoutez `app.funnelfox.com` et votre sous-domaine de paywall personnel (il ressemblera à `paywalls-....fnlfx.com`). Pour trouver votre sous-domaine, allez dans **Settings > Domains** et copiez la valeur **Hosted subdomain**. **Paddle** : 1. Dans la console Paddle, allez dans **Checkout > Website approval** et cliquez sur **Add a new domain**. 2. Ajoutez `app.funnelfox.com` et votre sous-domaine de paywall personnel (il ressemblera à `paywalls-....fnlfx.com`). Pour trouver votre sous-domaine, allez dans **Settings > Domains** et copiez la valeur **Hosted subdomain**. Le processus d'approbation chez Paddle est manuel, vous devrez donc patienter jusqu'à ce que les domaines passent de `Pending` à `Approved`. **FunnelFox Billing** : Suivez les [instructions d'intégration FunnelFox Billing](https://funnelfox.com/docs/billing/integration-billing-funnelfox). **SolidGate** : 1. Dans votre Solidgate Dashboard, allez dans **Developers > Apple Pay Domains**. 2. Cliquez sur **+ Add new domain** et collez le domaine de votre projet (depuis **Settings > Domains** dans FunnelFox). Ajoutez également votre domaine personnalisé, le cas échéant. 3. Pour utiliser Apple Pay en mode aperçu, ajoutez aussi `http://app.funnelfox.com/`. ## Créer et configurer un web paywall \{#create-and-configure-a-web-paywall\} 1. Sur la page de liste des web paywalls, cliquez sur **Create a paywall**. 2. Saisissez un nom de paywall et cliquez sur **Create**. <img src="/assets/shared/img/web-paywall-configuration-2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Vous serez redirigé vers un modèle de base avec deux options d'abonnement et le bouton d'achat Apple Pay. Le premier écran liste les formules d'abonnement. Les deuxième et troisième écrans sont des écrans de paiement. Chaque écran correspond à une formule proposée. Si vous n'avez qu'une seule formule, supprimez l'écran en trop. Si vous en avez davantage, dupliquez les écrans de paiement. Le dernier écran que les utilisateurs voient après un achat réussi est celui où vous devez indiquer clairement qu'ils peuvent retourner dans votre application. <img src="/assets/shared/img/web-paywall-configuration-10.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Configurez la liste des formules : ajoutez ou supprimez des formules et des prix. Tous les prix et formules affichés à l'écran ne sont pas ajoutés dynamiquement, vous devez donc les configurer manuellement. <img src="/assets/shared/img/web-paywall-configuration-8.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Ajoutez ou configurez un écran de paiement pour chaque formule. Nous recommandons d'ajouter le montant total sur chaque écran de paiement afin que les utilisateurs sachent combien ils devront payer avant de cliquer sur le bouton d'achat. 6. Sur les écrans de paiement, le bouton Apple Pay est déjà présent. Pour qu'il fonctionne, configurez sur chaque écran : 1. **Product type** : choisissez si vous souhaitez ajouter une période d'essai ou une réduction. 2. **Trial period** : saisissez la durée de la période d'essai. 3. **Product** : sélectionnez votre produit depuis votre prestataire de paiement. :::important Assurez-vous que le produit est bien ajouté dans Adapty. Sinon, le résultat de l'achat sera défini par défaut. ::: 4. **Subscription discount** : optionnellement, sélectionnez un coupon depuis votre prestataire de paiement. <img src="/assets/shared/img/web-paywall-configuration-6.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Vous devez maintenant associer les formules aux écrans de paiement. Sur l'écran de sélection des formules, cliquez sur le bouton **Continue** et sélectionnez un écran de destination pour chaque formule. <img src="/assets/shared/img/web-paywall-configuration-9.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Lorsque votre paywall est prêt, vous devez récupérer son lien pour l'activer dans Adapty. La façon de l'obtenir dépend de si vous le testez ou le lancez en production : 1. **Pour les tests en sandbox** : cliquez sur **Preview** en haut à droite et copiez le lien. 2. **Pour la production** : cliquez sur **Publish** en haut à droite. Cliquez sur **Home** et copiez le lien depuis la colonne **URL**. <img src="/assets/shared/img/web-paywall-configuration-11.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> C'est tout ! Utilisez ce lien pour [poursuivre la configuration](web-paywall#step-2-trigger-the-paywall). --- # File: fallback-paywalls --- --- title: "Paywalls de secours" description: "Utilisez les paywalls de secours pour garantir une expérience utilisateur fluide dans Adapty." --- :::important Cet article couvre les paywalls de secours pour le SDK Adapty v3 et les versions antérieures. Avec le SDK v4, un seul fichier de secours inclut les données de flow et de paywall — consultez [Flows de secours](fallback-flows). L'ancien format de fichier de secours est incompatible avec le SDK v4, alors téléchargez la version correcte après la mise à niveau. ::: Pour garantir une expérience utilisateur fluide, il est important de configurer des **versions de secours** pour vos [paywalls](paywalls) et [onboardings](onboardings). Lorsque votre application charge un paywall, le SDK demande les données de configuration du paywall à nos serveurs. Mais que se passe-t-il si l'appareil ne peut pas se connecter à Adapty en raison de problèmes réseau ou d'une indisponibilité des serveurs ? * Si l'utilisateur a déjà accédé au paywall et que l'appareil a mis ses données en cache, l'application charge les données du paywall **depuis le cache**. * Si l'appareil n'a pas mis le paywall en cache, l'application recherche un fichier de configuration stocké localement. Cela permet à l'application d'afficher le paywall sans erreur. Adapty génère automatiquement des fichiers de configuration de secours à télécharger et à utiliser. Chaque fichier contient les configurations spécifiques à la plateforme pour *tous* vos placements. ## Commencer \{#get-started\} 1. [Téléchargez le fichier de configuration de secours](/local-fallback-paywalls) depuis Adapty. 2. Utilisez le SDK Adapty pour configurer vos paywalls de secours : * [iOS](ios-use-fallback-paywalls) * [Android](android-use-fallback-paywalls) * [React Native](react-native-use-fallback-paywalls) * [Flutter](flutter-use-fallback-paywalls) * [Unity](unity-use-fallback-paywalls) * [Kotlin Multiplatform](kmp-use-fallback-paywalls) * [Capacitor](capacitor-use-fallback-paywalls) ## Limitations \{#limitations\} Les paywalls de secours sont codés en dur et stockés localement, ils n'ont donc pas les capacités dynamiques des paywalls Adapty ordinaires. * Les paywalls de secours ne prennent pas en charge [l'internationalisation](paywall-localization). Le fichier utilise toujours la locale `en`, donc les utilisateurs hors ligne ne voient que l'anglais. [Passez au SDK v4](migration-to-ios-sdk-v4) pour lever cette limite — son fichier de secours inclut toutes les locales. * Chaque placement ne peut avoir qu'un seul paywall de secours. Si votre configuration inclut différentes configurations de paywall pour différentes [audiences](audience), Adapty utilise la configuration destinée à « All users ». * Les paywalls de secours ne prennent pas en charge les [tests A/B](ab-tests). Si un paywall participe à un test A/B, son fichier de configuration de secours inclura la variante avec le poids le plus élevé. * Les paywalls de secours ne peuvent pas être [gérés à distance](customize-paywall-with-remote-config). Si vous souhaitez mettre à jour le fichier de configuration, vous devez publier une nouvelle version de l'application sur l'App Store / Google Play. --- # File: local-fallback-paywalls --- --- title: "Télécharger les paywalls de secours" description: "Utilisez les paywalls de secours locaux dans Adapty pour garantir des flows d'abonnement fluides." --- Adapty génère automatiquement des fichiers de configuration JSON pour vos [paywalls de secours](/fallback-paywalls), un par plateforme. Ces fichiers contiennent également les données de secours pour vos onboardings. Si un placement comporte plusieurs paywalls ou onboardings, la version de secours inclura la variante ayant le poids le plus élevé ou l'audience la plus large. Adapty met à jour ces fichiers chaque fois que vous modifiez vos paywalls ou onboardings. Suivez les étapes ci-dessous pour télécharger vos configurations de secours : 1. Ouvrez la page **[Placements](https://app.adapty.io/placements)**. 2. Cliquez sur le bouton **Fallbacks**. 3. Sélectionnez votre plateforme cible (*iOS* ou *Android*) dans le menu déroulant. 4. Sélectionnez votre version du SDK pour lancer le téléchargement. <img src="/assets/shared/img/9c63367-placements.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Après le téléchargement \{#after-the-download\} Suivez le guide de configuration correspondant à votre plateforme : * [iOS](ios-use-fallback-paywalls) * [Android](android-use-fallback-paywalls) * [React Native](react-native-use-fallback-paywalls) * [Flutter](flutter-use-fallback-paywalls) * [Unity](unity-use-fallback-paywalls) * [Kotlin Multiplatform](kmp-use-fallback-paywalls) * [Capacitor](capacitor-use-fallback-paywalls) --- # File: paywall-metrics --- --- title: "Métriques de paywall" description: "Suivez et analysez les métriques de performance des paywalls pour améliorer vos revenus d'abonnements." --- Adapty collecte une série de métriques pour vous aider à mieux mesurer la performance de vos paywalls. Toutes les métriques sont mises à jour en temps réel, sauf les vues, qui sont actualisées toutes les quelques minutes. Toutes les métriques, à l'exception des vues, sont attribuées au produit au sein du paywall. Ce document présente les métriques disponibles, leurs définitions et leur mode de calcul. Les métriques de paywall sont disponibles dans la liste des paywalls, vous offrant une vue d'ensemble de la performance de tous vos paywalls. Cette vue consolidée présente des métriques agrégées pour chaque paywall, ce qui vous permet d'évaluer leur efficacité et d'identifier les axes d'amélioration. Pour une analyse plus détaillée de chaque paywall, vous pouvez accéder aux métriques détaillées du paywall. Dans cette section, vous trouverez des métriques complètes spécifiques au paywall sélectionné, offrant une vision plus approfondie de ses performances. ### Filtrer les métriques par date d'installation \{#filter-metrics-by-install-date\} Les métriques de paywall, d'essai et d'achat peuvent être regroupées selon deux dates différentes : - **La date de l'événement** — quand le paywall a été consulté, l'essai commencé ou l'achat effectué. - **La date d'installation** — quand l'utilisateur a ouvert l'application pour la première fois. Les deux vues peuvent afficher des chiffres très différents pour la même plage de dates. La case **Filter metrics by install date** contrôle laquelle le tableau de bord utilise : - **Décochée (par défaut)** : les métriques sont regroupées par date d'événement. - **Cochée** : les métriques sont regroupées par date d'installation. **Exemple.** Vous définissez la plage de dates du 1er au 30 avril et vous regardez les essais. - **Décochée** : affiche les essais qui ont *démarré* en avril, quelle que soit la date d'installation de ces utilisateurs. - **Cochée** : affiche les essais des utilisateurs qui se sont *installés* en avril, quelle que soit la date de début de leur essai. Utilisez la vue par date d'installation pour mesurer les performances d'acquisition d'utilisateurs pour une cohorte spécifique. Utilisez la vue par date d'événement pour mesurer l'activité d'un paywall ou d'un onboarding sur une période donnée. ### Contrôles des métriques \{#metrics-controls\} Le système affiche les métriques en fonction de la période sélectionnée et les organise selon le paramètre de la colonne de gauche avec trois niveaux d'indentation. Pour un paywall actif, les métriques couvrent la période allant de la date de démarrage du paywall jusqu'à la date actuelle. Pour les paywalls inactifs, les métriques englobent la totalité de la période allant de la date de démarrage jusqu'à la fin de la période sélectionnée. Les paywalls en brouillon et archivés sont inclus dans le tableau des métriques, mais s'il n'y a pas de données disponibles pour ces paywalls, ils apparaîtront sans aucune métrique affichée. #### Options d'affichage des données de métriques \{#view-options-for-metrics-data\} La page de paywall propose deux options d'affichage des données de métriques : par placement et par audience. Dans la vue par placement, les métriques sont regroupées par placements associés au paywall. Cela permet aux utilisateurs d'analyser les métriques selon les différents placements. Dans la vue par audience, les métriques sont regroupées par audience cible du paywall. Les utilisateurs peuvent évaluer les métriques spécifiques aux différents segments d'audience. Vous pouvez sélectionner la vue souhaitée via le menu déroulant en haut de la page de détail du paywall. #### Plages de temps \{#time-ranges\} Vous pouvez choisir parmi différentes périodes pour analyser les données de métriques, ce qui vous permet de vous concentrer sur des durées spécifiques telles que des jours, des semaines, des mois ou des plages de dates personnalisées. #### Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: Adapty propose des outils puissants pour filtrer et personnaliser l'analyse des métriques selon vos besoins. La page des métriques d'Adapty vous donne accès à différentes plages de temps, options de regroupement et possibilités de filtrage. - Filtrer par : Audience, pays, paywall, état du paywall, groupe de paywalls, placement, pays, store, produit et store du produit. - Regrouper par : Produit et store. #### Graphique d'une métrique unique \{#single-metrics-chart\} L'un des éléments clés de la page des métriques de paywall est la section graphique, qui représente visuellement les métriques sélectionnées et facilite l'analyse. La section graphique de la page des métriques de paywall comprend un graphique à barres horizontales qui représente visuellement les valeurs des métriques choisies. Chaque barre du graphique correspond à une valeur de métrique et est proportionnelle en taille, ce qui facilite la compréhension des données en un coup d'œil. La ligne horizontale indique la période analysée, et la colonne verticale affiche les valeurs numériques des métriques. La valeur totale de l'ensemble des métriques est affichée à côté du graphique. De plus, cliquer sur l'icône de flèche dans le coin supérieur droit de la section graphique élargit la vue, affichant les métriques sélectionnées sur la ligne complète du graphique. #### Récapitulatif total des métriques \{#total-metrics-summary\} À côté du graphique d'une métrique unique, la section récapitulatif total des métriques affiche les valeurs cumulées des métriques sélectionnées à un moment précis, avec la possibilité de changer la métrique affichée via un menu déroulant. ### Définitions des métriques \{#metrics-definitions\} :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: #### Revenu \{#revenue\} Cette métrique représente le montant total d'argent généré en USD par les achats et les renouvellements. Veuillez noter que le calcul du revenu n'inclut pas la commission de l'App Store / Play Store et est calculé avant déduction des frais éventuels. #### Recettes \{#proceeds\} Cette métrique représente le montant réel reçu par le propriétaire de l'application en USD, provenant des achats et des renouvellements, après déduction de la commission applicable de l'App Store / Play Store. :::important Informez Adapty si votre application est inscrite à un programme de commission réduite. Pour garantir des calculs corrects, précisez votre statut dans le [Small Business Program](app-store-small-business-program) et le [programme de frais de service réduits](google-reduced-service-fee) dans vos [paramètres d'application](general). ::: Cela reflète le revenu net qui contribue directement aux gains de l'application. Pour plus d'informations sur le calcul des recettes, vous pouvez consulter la [documentation](analytics-cohorts#revenue-vs-proceeds) Adapty. #### ARPPU \{#arppu\} L'ARPPU est le revenu moyen par utilisateur payant. Il se calcule en divisant le revenu total par le nombre d'utilisateurs payants uniques. Par exemple : 15 000 $ de revenu / 1 000 utilisateurs payants = 15 $ d'ARPPU. #### ARPAS \{#arpas\} Le revenu moyen par abonné actif vous permet de mesurer le revenu moyen généré par abonné actif. Il se calcule en divisant le revenu total par le nombre d'abonnés ayant activé un essai ou un abonnement. Par exemple, si le revenu total est de 5 000 $ et qu'il y a 1 000 abonnés, l'ARPAS sera de 5 $. Cette métrique aide à évaluer le potentiel de monétisation moyen par abonné. #### Taux de conversion (CR) unique vers les achats \{#unique-conversion-rate-cr-to-purchases\} Le taux de conversion unique vers les achats se calcule en divisant le nombre d'achats par le nombre de vues uniques. Par exemple, si 10 achats ont été réalisés pour 100 vues uniques, le taux de conversion unique vers les achats sera de 10 %. Cette métrique se concentre sur le ratio entre les achats et le nombre de vues uniques, offrant des informations sur l'efficacité de conversion des visiteurs uniques en clients payants. #### CR vers les achats \{#cr-to-purchases\} Le taux de conversion vers les achats se calcule en divisant le nombre d'achats par le nombre total de vues. Par exemple, si 10 achats ont été réalisés pour 100 vues, le taux de conversion vers les achats sera de 10 %. Cette métrique indique le pourcentage de vues qui aboutissent à des achats, offrant des informations sur l'efficacité de votre paywall à convertir les utilisateurs en clients payants. #### CR unique vers les essais \{#unique-cr-to-trials\} Le taux de conversion unique vers les essais se calcule en divisant le nombre d'essais démarrés par le nombre de vues uniques. Par exemple, si 30 essais ont été démarrés pour 100 vues uniques, le taux de conversion unique vers les essais sera de 30 %. Cette métrique mesure le pourcentage de vues uniques qui aboutissent à des activations d'essai, offrant des informations sur l'efficacité de votre paywall à convertir les visiteurs uniques en utilisateurs en période d'essai. #### Achats \{#purchases\} Les achats représentent le total cumulé des différentes transactions effectuées sur le paywall. Les transactions suivantes sont incluses dans cette métrique (les renouvellements ne sont pas inclus) : - Les nouveaux achats effectués directement sur le paywall. - Les conversions d'essais initialement activés sur le paywall. - Les rétrogradations, mises à niveau et changements transversaux d'abonnements effectués sur le paywall. - Les restaurations d'abonnements sur le paywall, par exemple lorsqu'un abonnement est rétabli après expiration sans renouvellement automatique. En tenant compte de ces différents types de transactions, la métrique des achats offre une vue complète de l'activité globale d'acquisition et de monétisation sur votre paywall. #### Essais \{#trials\} La métrique des essais représente le nombre total d'essais qui ont été activés. Elle reflète le nombre d'utilisateurs ayant initié des périodes d'essai via votre paywall. Cette métrique aide à suivre l'efficacité de votre offre d'essai et peut fournir des informations sur l'engagement des utilisateurs et la conversion des essais en abonnements payants. #### Essais annulés \{#trials-canceled\} La métrique des essais annulés représente le nombre d'essais pour lesquels la fonctionnalité de renouvellement automatique a été désactivée. Cela se produit lorsque les utilisateurs se désinscrivent manuellement de l'essai, indiquant leur décision de ne pas poursuivre l'abonnement après la fin de la période d'essai. Le suivi des essais annulés fournit des informations précieuses sur le comportement des utilisateurs et vous permet de comprendre le taux auquel les utilisateurs renoncent à l'essai. #### Remboursements \{#refunds\} La métrique des remboursements représente le nombre d'achats et d'abonnements remboursés. Cela inclut les transactions qui ont été annulées ou remboursées pour diverses raisons, telles que les demandes des clients, les problèmes de paiement ou toute autre politique de remboursement applicable. #### Taux de remboursement \{#refund-rate\} Le taux de remboursement se calcule en divisant le nombre de remboursements par le nombre de premiers achats (les renouvellements ne sont pas inclus). Par exemple, si 5 remboursements ont été effectués pour 1 000 premiers achats, le taux de remboursement sera de 0,5 %. #### Vues \{#views\} La métrique des vues représente le nombre total de fois que le paywall a été consulté par les utilisateurs. Chaque fois qu'un utilisateur visite le paywall, cela compte comme une vue distincte. Par exemple, si un utilisateur visite le paywall deux fois, cela sera enregistré comme deux vues. Le suivi des vues vous aide à comprendre le niveau d'engagement et les interactions des utilisateurs avec votre paywall, offrant des informations sur le comportement des utilisateurs et l'efficacité du placement et du design de votre paywall. #### Vues uniques \{#unique-views\} La métrique des vues uniques représente le nombre d'instances uniques dans lesquelles le paywall a été consulté par les utilisateurs. Contrairement aux vues totales, qui comptent chaque visite comme une vue distincte, les vues uniques ne comptent la visite d'un utilisateur sur le paywall qu'une seule fois, quel que soit le nombre de fois où il y accède. Par exemple, si un utilisateur visite le paywall deux fois, cela sera enregistré comme une vue unique. Le suivi des vues uniques fournit une mesure plus précise de l'engagement des utilisateurs et de la portée de votre paywall, car il se concentre sur les utilisateurs individuels plutôt que sur le nombre total de visites. :::warning Assurez-vous d'envoyer les vues du paywall à Adapty en utilisant la méthode `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. Sinon, les vues du paywall ne seront pas prises en compte dans les métriques et les conversions ne seront pas pertinentes. ::: --- # File: migrate-paywalls --- --- title: "Migrer des paywalls entre applications" description: "Découvrez comment migrer des paywalls d'autres applications dans Adapty." --- Avec Adapty, vous n'avez pas besoin de créer un nouveau paywall de zéro pour chaque application. Si vous gérez plusieurs applications, vous pouvez migrer la configuration du Paywall Builder de n'importe quel paywall créé avec le builder d'une application à une autre. La migration vous permet de copier toutes les configurations visuelles : - Les paramètres de mise en page du paywall et de tous ses éléments - Les médias - La localisation La migration s'applique uniquement à la configuration du builder et ne copie pas les produits ni le Remote Config. :::note Si vous migrez une configuration de Paywall Builder avec des polices personnalisées, testez-les sur un appareil car elles peuvent s'afficher incorrectement. ::: ## Migrer un paywall \{#migrate-paywall\} :::important Vous pouvez uniquement migrer des paywalls créés dans le **nouveau** Paywall Builder d'Adapty. Pour migrer des paywalls du builder **legacy**, vous devez d'abord les migrer vers le nouveau Paywall Builder. ::: Pour migrer une configuration de Paywall Builder : 1. **Pour un nouveau paywall** : Commencez la [création d'un paywall](create-paywall) et ajoutez des produits. Ensuite, cliquez sur **Build no-code paywall** pour ouvrir la bibliothèque de templates. **Pour un paywall existant** : Accédez à la section **Layout settings** de l'onglet **Builder & Generator** et cliquez sur **Change template**. 2. Cliquez sur **Choose paywall** dans le bloc **Copy a design from your apps** lors de la modification du template de paywall. <img src="/assets/shared/img/migrate-paywall-builder.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Sélectionnez l'application et le paywall dont vous souhaitez copier la configuration. <img src="/assets/shared/img/migrate-app.png" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur **Copy Selected Paywall**. Après la migration, vous pouvez effectuer toutes les modifications nécessaires sans affecter le paywall d'origine. --- # File: duplicate-paywalls --- --- title: "Dupliquer un paywall" description: "Découvrez comment gérer les paywalls dupliqués et optimiser leurs performances dans Adapty." --- Si vous devez apporter de petites modifications à un paywall existant dans Adapty, notamment lorsqu'il est déjà utilisé dans votre application mobile et que vous ne voulez pas fausser vos analytics, vous pouvez simplement le dupliquer. Vous pouvez ensuite utiliser ces doublons pour remplacer les paywalls d'origine dans certains ou tous les placements selon vos besoins. Cette opération crée une copie du paywall avec tous ses détails : son nom, ses produits et ses éventuelles promotions. Le nom du nouveau paywall sera suivi de « Copy » pour le distinguer facilement de l'original. Pour dupliquer un paywall depuis l'Adapty Dashboard : 1. Ouvrez la section [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. La page de liste des paywalls dans l'Adapty Dashboard offre une vue d'ensemble de tous les paywalls présents dans votre compte. 2. Cliquez sur le bouton **3-dot** à côté du paywall et sélectionnez l'option **Duplicate**. <img src="/assets/shared/img/duplicate.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Ajustez le nouveau paywall et cliquez sur le bouton **Save**. 4. Adapty vous proposera de remplacer les paywalls d'origine par leurs doublons dans les placements si le paywall d'origine est actuellement utilisé dans un placement. Si vous choisissez **Create and replace original**, les nouveaux paywalls passeront immédiatement en état **Live**. Sinon, vous pouvez les créer comme nouveaux paywalls à l'état **Draft** et les ajouter aux placements ultérieurement. --- # File: archive-paywalls --- --- title: "Archiver un paywall" description: "Découvrez comment archiver les paywalls obsolètes dans Adapty sans perdre de données." --- Au fil de votre utilisation d'Adapty et de la configuration de vos paywalls, vous pouvez accumuler des paywalls qui ne correspondent plus à votre stratégie ou à vos campagnes actuelles. Ces paywalls inutilisés, laissés à l'état `Inactive`, peuvent encombrer votre espace de travail et rendre plus difficile la recherche de ceux qui comptent vraiment. Pour y remédier, Adapty vous offre la possibilité d'archiver ces paywalls superflus. L'archivage garantit qu'ils sont stockés en toute sécurité sans suppression définitive, prêts à être consultés si besoin à l'avenir. De plus, les paywalls archivés peuvent être filtrés depuis la vue par défaut, ce qui désencombre votre espace de travail et simplifie votre interface. Dans ce guide, nous vous expliquons comment archiver efficacement des paywalls dans Adapty, pour une meilleure maîtrise de votre gestion des paywalls. Petit rappel : les paywalls actifs, utilisés dans au moins un placement, ne peuvent pas être archivés. Si vous souhaitez archiver un tel paywall, commencez par le retirer de tous les placements. :::note Vous ne pouvez pas archiver un paywall s'il est utilisé dans un test A/B non archivé. Ainsi, l'utilisateur peut consulter les métriques détaillées d'un test A/B terminé, et le paywall associé fait partie de ces données. ::: **Pour archiver un paywall :** 1. Ouvrez la section [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. 2. Cliquez sur le bouton **3 points** à côté du paywall et sélectionnez l'option **Archive**. <img src="/assets/shared/img/archive-paywall.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Archive paywall**, saisissez simplement le nom du paywall à archiver, puis cliquez sur le bouton **Archive**. --- # File: restore-paywall --- --- title: "Restaurer un paywall depuis l'archive" description: "Restaurez des paywalls dans Adapty pour assurer des services d'abonnement ininterrompus pour les utilisateurs." --- La possibilité d'archiver des paywalls est une fonctionnalité très utile pour simplifier la gestion de vos paywalls. Elle vous permet de masquer les paywalls dont vous n'avez plus besoin, réduisant ainsi l'encombrement de votre espace de travail. De plus, l'option de restauration des paywalls archivés offre une grande flexibilité, vous permettant de les réintégrer dans votre stratégie s'ils s'avèrent à nouveau utiles. Les paywalls archivés peuvent être exclus de la vue par défaut. Pour les afficher, sélectionnez **Archived** dans le filtre **State**. **Pour restaurer un paywall depuis l'archive** 1. Ouvrez la section [**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty. 2. Assurez-vous que les paywalls archivés sont affichés dans la liste. Sinon, mettez à jour le filtre à droite. <img src="/assets/shared/img/paywall-filter.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur le bouton **3-dot** à côté du paywall archivé et sélectionnez **Back to active**. <img src="/assets/shared/img/restore-paywall.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: profiles-crm --- --- title: "Profils/CRM" description: "Gérez les profils utilisateurs et les données CRM dans Adapty pour améliorer la segmentation d'audience." --- Profils est un CRM pour vos utilisateurs. Avec Profils, vous pouvez : 1. Trouvez des utilisateurs spécifiques par ID de profil, ID utilisateur client, e-mail ou ID de transaction. 2. Consultez la chronologie des événements de l'utilisateur, y compris les problèmes de facturation, les délais de grâce et autres [événements](events). 3. Analysez les propriétés de l'utilisateur telles que l'état de l'abonnement, le revenu/produit total, et plus encore. 4. Accordez à l'utilisateur un abonnement. :::note Les événements du flux d'événements arrivent sur le tableau de bord avec un léger délai. Les nouveaux profils et les modifications d'attributs peuvent ne pas être visibles immédiatement. ::: <img src="/assets/shared/img/profiles.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::link Pour comprendre comment Adapty crée et associe les profils utilisateurs, consultez [Comment fonctionnent les profils](how-profiles-work). ::: ## Trouver des utilisateurs \{#finding-users\} Dans la liste des profils, vous pouvez rechercher un utilisateur spécifique par : - **Profile ID** : l'identifiant interne d'Adapty pour l'utilisateur (également appelé Adapty ID). - **Customer user ID** : l'identifiant de votre application pour l'utilisateur, si vous en avez défini un. - **Email** : l'adresse e-mail de l'utilisateur, si elle a été envoyée comme attribut personnalisé. - **Transaction ID** : l'identifiant de transaction du store issu d'un achat. Cliquez sur n'importe quelle ligne pour ouvrir le profil complet de l'utilisateur. ## État de l'abonnement \{#subscription-state\} Dans la liste des profils, vous pouvez filtrer et trier les utilisateurs par état de l'abonnement. Les valeurs d'état sont : | **État** de l'utilisateur | Description | | :--------------------- | :----------------------------------------------------------- | | Subscribed | L'utilisateur dispose d'un abonnement actif avec le renouvellement automatique activé. | | Auto-renew off | L'utilisateur a désactivé le renouvellement automatique mais conserve l'accès aux fonctionnalités premium jusqu'à la fin de la période d'abonnement. | | Subscription cancelled | L'utilisateur a annulé son abonnement, qui a entièrement pris fin. | | Billing issue | L'utilisateur n'a pas pu être débité en raison d'un problème de paiement, après l'expiration de son abonnement ou de sa période d'essai. | | Grace period | L'utilisateur est actuellement en délai de grâce en raison d'un problème de paiement survenu lors de la tentative de débit après l'expiration de son abonnement ou de sa période d'essai. | | Active trial | L'utilisateur dispose d'un abonnement actif actuellement en période d'essai. | | Trial cancelled | L'utilisateur a annulé la période d'essai et ne dispose pas d'un abonnement actif. | | Never subscribed | L'utilisateur ne s'est jamais abonné ni n'a démarré de période d'essai et reste un utilisateur freemium. | ## Attributs utilisateur \{#user-attributes\} <img src="/assets/shared/img/ce8df4d-CleanShot_2023-06-26_at_20.32.232x.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> Vous pouvez envoyer des propriétés utilisateur supplémentaires à Adapty via le SDK. Par défaut, Adapty définit : | Propriété | Description | | ---------------- | ------------------------------------------------------------ | | Customer user ID | Un identifiant de votre utilisateur final dans votre système. | | Adapty ID | Identifiant interne Adapty de votre utilisateur final, appelé Profile ID. | | IDFA | L'Identifier for Advertisers, attribué par Apple à l'appareil d'un utilisateur. Nécessite l'autorisation App Tracking Transparency (ATT) sur iOS 14+. Non disponible sur Android. | | IP country | Pays de votre utilisateur final, déterminé par son adresse IP la plus récente. | | Store country | Pays du compte App Store ou Google Play de votre utilisateur final, tel que communiqué par le store. Adapty le reçoit avec les transactions du store, donc il est vide pour les utilisateurs sans achats. | | OS | Le système d'exploitation utilisé par l'utilisateur final. | | Device | Le nom du modèle d'appareil visible par l'utilisateur final. | | Install date | La date à laquelle l'utilisateur a été enregistré pour la première fois dans Adapty : <ul><li>La date de création de l'utilisateur. </li><li>Si l'utilisateur a installé votre application avant que vous n'intégriez Adapty, la date d'installation correspond à la date de sa première transaction.</li><li>Le cas échéant, la date fournie lors d'une importation de données historiques.</li></ul> | | Created at | La date de création de l'utilisateur. | Envoyez au moins votre identifiant utilisateur interne ou votre adresse e-mail. Cela vous permet de retrouver les utilisateurs par ces identifiants dans la liste des profils. Après avoir installé le SDK, Adapty collecte automatiquement les événements utilisateur depuis la file de paiement et les affiche dans le profil utilisateur. Les attributs du tableau ci-dessus sont collectés automatiquement — vous n'avez pas besoin de les envoyer. ### Attributs personnalisés \{#custom-attributes\} Dans la section **Attributes** d'un profil, vous pouvez voir les attributs personnalisés définis via le SDK ou l'API. Vous pouvez également en attribuer manuellement en cliquant sur le bouton **Add attribute**. <img src="/assets/shared/img/378c1fb-add_attribute.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> Pour modifier ou supprimer un attribut, cliquez sur les trois points à côté de lui et sélectionnez **Edit** ou **Delete**. La suppression d'un attribut n'affecte que ce profil — les autres profils qui possèdent le même attribut le conservent. ## Accorder un abonnement \{#granting-a-subscription\} Dans un profil, vous pouvez prolonger un abonnement actif ou accorder à un utilisateur un accès à vie à un niveau d'accès — sans lui demander d'effectuer un achat. <img src="/assets/shared/img/b1d74fd-edit_paid_access_level.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> C'est particulièrement utile pour : - Dédommager un utilisateur après un problème de facturation ou de support. - Lancer des promotions manuelles ou des programmes bêta. - Tester des flows d'abonnement sans effectuer de vrai achat. Pour accorder un accès, ouvrez le profil de l'utilisateur, allez dans la section **Access levels** et cliquez sur **Edit**. Définissez la date d'expiration et enregistrez. La date d'expiration doit être dans le futur et ne peut pas être réduite une fois définie. La modifier pour des abonnements actifs n'affecte pas les paiements en cours. :::note Accorder un accès ne crée pas d'événements d'achat sur l'App Store ou Google Play. Le fil d'événements et les analyses de l'utilisateur différeront d'un vrai flux d'achat. ::: Vous pouvez également accorder un accès de manière programmatique en utilisant la méthode API [Grant access level](api-adapty/operations/grantAccessLevel). ## Partager l'accès payant entre les comptes utilisateurs \{#sharing-paid-access-between-user-accounts\} :::link Article principal : [Partager l'accès payant entre les comptes utilisateurs](sharing-paid-access-between-user-accounts) ::: ### Historique du partage d'accès \{#access-sharing-history\} Lorsque des niveaux d'accès sont partagés ou transférés, le profil de l'utilisateur affiche un lien vers le profil connecté — le profil qui a partagé l'accès, ou celui qui l'a reçu. Pour consulter le profil connecté, dans le **Profile** de l'utilisateur, cliquez sur le lien situé à côté du niveau d'accès. <img src="/assets/shared/img/profile-access-level-origin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Les soldes en monnaie virtuelle ne sont pas partagés ni transférés entre les profils comme le sont les niveaux d'accès. Chaque solde reste attaché à un seul profil — voir [Soldes, profils et appareils](virtual-currency-balance#balances-profiles-and-devices). ::: ## Étapes suivantes \{#next-steps\} - Pour comprendre comment Adapty crée et lie les profils, voir [Comment fonctionnent les profils](how-profiles-work). - Pour configurer la politique de partage des accès, voir [Partage des accès payants entre comptes utilisateurs](sharing-paid-access-between-user-accounts). - Pour accorder un accès par programmation, voir la méthode API [Accorder un niveau d'accès](api-adapty/operations/grantAccessLevel). --- # File: how-profiles-work --- --- title: "Comment fonctionnent les profils" description: "Comprenez comment Adapty crée, suit et associe les profils utilisateurs — notamment les profils anonymes, les utilisateurs identifiés et les relations parent/héritier." --- Chaque utilisateur de votre application dispose d'un profil Adapty qui suit ses achats, événements et état d'abonnement. Comprendre comment les profils sont créés et liés vous aide à éviter les bugs d'intégration, la fragmentation des données et à interpréter les informations dans la section [Profils](profiles-crm). ## Création de profil \{#profile-creation\} Adapty crée automatiquement un profil la première fois qu'un utilisateur ouvre votre application. **Sans Customer User ID**, le profil est anonyme. Un nouveau profil anonyme est créé à chaque fois que : - Un utilisateur réinstalle l'application - Un utilisateur se déconnecte de votre application (lorsque votre application appelle `Adapty.logout()`) Les achats sont liés à l'installation de l'application, et non à une identité utilisateur persistante. **Avec un Customer User ID**, le profil persiste entre les réinstallations et sur plusieurs appareils. Utiliser un Customer User ID vous permet de : 1. Suivre un utilisateur entre les réinstallations de l'application et sur plusieurs appareils. 2. Retrouver des utilisateurs via leur Customer User ID dans la section [**Profiles**](profiles-crm). 3. Utiliser le Customer User ID dans l'[API côté serveur](getting-started-with-server-side-api). 4. Adapty envoie le Customer User ID à toutes les intégrations. Le comportement du profil avec un Customer User ID dépend du moment où vous le définissez : - **Lors de l'activation du SDK** : Adapty utilise le profil existant associé à ce Customer User ID (pour les utilisateurs de retour) ou crée un nouveau profil (pour les nouveaux utilisateurs). - **Après l'activation du SDK** : Adapty crée un profil anonyme lors de l'activation. Lorsque vous identifiez l'utilisateur par la suite, Adapty associe le Customer User ID au profil anonyme (pour les nouveaux utilisateurs) ou bascule vers le profil existant avec cet ID (pour les utilisateurs de retour). **Quelle approche utiliser :** - **Customer User ID disponible au lancement de l'application** (par exemple, stocké depuis une session précédente) — transmettez-le à `activate()` lors de l'initialisation du SDK. - **Les utilisateurs se connectent après le lancement de l'application** — appelez `identify()` après l'authentification. Adapty associe l'ID au profil actuel (si l'ID est nouveau) ou bascule vers le profil existant (si l'ID existe déjà). - **Les utilisateurs peuvent acheter avant de se connecter** — appelez `identify()` après la connexion. Si le Customer User ID existe déjà dans Adapty, récupérez le profil ensuite pour synchroniser le niveau d'accès actuel. Pour les détails d'implémentation, consultez le guide SDK [identification des utilisateurs](identifying-users). :::note Si un utilisateur de retour a précédemment utilisé votre application sans Customer User ID, ces profils anonymes ne sont pas automatiquement fusionnés lorsque vous commencez à identifier lors de l'activation du SDK. Pour conserver l'historique complet de ces utilisateurs, utilisez `identify()` après la connexion à la place. ::: ## Profils parent et héritier \{#parent-and-inheritor-profiles\} Lorsqu'un même abonnement côté store est associé à plusieurs profils Adapty, Adapty traite ces profils comme une chaîne : un profil **parent** et un ou plusieurs profils **héritiers** qui partagent l'accès issu du même achat. Cela se produit lorsque : - Le [partage d'accès payant entre comptes utilisateurs](sharing-paid-access-between-user-accounts) est activé et qu'un utilisateur se connecte sur un appareil où un profil différent avait précédemment effectué l'achat. - Un utilisateur réinstalle l'application sans `customer_user_id`, et le nouveau profil récupère l'achat de l'installation précédente. - Des utilisateurs identifiés différents restaurent des achats sur le même appareil. - Une application est transférée entre des Team IDs Apple et la nouvelle application récupère les achats effectués sous l'ancien Team ID. **Comment le parent est sélectionné.** Le parent est le **premier profil à enregistrer l'achat** — déterminé par l'ordre des reçus d'achat dans Adapty, et non par l'ordre de création des profils. Par exemple : vous installez l'application sans effectuer d'achat, puis vous réinstallez et achetez un abonnement. Le second profil devient le parent car c'est lui qui a effectué l'achat. Le premier profil devient l'héritier et obtient l'accès via le partage. **Comment les événements sont distribués :** - **Événements transactionnels** (achats, renouvellements, annulations, problèmes de facturation, délais de grâce, remboursements) : Apparaissent uniquement sur le profil **parent** qui a effectué l'achat. Tous les renouvellements et mises à jour d'abonnements continuent d'apparaître sur ce profil. - **Événements `access_level_updated`** : Apparaissent sur les profils **parent et héritier** à chaque changement d'état du niveau d'accès. Cela permet de maintenir tous les profils connectés informés de leur statut d'accès actuel. Le profil parent affiche l'historique complet des transactions. Les profils héritiers affichent uniquement leurs mises à jour de niveau d'accès et un lien vers le profil parent dans la section **Access level**. <img src="/assets/shared/img/98d0dad-non-original_profile.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> **Suivi du même abonnement sur plusieurs profils.** Chaque profil héritier possède son propre `profile_id`, donc `profile_id` n'est pas stable au sein d'une chaîne. Pour identifier le même abonnement sur plusieurs profils — par exemple lors du rapprochement d'événements webhook ou de la correspondance entre profils du tableau de bord et un utilisateur sous-jacent — utilisez plutôt l'identifiant côté store. | Champ | Utilisation | | --- | --- | | `store_original_transaction_id` | Identifier une chaîne d'abonnement sur plusieurs profils. Unique par abonnement Apple. | | `profiles_sharing_access_level` (champ webhook) | Tous les profils actuellement autorisés par l'abonnement, lorsque le partage est activé. | | `profile_id` | **Non** adapté au suivi cross-profil — chaque héritier possède le sien. | ## Transactions sans profil \{#transactions-without-profiles\} Certaines transactions dans Adapty ne sont rattachées à aucun profil — elles apparaissent dans les analyses et les exports mais pas dans la liste des Profils. Cela se produit pour les **notifications store serveur à serveur (S2S)** envoyées pour des utilisateurs dont les comptes ne se sont jamais connectés à votre application via le SDK Adapty. Les sources connues sont : - Notifications S2S de l'App Store (y compris les événements de remboursement) - Notifications S2S de Google Play - Événements webhook Stripe et Paddle Ces transactions : - **Apparaissent dans les graphiques analytiques** (elles sont comptabilisées dans les métriques globales) - **Apparaissent dans les exports** (S3, GCS, BigQuery) avec `profile_id` défini à `null` - **N'apparaissent pas dans la liste des Profils** — il n'y a aucun profil auquel les rattacher Si vous constatez plus d'événements dans les analyses ou les exports que vous n'en trouvez dans l'interface Profils, la différence correspond probablement à ces transactions sans profil. Pour les trouver dans un export, filtrez les lignes où `profile_id IS NULL`. ## Partage de l'accès payant entre comptes utilisateurs \{#sharing-paid-access-between-user-accounts\} :::link Article principal : [Partage de l'accès payant entre comptes utilisateurs](sharing-paid-access-between-user-accounts) ::: Pour définir votre politique de partage de niveau d'accès, sur la page des paramètres [**General**](general), sélectionnez une option de partage. Vous pouvez définir une politique distincte pour l'[environnement sandbox](test-purchases-in-sandbox). **Activé (par défaut)** Les utilisateurs identifiés (ceux qui ont un [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) peuvent partager le même [niveau d'accès](access-level) fourni par Adapty si leur appareil est connecté au même identifiant Apple/Google. C'est utile quand un utilisateur réinstalle l'application et se connecte avec un autre e-mail — il conserve tout de même l'accès à son achat précédent. Avec cette option, plusieurs utilisateurs identifiés peuvent partager le même niveau d'accès. Même si le niveau d'accès est partagé, toutes les transactions passées et futures sont enregistrées comme événements dans le Customer User ID d'origine afin de maintenir des analyses cohérentes et conserver un historique de transactions complet — y compris les périodes d'essai, les achats d'abonnement, les renouvellements, etc., liés au même profil. **Transférer l'accès au nouvel utilisateur** Les utilisateurs identifiés peuvent continuer à accéder au [niveau d'accès](access-level) fourni par Adapty, même s'ils se connectent avec un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) différent ou réinstallent l'application, tant que l'appareil est connecté au même identifiant Apple/Google. Contrairement à l'option précédente, Adapty transfère l'achat entre les utilisateurs identifiés. Cela garantit que le contenu acheté est disponible, mais un seul utilisateur peut y avoir accès à la fois. Par exemple, si UserA achète un abonnement et que UserB se connecte sur le même appareil et restaure les transactions, UserB obtient l'accès à l'abonnement, et celui-ci est révoqué pour UserA. Si l'un des utilisateurs (le nouveau ou l'ancien) n'est pas identifié, le niveau d'accès sera tout de même partagé entre ces profils dans Adapty. Bien que le niveau d'accès soit transféré, toutes les transactions passées et futures sont enregistrées comme événements dans le Customer User ID d'origine afin de maintenir des analyses cohérentes et conserver un historique de transactions complet — y compris les périodes d'essai, les achats d'abonnement, les renouvellements, etc., liés au même profil. Après être passé à **Transférer l'accès au nouvel utilisateur**, les niveaux d'accès ne seront pas transférés entre les profils immédiatement. Le processus de transfert pour chaque niveau d'accès spécifique est déclenché uniquement lorsqu'Adapty reçoit un événement du store, comme un renouvellement d'abonnement, une restauration ou lors de la validation d'une transaction. **Désactivé** Le premier profil d'utilisateur identifié à obtenir un niveau d'accès le conservera indéfiniment. C'est la meilleure option si votre logique métier exige que les achats soient liés à un seul Customer User ID. Notez que les niveaux d'accès sont tout de même partagés entre les utilisateurs anonymes. Vous pouvez « délier » un achat en [supprimant le profil de l'utilisateur propriétaire](https://adapty.io/docs/fr/api-adapty/operations/deleteProfile). Après la suppression, le niveau d'accès devient disponible pour le premier profil utilisateur qui le réclame, qu'il soit anonyme ou identifié. La désactivation du partage ne concerne que les nouveaux utilisateurs. Les abonnements déjà partagés entre utilisateurs continueront de l'être même après la désactivation de cette option. :::warning Apple et Google exigent que les achats intégrés soient partagés ou transférés entre utilisateurs car ils s'appuient sur l'identifiant Apple/Google pour y associer l'achat. Sans partage, la restauration des achats risque de ne pas fonctionner lors des réinstallations ultérieures. La désactivation du partage peut empêcher les utilisateurs de retrouver l'accès après connexion. Nous recommandons de désactiver le partage uniquement si vos utilisateurs **sont tenus de se connecter** avant d'effectuer un achat. Dans le cas contraire, un utilisateur identifié pourrait acheter un abonnement, se connecter à un autre compte et perdre définitivement l'accès. ::: ### Quel paramètre choisir ? \{#which-setting-should-i-choose\} | Mon application... | Option à choisir | | ------------------------------------------------------------ | ------------------------------------------------------------ | | N'a pas de système de connexion et utilise uniquement les identifiants de profil anonymes d'Adapty. | Utilisez l'option par défaut, car les niveaux d'accès sont toujours partagés entre les identifiants de profil anonymes pour les trois options. | | Dispose d'un système de connexion optionnel et permet aux clients d'effectuer des achats avant de créer un compte. | Choisissez **Transférer l'accès au nouvel utilisateur** pour garantir que les clients qui achètent sans compte pourront toujours restaurer leurs transactions ultérieurement. | | Exige que les clients créent un compte avant d'acheter, mais permet de lier les achats à plusieurs Customer User ID. | Choisissez **Transférer l'accès au nouvel utilisateur** pour garantir qu'un seul Customer User ID a accès à la fois, tout en permettant aux utilisateurs de se connecter avec un autre Customer User ID sans perdre leur accès payant. | | Exige que les clients créent un compte avant d'acheter, avec des règles strictes liant les achats à un seul Customer User ID. | Choisissez **Désactivé** pour garantir que les transactions ne sont jamais transférées entre comptes. | ## Horodatages d'événements avec des dates futures (Apple/iOS) \{#event-timestamps-with-future-dates-appleios\} Ce comportement est spécifique à l'App Store d'Apple. Le système de notifications de Google Play n'envoie pas d'événements à l'avance. Les horodatages d'événements dans les profils et les intégrations peuvent afficher des dates futures car Apple envoie les événements de renouvellement à l'avance. - **Pourquoi cela se produit** : Apple fait cela pour s'assurer que les abonnements se renouvellent automatiquement avant leur expiration, évitant ainsi toute interruption de service pour les utilisateurs. Pour plus de détails, consultez le Forum des développeurs Apple : [Server Notifications for Subscriptions](https://developer.apple.com/forums/tags/app-store-server-notifications). - **Types d'événements concernés** : En général, cela s'applique aux renouvellements d'abonnements et aux conversions d'essai vers payant. Ces événements peuvent avoir des horodatages futurs car Apple en notifie les systèmes à l'avance. - **Autres types d'événements** : Les achats intégrés supplémentaires et les changements de plan d'abonnement sont enregistrés avec leurs horodatages réels car ces événements ne peuvent pas être prédits à l'avance. - **Impact sur les analyses et le flux d'événements** : Ces événements n'apparaîtront dans **Analytics** et dans le **Event Feed** qu'une fois leurs horodatages dépassés. Les événements avec des horodatages futurs ne sont affichés dans aucune de ces sections. - **Impact sur les intégrations** : Adapty envoie les événements aux intégrations dès leur réception. Si un événement a un horodatage futur, Adapty l'envoie à votre intégration avec l'horodatage futur inchangé. ## Étapes suivantes \{#next-steps\} - Pour utiliser le tableau de bord Profils afin de trouver et gérer les utilisateurs, consultez [Profils](profiles-crm). - Pour configurer l'identification des utilisateurs dans votre application, consultez le guide SDK [identification des utilisateurs](identifying-users). - Pour configurer la politique de partage d'accès, consultez [Partage de l'accès payant entre comptes utilisateurs](sharing-paid-access-between-user-accounts). --- # File: sharing-paid-access-between-user-accounts --- --- title: "Partage de l'accès payant entre comptes utilisateurs" description: "Partage de l'accès payant entre différents comptes utilisateurs pour les utilisateurs disposant de plusieurs appareils ou de plusieurs profils dans l'application" --- Lorsqu'un utilisateur effectue un achat, Adapty attribue un nouveau [niveau d'accès](access-level) à son [profil](identifying-users) actif. Ce niveau d'accès autorise l'acheteur à accéder au contenu payant. Le profil de l'acheteur peut changer par inadvertance s'il réinstalle votre application ou se connecte à un nouveau compte dans l'application. Pour garantir un accès ininterrompu, Adapty partage automatiquement le niveau d'accès de l'utilisateur entre le profil d'origine et les profils suivants. Cette approche convient à la plupart des applications. Mais si votre logique métier l'exige, vous pouvez choisir une politique de partage d'accès payant plus restrictive. Ouvrez la page [General Settings](https://app.adapty.io/settings/general) pour définir une politique de partage de niveau d'accès. Pour faciliter les tests, vous pouvez modifier ce paramètre uniquement pour [l'environnement sandbox](#sharing-paid-access-on-sandbox). <Details> :::important Si votre application n'authentifie pas les utilisateurs, vous pouvez ignorer ce paramètre. Les profils anonymes associés au même compte store *partagent toujours* leur niveau d'accès. ::: <summary>Quelle politique de partage d'accès choisir ? (Cliquez pour développer)</summary> | Mon application... | Meilleure option | | ------------------------------------------------------------ | ------------------------------------------------------------ | | N'a pas de fonctionnalité d'authentification et utilise uniquement les identifiants de profil anonymes d'Adapty. | Utilisez le paramètre **Enabled (default)**. | | Peut authentifier les utilisateurs, mais leur permet d'effectuer des achats sans compte. | Activez le paramètre **Transfer access to new user**. Les utilisateurs pourront s'inscrire et récupérer leurs achats anonymes. | | Exige la création d'un compte avant un achat, mais peut associer un seul produit à plusieurs Customer User IDs. | Activez le paramètre **Transfer access to new user**. Plusieurs comptes pourront accéder au produit, mais uniquement de façon séquentielle. | | Exige la création d'un compte avant un achat, avec des règles strictes liant les achats à un seul Customer User ID. | **Désactivez** le partage de niveau d'accès. | </Details> <img src="/assets/shared/img/sharing-paid-access.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Enabled (default) \{#enabled-default\} Ce paramètre convient le mieux aux applications **sans authentification intégrée**. Après l'achat, tous les profils associés au même compte store *héritent* automatiquement du niveau d'accès. * Si un utilisateur se connecte à votre application avec de nouveaux identifiants, il conserve l'accès au contenu payant. * Si un utilisateur réinstalle votre application après une réinitialisation d'usine, il conserve l'accès au contenu payant. * Si un utilisateur installe l'application sur d'autres appareils avec le même compte store, l'achat est disponible sur tous les appareils, même si chaque instance de l'application possède son propre profil client. ## Transfer access to new user \{#transfer-access-to-new-user\} Ce paramètre convient le mieux aux applications qui autorisent les achats **avec ou sans authentification**, ou qui souhaitent appliquer une politique **un appareil par utilisateur**. Adapty limite l'accès à un achat à 1 identifiant client à la fois. Le propriétaire de l'appareil peut réinstaller l'application, se connecter et se déconnecter, mais ne peut pas accéder au même produit depuis plus d'un identifiant client simultanément. Lorsque ce paramètre est activé, les profils anonymes (par exemple, un profil qui devient actif après la déconnexion de l'utilisateur) héritent toujours du niveau d'accès du dernier identifiant client actif. Cela est nécessaire pour éviter toute perte d'accès ultérieure. :::warning Lorsque vous désactivez le paramètre par défaut et activez **Transfer access to new user**, Adapty ne met pas immédiatement à jour les niveaux d'accès des profils clients existants. Le basculement se produit lorsqu'un utilisateur déclenche un nouvel événement store : par exemple, lors du renouvellement de l'abonnement ou de la restauration de ses achats. ::: :::important Adapty révoque l'ancien profil uniquement lorsque le nouveau profil possède un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) au moment où le SDK propage la transaction. Si `restorePurchases` s'exécute sur un profil anonyme, l'ancien Customer User ID et le nouveau profil anonyme se retrouvent tous deux avec le niveau d'accès. L'ancien profil est révoqué plus tard, lorsque vous identifiez le profil anonyme. Pour éviter cela, appelez les méthodes du SDK dans l'ordre : `activate` → `identify` → `restorePurchases`. ::: ## Désactiver le partage d'accès payant \{#disable-paid-access-sharing\} Ce paramètre est **uniquement adapté** aux applications avec une **authentification obligatoire** ou une implémentation indépendante de la gestion des accès. Dans les autres cas, les utilisateurs pourraient ne pas pouvoir accéder à leurs achats, et votre application risque **d'échouer à la vérification obligatoire du store**. Si vous désactivez le partage d'accès payant, Adapty lie le produit à l'[identifiant client](identifying-users#set-customer-user-id-on-configuration) actif au moment de l'achat et ne partage pas le niveau d'accès avec d'autres profils clients. Cette politique permet une distribution stricte du produit en 1 pour 1. :::warning Lorsque vous désactivez le partage d'accès payant, vous empêchez les identifiants clients d'hériter de l'accès payant. Si un identifiant client a hérité d'un accès payant par le passé, cela ne peut pas être révoqué automatiquement. ::: :::important En cas d'urgence, vous devrez peut-être [supprimer un profil utilisateur](api-adapty/operations/deleteProfile) pour que le prochain profil disponible (identifié ou anonyme) puisse revendiquer son niveau d'accès. ::: ## Référence pratique \{#practical-reference\} Une fois le mode choisi, les contrats ci-dessous décrivent ce à quoi s'attendre : quels profils voient l'accès, quand l'ancien profil le perd, et quels événements webhook se déclenchent. | Mode | Plusieurs profils partagent un même achat ? | Ancien profil révoqué lors du transfert ? | Quand l'ancien profil est révoqué | Événements webhook lorsqu'un second profil revendique l'abonnement | | --- | --- | --- | --- | --- | | **Enabled (default)** | Oui — chaque profil qui restaure ou se connecte hérite de l'accès | Jamais | N/A | `access_level_updated` (`is_active=true`) pour chaque nouveau profil qui hérite | | **Transfer access to new user** | Non — exclusif, mais transférable entre profils | Oui | Immédiatement lorsque le nouvel appareil identifié propage la transaction (`restorePurchases`, identify ou le prochain événement côté store) | Nouveau profil : `access_level_updated` (`is_active=true`). Ancien profil : `access_level_updated` (`is_active=false`) | | **Disabled** | Non — un Customer User ID par achat, de façon permanente | N/A — l'accès n'est jamais transféré | N/A | Aucun pour le second profil. Le SDK n'affiche aucun accès pour celui-ci | ## Partage de l'accès payant en sandbox \{#sharing-paid-access-on-sandbox\} Vous pouvez définir une politique de partage d'accès payant spécifiquement pour l'environnement sandbox. Lorsque vous testez des achats dans l'environnement sandbox, attendez-vous au comportement suivant : * Apple stocke les informations sur vos achats passés dans l'historique d'achats du compte. Le SDK Adapty peut également y accéder. * Si vous réinstallez l'application et qu'Adapty détecte que le produit a déjà été acheté, le profil actif héritera du niveau d'accès. * Si Apple détecte un achat existant pour le produit, il ne vous permettra pas d'effectuer le même achat deux fois, même si le profil actif ne possède pas le niveau d'accès nécessaire. Ce comportement se produit **indépendamment de votre paramètre de partage d'accès payant**. Votre application n'affiche pas le paywall, vous ne pouvez pas acheter le produit. La seule solution est de **vider l'historique d'achats de votre compte**. Suivez le [guide de test sandbox](test-purchases-in-sandbox) pour des instructions détaillées. :::warning Les abonnements sandbox sur Apple se renouvellent automatiquement toutes les quelques minutes. Ces renouvellements rapides peuvent modifier quel profil Adapty considère comme [parent](how-profiles-work#parent-and-inheritor-profiles) — un comportement en chaîne que la production reproduit rarement. Testez le mode que vous utilisez en production et confirmez le comportement avec un vrai Apple ID avant de tirer des conclusions à partir du sandbox. ::: ## Partage de l'accès payant dans les analyses \{#paid-access-sharing-in-analytics\} * Adapty enregistre les transactions au fur et à mesure qu'elles se produisent. Une seule transaction peut être associée à plusieurs profils, mais n'est comptabilisée qu'une seule fois. * Si deux profils ou plus partagent le même niveau d'accès, l'achat est attribué au [profil parent](how-profiles-work#parent-and-inheritor-profiles). * L'héritage du niveau d'accès n'a pas d'impact sur les statistiques d'installation. Pour déterminer comment Adapty comptabilise les installations, vous pouvez sélectionner l'une des deux [définitions d'installation](installs#counting-modes) disponibles sur la page des paramètres. --- # File: segments --- --- title: "Segments" description: "Créez et gérez des segments d'utilisateurs pour un meilleur ciblage dans Adapty." --- Un **segment** est un ensemble de filtres qui regroupe les utilisateurs ayant des propriétés communes. Utilisez les segments pour cibler les paywalls et les tests A/B de façon plus précise. :::note Les événements du flux d'événements arrivent sur le tableau de bord avec un léger délai. Les nouveaux profils et les modifications d'attributs peuvent ne pas être visibles immédiatement. ::: Une fois un segment créé, vous pouvez [l'utiliser comme **audience** dans les placements et les tests A/B](audience) pour contrôler quel paywall est affiché aux utilisateurs (simple ou multiple). Exemples : - Afficher un paywall standard aux non-abonnés et proposer une réduction aux utilisateurs qui ont déjà annulé un abonnement ou un essai. - Afficher des paywalls différents aux utilisateurs selon leur pays. - Cibler les utilisateurs en fonction des données d'attribution Apple Search Ads. - S'assurer que les utilisateurs sur des versions plus anciennes de l'app continuent de voir le paywall existant, tandis que les versions plus récentes affichent la version mise à jour. - [Dans Analytics](controls-filters-grouping-compare-proceeds#filter-and-group-data), filtrer par segments pour consulter les performances de groupes d'utilisateurs spécifiques. Groupez par segment pour comparer les performances ou la contribution au sein de **All users**. <img src="/assets/shared/img/3244407-Segments.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Création \{#creation\} Pour créer un segment, saisissez un nom et sélectionnez les attributs qui définissent ses filtres. Lorsque vous sélectionnez plusieurs attributs, les utilisateurs doivent correspondre à toutes les conditions. Adapty applique une logique ET entre les attributs. <img src="/assets/shared/img/1af9744-new_cohort.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Attributs disponibles \{#available-attributes\} :::note Si de nombreux attributs utilisateur sont définis automatiquement (comme **Country** ou **Calculated total revenue USD**), **Age**, **App user ID**, les données **Attribution**, **Gender** et les **Custom attributes** ne le sont pas. Vous devez [définir les attributs utilisateur](setting-user-attributes) ou [transmettre les données d'attribution](attribution-integration) si vous souhaitez les utiliser pour la segmentation. ::: :::tip Pour les attributs de type date, vous pouvez filtrer avec : - **Date fixe** : sélectionnez des dates précises dans un calendrier (par exemple, afficher une offre spéciale aux utilisateurs ayant installé l'app entre le Black Friday et le Cyber Monday). - **Plage relative** : définissez des fenêtres temporelles dynamiques comme « 7 derniers jours » ou « 3 derniers mois » (par exemple, réengager les utilisateurs dont la dernière connexion remonte à plus de 30 jours, ou cibler les installations récentes). Les plages relatives se mettent à jour automatiquement, ce qui les rend idéales pour les campagnes en continu. Les dates fixes conviennent mieux aux promotions à durée limitée. ::: | Attribut | Filtrer par | |---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Age** | L'âge de l'utilisateur. Notez que l'âge est calculé lors de la première réception par Adapty et n'est pas mis à jour par la suite. | | **App User ID** | L'identifiant de l'utilisateur dans votre app ([customer_user_id](profiles-crm#user-attributes)). Vous pouvez filtrer selon sa présence ou son absence, par exemple pour afficher un paywall uniquement aux utilisateurs qui ne se sont pas connectés. | | **App version (current)** | La version actuelle de l'app installée sur l'appareil de l'utilisateur où Adapty a reçu les dernières données d'événement — **mise à jour à chaque montée de version**, elle reflète donc toujours ce que l'utilisateur utilise en ce moment. Utilisez-la lors d'un déploiement vers tous les utilisateurs d'une version spécifique, y compris ceux qui l'ont obtenue par mise à jour. Pour créer un segment, cliquez sur l'icône crayon à côté de **App version** et ajoutez une nouvelle version pour pouvoir l'utiliser immédiatement.<br/> La condition **version > X.X** permet de mesurer l'impact sur la conversion de toutes les versions d'app antérieures ou postérieures à une version donnée, sans avoir à les lister individuellement.<br/><br/> **Format :** les chaînes de version doivent respecter le format [SemVer](https://semver.org/). Les zéros non significatifs dans n'importe quelle partie sont invalides — `26.03.4` ne correspondra pas, alors que `26.3.4` oui. Les versions invalides sont silencieusement exclues du segment. | | **App version (on install)** | La version de l'app installée sur l'appareil de l'utilisateur lors de la première réception de données d'événement par Adapty — **figée à cette installation et jamais mise à jour**, même après une montée de version. Utilisez-la pour cibler les utilisateurs selon la version qu'ils ont installée à l'origine, et non leur version actuelle. `App version (on install) = 1.5.7` ne correspond qu'aux utilisateurs dont la première installation était la 1.5.7 et exclut silencieusement ceux qui ont mis à jour vers la 1.5.7 depuis une version antérieure — pour capturer également les utilisateurs ayant mis à jour, utilisez **App version (current)**.<br/><br/> **Format :** les chaînes de version doivent respecter le format [SemVer](https://semver.org/). Les zéros non significatifs dans n'importe quelle partie sont invalides — `26.3.04` ne correspondra pas, alors que `26.3.4` oui. Les versions invalides sont silencieusement exclues du segment. | | **Attribution: Ad Group** | Le groupe d'annonces de l'attribution. | | **Attribution: Ad Set** | L'ensemble d'annonces de l'attribution. | | **Attribution: Campaign** | Le nom de la campagne marketing. | | **Attribution: Creative** | Le mot-clé créatif de l'attribution. | | **Attribution: Channel** | Le nom du canal marketing. | | **Attribution: Source** | L'origine de l'attribution. | | **Attribution: Status** | Le statut de l'attribution. Valeurs possibles : <ul><li> **Organic** – L'utilisateur a installé l'app sans influence de marketing payant (par exemple, recherche directe dans l'App Store/Google Play, bouche-à-oreille ou portée organique sur les réseaux sociaux).</li><li> **Non-organic** – L'utilisateur a été acquis via un canal marketing payant (par exemple, publicités, campagnes d'influenceurs, programmes de parrainage).</li><li> **Unknown** – Aucune donnée d'attribution n'est disponible pour cet utilisateur.</li></ul> | | **Calculated subscription state** | Le [statut d'abonnement actuel](profiles-crm#subscription-state) de l'utilisateur, indiquant si l'abonnement est actif, annulé ou si un problème de facturation non résolu est en cours. | | **Calculated total revenue USD** | Le revenu total généré par cet utilisateur. | | **Country** | Le pays du client, déterminé par son adresse IP la plus récente. Adapty actualise le signal IP au plus une fois par semaine, ce qui peut entraîner un décalage si l'utilisateur change de lieu ou utilise un VPN. Pour cibler le pays du compte App Store / Play Store de l'utilisateur, utilisez **Country from store account**. | | **Country from store account** | Le pays associé au compte iOS ou Android store de l'utilisateur. Notez qu'Adapty ne collecte le pays du store que pour les appareils iOS sous la version 13 ou ultérieure. | | **Creation date** | La date de création du profil (lorsque l'app a été installée pour la première fois sur l'appareil de l'utilisateur). | | **Device** | Le type d'appareil basé sur les métadonnées. Par exemple, « Samsung Galaxy » ou « iPhone 13 ». | | **Gender** | Le genre de l'utilisateur. Notez que vous définissez vous-même cette valeur. | | **Installation date** | La date à laquelle l'utilisateur a installé l'app. | | **Language** | La langue de l'appareil de l'utilisateur. <Callout type="warning">Adapty stocke la langue sous forme de code `ISO 639-1` à 2 lettres. N'utilisez pas de locales étendues comme `zh-Hant-TW` ou `pt-BR`. Elles peuvent apparaître dans la liste déroulante mais ne correspondent à aucun utilisateur.</Callout> <Callout type="tip">Pour affiner encore le ciblage par langue, combinez **Language** avec **Country**. Par exemple, **Chinois simplifié (`zh`)** + **Country = TW, HK, MO** cible les utilisateurs de l'écriture chinoise traditionnelle.</Callout> | | **Last seen** | La dernière date à laquelle l'utilisateur a ouvert l'app. | | **OS** | La version du système d'exploitation de l'appareil de l'utilisateur. | | **Paid access level** | Le niveau d'accès accordé à l'utilisateur. | | **Platform** | La plateforme de l'appareil de l'utilisateur. Valeurs possibles : `iOS`, `macOS`, `iPadOS`, `visionOS`, `Android`. <br/> Si des utilisateurs accèdent à votre app depuis plusieurs plateformes (par exemple iOS et Android), l'appartenance au segment est évaluée séparément pour chaque plateforme en utilisant les données les plus récentes de cet appareil spécifique. Cela permet un ciblage par plateforme même pour un même profil utilisateur. | | **Subscription expiration date** | La date d'expiration de l'abonnement ou sa présence/absence. Affiche `none` pour les achats à vie et reste vide si l'utilisateur possède un profil mais n'a jamais eu d'essai, d'abonnement ou d'achat à vie. | | **Subscription product** | L'identifiant du dernier produit de l'abonnement actif du client. | | **[Custom attributes](profiles-crm#custom-attributes)** | Définissez vos propres attributs pour créer des segments très ciblés basés sur des propriétés spécifiques à votre app ou à votre activité. | ## Attributs personnalisés \{#custom-attributes\} Définissez des attributs personnalisés pour construire des segments plus ciblés basés sur des propriétés propres à votre app ou à votre activité. :::note - Vous pouvez configurer des attributs personnalisés dans le SDK ou dans l'Adapty Dashboard. Pour la configuration via le SDK, suivez les instructions [ici](setting-user-attributes#custom-user-attributes). - Modifier un attribut personnalisé après son utilisation dans un segment peut désynchroniser l'utilisateur de ce segment dans [analytics](controls-filters-grouping-compare-proceeds#filter-and-group-data). Les données refléteront l'ancienne valeur. ::: ### Comment configurer un attribut personnalisé \{#how-to-configure-a-custom-attribute\} Dans l'Adapty Dashboard, sélectionnez **Create custom attributes** dans le menu déroulant des attributs. <img src="/assets/shared/img/883d3b2-CleanShot_2023-03-16_at_17.20.452x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> | Champ | Description | | ------ |--------------------------------------------------------------------------------------------------------------------------------------| | **Name** | Un libellé pour l'attribut personnalisé, utilisé uniquement dans l'Adapty Dashboard. | | **Key** | Un identifiant unique pour l'attribut. Il doit correspondre à la clé utilisée dans le SDK. | | **Type** | Choisissez entre :<ul><li>String : nécessite une liste prédéfinie de valeurs possibles.</li><li>Number : accepte uniquement des valeurs numériques.</li></ul> | | **Values** | Si vous sélectionnez `String`, saisissez la liste des valeurs possibles. Si vous choisissez `Number`, l'attribut n'acceptera que des valeurs numériques. Les attributs numériques prennent en charge les valeurs décimales et peuvent être utilisés avec des opérateurs de comparaison. | Une fois les champs requis remplis, vous pouvez utiliser les attributs personnalisés dans vos segments, [tests A/B](ab-tests) et plus encore. Chaque profil peut avoir jusqu'à 30 attributs personnalisés. ## Nombre total et échantillon aléatoire \{#total-number-and-random-sample\} Après la création d'un segment, Adapty affiche le nombre total d'utilisateurs correspondant aux critères du segment. Adapty affiche également un échantillon aléatoire de 40 utilisateurs répondant aux critères. Utilisez-le pour tester votre segment et vérifier qu'il est correctement configuré. <img src="/assets/shared/img/segment-random-set.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Dupliquer des segments \{#duplicate-segments\} Si vous avez besoin d'un segment similaire à un segment existant, dupliquez-le plutôt que de le recréer de zéro. Cela fait gagner du temps aux équipes qui gèrent plusieurs campagnes ou tests A/B avec des groupes d'utilisateurs similaires. La duplication d'un segment crée une copie avec tous ses filtres et sa description. Le nouveau segment aura « (copy) » ajouté à son nom pour le distinguer de l'original. Le nouveau segment est indépendant de l'original. Les modifications apportées à l'un n'affectent pas l'autre. Pour dupliquer un segment dans l'Adapty Dashboard : 1. Ouvrez la section **Profiles & Segments** dans le menu principal d'Adapty et basculez vers l'onglet [**Segments**](https://app.adapty.io/segments). 2. Cliquez sur le bouton **3 points** à côté du segment et sélectionnez **Duplicate**. <img src="/assets/shared/img/duplicate-segment.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Ouvrez le nouveau segment et ajustez ses filtres selon vos besoins. ## Supprimer des segments \{#delete-segments\} Lorsque vous n'avez plus besoin d'un segment, vous pouvez le supprimer définitivement. Adapty bloque la suppression si le segment est actuellement utilisé comme audience par l'un des éléments suivants : - **Un placement** : au moins un placement non supprimé utilise le segment comme audience. - **Un test A/B (En cours ou Terminé)** : au moins un test A/B non supprimé utilise le segment comme audience. Pour la suppression d'un segment, Adapty considère les tests A/B **En cours** et **Terminés** comme actifs. Un test terminé utilise toujours l'audience pour afficher le paywall ou l'onboarding post-test aux utilisateurs correspondants, et les métriques historiques du test sont limitées à ce segment. Le segment n'est libéré que lorsque le test A/B lui-même est supprimé. :::warning La suppression d'un segment est définitive. Le segment ne peut pas être restauré. ::: Pour supprimer un segment dans l'Adapty Dashboard : 1. Accédez à **Profiles & Segments** dans le menu principal d'Adapty et basculez vers l'onglet [**Segments**](https://app.adapty.io/segments). 2. Cliquez sur le bouton **3 points** à côté du segment et sélectionnez **Delete**. 3. Saisissez le nom du segment dans le champ de confirmation, puis cliquez sur **Delete forever**. :::info Si le segment est en cours d'utilisation, la boîte de dialogue liste les placements et les tests A/B qui y font référence. Pour débloquer la suppression, ouvrez chaque placement ou test A/B de la liste et supprimez le segment de son audience, ou supprimez le placement ou le test A/B entièrement. Une fois qu'aucun élément ne référence le segment, vous pouvez le supprimer. ::: --- # File: event-feed --- --- title: "Fil d'événements" description: "Surveillez et analysez l'activité des utilisateurs avec le fil d'événements d'Adapty." --- Le fil d'événements vous permet de suivre visuellement les [événements](events) générés par Adapty et de vérifier le statut de leur export vers des intégrations tierces, y compris le webhook. :::warning Le fil d'événements n'affiche pas : - **Les transactions de l'API server-side v1** : créées via l'[API server-side (version 1)](server-side-api-specs-legacy#requests). Utilisez l'[API server-side (version 2)](api-adapty/operations/setTransaction) pour qu'elles apparaissent. - **Les événements sans profil** : les transactions arrivées avant que le SDK n'ait identifié un utilisateur — par exemple, les notifications server du store. Pour les inclure dans les exports, activez **Include events without profile** dans l'intégration [S3](s3-exports) ou [Google Cloud Storage](google-cloud-storage). ::: <img src="/assets/shared/img/event-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note Le statut d'envoi vers AppsFlyer, Facebook Ads et Branch peut être inexact, car ces services ne renvoient pas toujours d'erreur lorsqu'il s'en produit une. ::: Pour consulter le profil de l'utilisateur qui a initié la transaction, cliquez sur le bouton **View Profile** dans les détails de l'événement. --- # File: retention-messaging --- --- title: "Messages de rétention" description: "Affichez un message personnalisé aux abonnés sur l'écran d'annulation d'abonnement d'Apple. Créez et localisez des messages de rétention dans Adapty — sans backend, sans mise à jour de l'application." --- [Retention Messaging](https://developer.apple.com/documentation/retentionmessaging) est une fonctionnalité Apple qui affiche un message personnalisé aux abonnés sur l'écran iOS **Cancel Subscription**, juste avant qu'ils confirment leur annulation. Utilisez-la pour réduire le churn en leur donnant une raison — ou une offre — de rester. Adapty se connecte à l'API Retention Messaging d'Apple, afin qu'Apple demande le bon message en temps réel dès qu'un abonné appuie sur **Cancel Subscription**. Adapty gère cet endpoint pour vous : vous rédigez, localisez et testez vos messages dans l'Adapty Dashboard, et Adapty répond automatiquement à Apple. Aucun backend à construire, aucune mise à jour de l'app nécessaire. Il existe deux types de messages. Un message *par défaut* est un texte générique qui s'applique à tous les abonnés d'un produit. Un message *promo* ajoute une incitation concrète : une réduction, un essai gratuit ou un passage à un plan plus adapté. Apple affiche à chaque abonné le message correspondant à son produit et à sa langue. <CustomDocCardList ids={['retention-messaging-setup', 'retention-messaging-create']} /> ## Démarrage rapide \{#quickstart\} Avant de commencer, vous avez besoin de : - Un accès au [programme Apple Retention Messaging](https://developer.apple.com/documentation/retentionmessaging). - Une [clé API App Store Connect](app-store-connection-configuration) dans Adapty. Ensuite : 1. [Connectez Adapty à l'API Retention Messaging en mode sandbox](retention-messaging-setup). 2. Effectuez un achat parmi vos produits en mode sandbox, afin que le test de connectivité ait une transaction à utiliser. 3. Réussissez le test de connectivité d'Apple. 4. Passez en mode production. 5. [Créez vos messages de production](retention-messaging-create) — d'abord les messages par défaut, puis les messages promotionnels — et soumettez chacun d'eux à la validation d'Apple. --- # File: retention-messaging-setup --- --- title: "Configurer la messagerie de rétention" description: "Connectez Adapty à la messagerie de rétention d'Apple : configurez-la en sandbox, réussissez le test de performance d'Apple, puis passez en production." --- Avant que vos abonnés puissent voir vos messages de rétention, Apple a besoin d'un moyen de contacter Adapty lorsque quelqu'un annule. Cet article explique comment configurer cette connexion — d'abord en mode sandbox, puis en production. ## Avant de commencer \{#before-you-begin\} - Ajoutez une [clé API App Store Connect](app-store-connection-configuration) à Adapty. Adapty l'utilise pour enregistrer l'URL en temps réel et communiquer avec Apple. - Demandez l'accès au [programme Apple Retention Messaging](https://developer.apple.com/documentation/retentionmessaging) et attendez l'approbation d'Apple. Sans approbation, Apple rejette la connexion. ## Configuration du sandbox \{#sandbox-setup\} Apple vous demande de tester la connexion dans un environnement sandbox d'abord, afin que vous puissiez vérifier sa fiabilité avant d'envoyer des messages en production. ### Configurer l'URL Sandbox \{#configure-sandbox-url\} Cliquez sur **Configure Sandbox URL** pour démarrer la configuration. Adapty connecte votre compte App Store Connect à son propre endpoint en temps réel. Si une autre URL est déjà définie dans App Store Connect, le bouton affiche **Replace URL** à la place. Une fois la connexion établie, Adapty confirme avec « Sandbox URL has been configured. » ### Tester la connexion \{#test-the-connection\} Avant d'envoyer des messages en production, Apple effectue un test pour confirmer qu'Adapty répond rapidement à ses requêtes. 1. Effectuez un achat avec l'un de vos produits via [un compte sandbox](test-purchases-in-sandbox). Le test nécessite une transaction à annuler. 2. Cliquez sur **Start Test**. Le test prend quelques minutes et vous pouvez le relancer en cas d'échec. ## Passer en mode production \{#switch-to-production\} Une fois l'environnement sandbox configuré, Adapty vous permet de désactiver le bouton **Sandbox mode** pour passer en mode production. Cliquez sur **Configure URL**. Adapty enregistre son endpoint auprès d'Apple pour la production et confirme avec « Production URL has been configured. » Si une URL de production différente est déjà définie dans App Store Connect, cliquez plutôt sur **Replace URL**. ## Étapes suivantes \{#next-steps\} - [Créer un message de rétention](retention-messaging-create) que les abonnés voient lorsqu'ils annulent. --- # File: retention-messaging-create --- --- title: "Créer un message de rétention" description: "Créez des messages de rétention par défaut et promotionnels dans Adapty. Rédigez le contenu, ajoutez une offre ou un changement de plan, localisez-le et soumettez-le à la revue d'Apple." --- Les messages de rétention vous permettent de contacter les abonnés sur le point de se désabonner pendant le processus d'annulation. Lorsqu'un client atteint l'écran iOS Annuler l'abonnement, Apple lui affiche le message correspondant à son produit et à sa langue. Il existe deux types de messages de rétention : - **Default** : Un message de reconquête simple avec un titre, un corps de texte et une image facultative. Utilisé comme solution de secours lorsqu'aucun message promo n'est disponible. - **Promo** : Un message de reconquête qui propose aux abonnés une offre spéciale ou un plan différent. Vous ne pouvez créer des messages promo que pour des produits auxquels un message Default est déjà assigné. ## Avant de commencer \{#before-you-begin\} - Créez au moins un [produit](create-product) que le message doit couvrir. - [Testez la messagerie de rétention](retention-messaging-setup) en mode sandbox. ## Créer un message \{#create-a-message\} Ouvrez la page Retention Messaging dans l'Adapty Dashboard. Cliquez sur **Create Default** pour un message par défaut, ou sur **Create Message** pour un message promotionnel. Sélectionnez l'environnement : un message sandbox pour les tests, ou un message de production pour les vrais utilisateurs. ### Général \{#general\} Nommez le message et ajoutez les produits dont l'annulation déclenchera le message. Pour un message de type **promo**, configurez l'incentive qui persuadera l'abonné de rester : - **Promo offer** : une offre promotionnelle que vous avez [configurée au préalable pour le produit](app-store-offers). - **Plan switch** : Un produit différent de votre catalogue. ### Contenu \{#content\} Rédigez le message en anglais. Un aperçu sur la droite affiche le message sur l'écran d'annulation d'abonnement au fur et à mesure de votre saisie. Le message **Default** peut inclure une image. ### Localisation \{#localization\} L'anglais est la langue source. Ajoutez les autres langues utilisées par vos abonnés, puis traduisez le contenu. 1. Cliquez sur **Add Locale** et choisissez les paramètres régionaux à prendre en charge. 2. Cliquez sur **AI Translate All Cells** pour traduire automatiquement le [contenu](#content). 3. Cliquez sur une cellule pour modifier une traduction. Survolez un paramètre régional pour le prévisualiser sur l'écran d'annulation d'abonnement. ## Soumettre pour révision \{#submit-for-review\} Lorsque le message est prêt, cliquez sur **Submit To Review**. Apple l'examine, et le statut passe à **In review**, puis **Live** ou **Rejected**. Le message est mis en ligne pour les utilisateurs en production dès qu'Apple approuve au moins une locale. :::note Apple approuve chaque locale séparément. Les abonnés voient votre message uniquement dans les locales approuvées — il n'y a pas de repli automatique vers l'anglais. ::: --- # File: ab-tests --- --- title: "Test A/B" description: "Optimisez les prix de vos abonnements avec les tests A/B dans Adapty pour de meilleurs taux de conversion." --- :::tip Vous pouvez obtenir un plan de test A/B directement actionnable sans faire de recherche vous-même. [AI Growth Advisor](autopilot) audite votre paywall, analyse vos concurrents et génère des suggestions à partir de données anonymisées issues de 20 000 apps d'abonnement suivies par Adapty. ::: Boostez les revenus de votre app en lançant des tests A/B dans Adapty. Comparez différents flows, paywalls et onboardings pour trouver ce qui convertit le mieux — sans modifier votre code. Par exemple, vous pouvez tester : - Les prix des abonnements - Le design, les textes et la mise en page des paywalls - Les périodes d'essai et les durées d'abonnement - Les designs d'onboarding ## Prérequis \{#prerequisites\} Avant de configurer un test A/B, vous devez disposer de : - **Placements** : Un ou plusieurs [placements](placements) où un flow, un paywall ou un onboarding est affiché. - **Pour les flows** : Au moins deux [flows](adapty-flow-builder). - **Pour les paywalls** : Au moins deux [paywalls](paywalls). - **Pour les onboardings** : Au moins deux [onboardings](onboardings). :::warning Si vous n'utilisez pas [Adapty Flow builder](adapty-flow-builder) ni [Adapty Paywall builder](adapty-paywall-builder), [envoyez les vues de paywall à Adapty](present-remote-config-paywalls#track-paywall-view-events) avec `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. Sans cette méthode, Adapty ne peut pas comptabiliser les vues de paywall dans le test, et les statistiques de conversion seront inexactes. ::: ## Types de tests A/B \{#ab-test-types\} Adapty prend en charge deux grands types de tests A/B : - **Classique** : S'exécute sur un seul placement de flow/paywall/onboarding. - **Crossplacement** : S'exécute sur plusieurs placements de paywalls et affiche la même variante à un utilisateur partout. Disponible uniquement pour les paywalls pour l'instant. Pour une comparaison complète des types, des cas d'usage et des règles de priorité, consultez [Types de tests A/B](ab-test-types). ## Étapes suivantes \{#next-steps\} - [AI Growth Advisor](autopilot) — Analysez votre paywall, obtenez des insights marché et générez un plan de test A/B - [Types de tests A/B](ab-test-types) — Découvrez les types de tests et quand utiliser chacun - [Créer, lancer et arrêter un test A/B](run_stop_ab_tests) — Configurez et lancez votre premier test - [Résultats et métriques des tests A/B](results-and-metrics) — Comprenez vos données de test A/B et choisissez un gagnant --- # File: ab-test-types --- --- title: "Types de tests A/B" description: "Découvrez les types de tests A/B dans Adapty." --- Adapty propose deux types de tests A/B, chacun adapté à des scénarios différents : - **Test A/B classique :** Un test A/B créé pour un seul placement de [flow](adapty-flow-builder)/[paywall](paywalls)/[onboarding](onboardings). - **Test A/B crossplacement :** Un test A/B créé pour plusieurs placements de paywalls dans votre application. Une fois que le test A/B attribue une <InlineTooltip tooltip="variante">Les variantes d'un test A/B sont des versions alternatives du flow, du paywall ou de l'onboarding à tester.</InlineTooltip>, il affiche cette variante de manière cohérente dans toutes les sections sélectionnées de votre application. :::warning Les tests A/B crossplacement sont uniquement disponibles pour les SDKs Adapty à partir de la version 3.5.0. Les tests A/B crossplacement fonctionnent uniquement avec des paywalls. Les tests A/B de flow nécessitent le SDK Adapty v4.0.0+. Les tests A/B d'onboarding nécessitent le SDK Adapty v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity) ou v3.15.0+ (Kotlin Multiplatform, Capacitor). Les utilisateurs des versions précédentes les ignorent. ::: Chaque flow/paywall/onboarding reçoit un poids qui répartit le trafic pendant le test. Par exemple, avec des poids de 70 % et 30 %, le premier paywall est affiché à environ 700 utilisateurs sur 1 000, le second à environ 300. Dans les tests crossplacement, les poids sont définis par variante, et non par paywall. Cette configuration vous permet de comparer différents flows et paywalls, et de prendre des décisions basées sur les données pour la stratégie de monétisation de votre application. ## Quand utiliser chaque type \{#when-to-use-each-type\} Chaque type de test A/B est utile si : - **Tests A/B classiques** : - Votre application ne contient qu'un seul placement. - Vous souhaitez exécuter votre test A/B sur un seul placement et suivre les changements économiques pour ce placement uniquement, même si votre application comporte plusieurs placements. - Vous souhaitez exécuter un test A/B sur les anciens utilisateurs (ceux qui ont déjà vu au moins un paywall Adapty). - **Test A/B crossplacement** : - Vous souhaitez synchroniser les variantes sur plusieurs placements. Par exemple, vous pourriez modifier les prix dans le flow d'onboarding et dans les paramètres de votre application en même temps. - Vous souhaitez évaluer l'économie globale de votre application. Exécuter le test sur tous les placements rend les statistiques du test A/B plus faciles à analyser que de tester des placements isolés. - Vous souhaitez exécuter un test A/B uniquement sur les nouveaux utilisateurs, c'est-à-dire ceux qui n'ont jamais vu un seul paywall Adapty. - Vous souhaitez utiliser plusieurs paywalls au sein d'une seule variante : <img src="/assets/shared/img/ab-test-variants.png" alt="Exemple de plusieurs paywalls au sein d'une seule variante de test A/B crossplacement" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Principales différences \{#key-differences\} | Fonctionnalité | Test A/B classique | Test A/B crossplacement | | ------------------------------- |--------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| | **Ce qui est testé** | Un flow/paywall/onboarding | Ensemble de paywalls appartenant à une variante | | **Cohérence des variantes** | La variante est déterminée séparément pour chaque placement | La même variante est utilisée sur tous les placements de paywalls | | **Ciblage d'audience** | Défini par placement de flow/paywall/onboarding | Partagé sur tous les placements de paywalls | | **Analytique** | Vous analysez un placement de flow/paywall/onboarding | Vous analysez l'ensemble de l'application sur les placements faisant partie du test | | **Répartition du poids des variantes** | Par flow/paywall/onboarding | Par ensemble de paywalls | | **Utilisateurs** | Pour tous les utilisateurs | Uniquement les nouveaux utilisateurs (ceux qui n'ont pas vu de paywall Adapty) | | **Version du SDK Adapty** | Pour les flows : v4.0.0+. Toute version pour les paywalls. Pour les onboardings : v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity), v3.15.0+ (KMP, Capacitor) | 3.5.0+ | | **Idéal pour** | Tester des modifications indépendantes dans un seul placement de flow/paywall/onboarding sans tenir compte de l'économie globale de l'application | Évaluer les stratégies de monétisation globales à l'échelle de l'application | ## Logique de sélection du test A/B \{#ab-test-selection-logic\} **Les tests A/B crossplacement ont la priorité sur les tests A/B classiques.** Cependant, les tests crossplacement ne sont affichés qu'aux **nouveaux utilisateurs** — ceux qui n'ont encore vu aucun paywall Adapty (la méthode SDK `getPaywall` n'a jamais été appelée pour eux). Cela garantit la cohérence des résultats sur l'ensemble des placements. Le diagramme suivant illustre la logique qu'Adapty utilise pour sélectionner un test A/B pour un placement : <img src="/assets/shared/img/ab-tests-scheme.webp" alt="Diagramme illustrant la logique de sélection du test A/B pour un placement de paywall" style={{ border: '1px solid #727272', /* border width and color */ width: '350px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Sur la page **A/B Tests**, les tests de paywall, d'onboarding, de flow et les tests crossplacement apparaissent dans des onglets séparés. <img src="ab-tests-tabs.webp" alt="Page de liste des tests A/B avec des onglets pour les types de tests Classique, Onboarding et Crossplacement" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Limitations des tests A/B crossplacement \{#crossplacement-ab-test-limitations\} :::warning Les tests A/B crossplacement ne peuvent pas inclure de placements de flow ou d'onboarding. ::: Les tests A/B crossplacement garantissent que chaque utilisateur voit la même variante sur tous les placements du test. Cela entraîne les limitations suivantes : * Seuls les nouveaux utilisateurs peuvent participer. Un nouvel utilisateur est celui qui n'a pas vu de paywall Adapty et dont l'application n'a jamais appelé `getPaywall`. Adapty ne peut pas garantir une chaîne de paywalls cohérente pour les autres utilisateurs. * Le premier placement que l'utilisateur rencontre détermine le paywall qu'Adapty affiche. Vous ne pouvez pas modifier l'attribution d'un utilisateur ni inscrire le même utilisateur dans plus d'un test A/B crossplacement. :::warning Une fois qu'un utilisateur reçoit un paywall crossplacement, il le voit pendant 90 jours, même après l'arrêt du test. Pour modifier cette durée, dans les paramètres **General**, ajustez **[Cross-placement variation stickiness](general#9-cross-placement-variation-stickiness)**. ::: ## Priorité des tests A/B crossplacement \{#crossplacement-ab-test-priority\} * Les tests A/B crossplacement ont toujours la priorité sur les tests A/B classiques et les tests d'onboarding. Si un nouvel utilisateur est éligible à la fois à un test crossplacement et à un test classique sur le même placement, c'est le test crossplacement qui est affiché. * Lorsque plusieurs tests A/B crossplacement avec la même audience partagent le même placement, Adapty attribue automatiquement la priorité des tests selon l'ordre dans lequel ils ont été ajoutés. Le premier test obtient la priorité la plus élevée. Vous ne pouvez pas la modifier manuellement. * Les tests ciblant des segments plus restreints de votre audience obtiennent automatiquement la priorité sur ceux qui ciblent le segment Tous les utilisateurs. :::note Dans Analytics, un test A/B crossplacement apparaît sous la forme de plusieurs tests enfants, un par placement. Les tests enfants suivent le schéma de nommage `<test-name> child-0`, `<test-name> child-1`, et ainsi de suite. La numérotation correspond à l'ordre des placements sur la page de détails du test A/B. Pour afficher les résultats d'un placement spécifique, filtrez par **Placement**. ::: ## Étapes suivantes \{#next-steps\} - [Créer, exécuter et arrêter un test A/B](run_stop_ab_tests) — Configurez et lancez votre premier test - [Résultats et métriques du test A/B](results-and-metrics) — Analysez les performances et choisissez un gagnant --- # File: run_stop_ab_tests --- --- title: "Créer, lancer et arrêter un test A/B" description: "Guide étape par étape pour créer, lancer et arrêter des tests A/B dans Adapty." --- Cet article couvre le cycle de vie complet d'un test A/B dans Adapty : créer un test, le lancer et l'arrêter lorsque vous êtes prêt à analyser les résultats. ## Prérequis \{#prerequisites\} Avant de configurer un test A/B, vous devez disposer de : - Au moins deux [flows](adapty-flow-builder)/[paywalls](paywalls)/[onboardings](onboardings) créés - Un [placement](placements) configuré dans votre application :::warning Si vous n'utilisez pas le [Adapty Flow builder](adapty-flow-builder) ni le [Adapty Paywall builder](adapty-paywall-builder), [envoyez les vues de paywall à Adapty](present-remote-config-paywalls#track-paywall-view-events) avec `.logShowPaywall()`. Sans cette méthode, Adapty ne peut pas calculer les vues de paywall dans le test, et les statistiques de conversion seront inexactes. ::: :::info Les tests A/B dans Adapty suivent un processus en deux étapes. Vous créez d'abord un test et l'enregistrez en tant que brouillon — il ne se lance pas immédiatement. Quand vous êtes prêt, vous le lancez séparément. Cela vous permet de vérifier la configuration avant que les utilisateurs ne le voient. ::: ## Créer un test A/B \{#create-an-ab-test\} Lors de la création d'un nouveau test A/B, vous devez inclure au moins deux [flows](adapty-flow-builder)/[paywalls](paywalls)/[onboardings](onboardings). Pour créer un nouveau test A/B : 1. Accédez à [A/B tests](ab-tests) depuis le menu principal d'Adapty. <img src="/assets/shared/img/go-to-abtests.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. En haut à droite, cliquez sur **Create A/B test**. <img src="/assets/shared/img/create-abtest.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Create the A/B test**, saisissez un **Test name**. Ce champ est obligatoire. Choisissez un nom qui décrit clairement l'objet du test afin de pouvoir l'identifier lors de l'analyse des résultats. 4. Remplissez le champ **Test goal** pour décrire ce que vous souhaitez accomplir (par exemple, augmenter les abonnements ou réduire le taux de désabonnement). 5. Cliquez sur **Select placement** et choisissez un placement de flow, paywall ou onboarding. 6. Configurez le contenu du test dans le tableau **Variants**. Chaque ligne est une variante, chaque colonne est un placement. Ajoutez un paywall à chaque intersection. Par défaut, le tableau contient 2 variantes et 1 placement. Vous pouvez ajouter jusqu'à 20 variantes. Dès que vous ajoutez un second placement, le test devient un test A/B crossplacement. Notez que les tests A/B crossplacement sont uniquement disponibles pour les paywalls. <img src="/assets/shared/img/abtest-variants.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 7. Enregistrez votre test. Vous avez deux options : 1. **Save as draft** : Le test ne sera pas lancé immédiatement. Vous pourrez le lancer ultérieurement depuis le placement ou la liste des tests A/B. Utilisez cette option pour vérifier la configuration avant le lancement. 2. **Run A/B test** : Lance le test immédiatement. Le test est actif dès que vous cliquez sur ce bouton. Une fois enregistré en tant que brouillon, passez à [Lancer un test A/B](#run-an-ab-test). ## Modifier un test A/B \{#edit-an-ab-test\} Vous ne pouvez modifier que les tests A/B enregistrés en tant que brouillons. Une fois qu'un test est en cours, il ne peut plus être modifié. Pour mettre à jour un test en cours, utilisez l'option **Modify** — cela crée un doublon avec le même nom dans lequel vous pouvez effectuer des modifications. Adapty arrête le test d'origine, et les deux versions (originale et modifiée) apparaissent séparément dans vos analyses. ## Lancer un test A/B \{#run-an-ab-test\} Lancer un test A/B dans Adapty consiste à l'associer à un placement afin qu'il puisse commencer à afficher des paywalls et des onboardings aux utilisateurs. 1. Accédez à la section [A/B tests](ab-tests) depuis le menu principal d'Adapty. 2. Assurez-vous de consulter la bonne liste — les tests A/B **Paywall**, **Flow**, **Onboardings** et **Crossplacement** sont affichés dans des onglets séparés entre lesquels vous pouvez naviguer. <img src="/assets/shared/img/ab-tests-tabs.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Passez à l'onglet **Drafts**. Seuls les tests en brouillon peuvent être démarrés. 4. À côté du test que vous souhaitez lancer, cliquez sur **Run A/B test**. <img src="/assets/shared/img/run-ab-test-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. La fenêtre **Edit A/B test** s'ouvre. Vérifiez la configuration et apportez les dernières modifications. Si le placement ou l'audience est manquant, ajoutez-le maintenant. 6. Après avoir vérifié la configuration, cliquez sur **Run A/B test** pour démarrer. Après le lancement du test, vous pouvez suivre sa progression et consulter les données de performance sur la page [Résultats et métriques du test A/B](results-and-metrics). ## Arrêter un test A/B \{#stop-an-ab-test\} Lorsque vous arrêtez un test A/B, il se termine et vous pouvez analyser les résultats. Vous décidez également ce qui sera affiché aux utilisateurs dans les placements concernés après la fin du test. <img src="/assets/shared/img/stop-ab-test.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. Ouvrez la section [A/B tests](https://app.adapty.io/ab-tests) et accédez à l'onglet **Live**. 2. À côté du test que vous souhaitez arrêter, cliquez sur le menu à trois points, puis choisissez **Stop A/B test**. 3. Dans la fenêtre **Stop the A/B test**, décidez de ce qui doit se passer après la fin du test. Vous avez trois options : | Option | Description | |----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Display one of the tested paywalls/onboardings | Choisissez le paywall ou l'onboarding gagnant en fonction des résultats du test, comme le chiffre d'affaires, la probabilité d'être le meilleur (**P2BB**) et le chiffre d'affaires pour 1 000 utilisateurs. Ce paywall ou onboarding sera affiché pour le placement et l'audience sélectionnés. | | Select paywalls/onboardings that don't participate in A/B test | Choisissez un paywall ou un onboarding qui ne fait pas partie du test A/B en cours. Utilisez cette option quand aucune des variantes testées n'a atteint vos objectifs. | | Don't show any specific paywall/onboarding | Pour le placement et l'audience sélectionnés, aucun paywall ou onboarding spécifique ne sera sélectionné après la fin du test A/B. À la place, le prochain paywall ou onboarding disponible selon la priorité d'audience sera affiché. C'est un bon choix si vous préférez laisser votre configuration existante décider quel paywall ou onboarding afficher, sans en sélectionner un manuellement. | :::note L'arrêt d'un test A/B est irréversible — le test ne peut pas être relancé. Assurez-vous d'avoir collecté suffisamment de données avant de décider d'arrêter. ::: 4. Cliquez sur le bouton **Stop and complete this A/B test**. Une fois le test A/B terminé, il ne sera plus actif et les paywalls ou onboardings qui en faisaient partie ne seront plus affichés aux nouveaux utilisateurs. Vous pouvez toujours accéder aux résultats et aux métriques du test A/B sur la [page des métriques du test A/B](results-and-metrics#metrics-controls) pour analyser les performances des utilisateurs ayant participé pendant que le test était en cours. Les métriques peuvent continuer à se mettre à jour au fur et à mesure que de nouveaux événements d'achat ou de revenus sont attribués à ces utilisateurs. --- # File: ab-test-no-paywall-variants --- --- title: "Ajouter des variantes de test A/B sans flows ni paywalls" description: "Lancez un test A/B où une variante ignore le flow ou le paywall, en utilisant un indicateur de Remote Config pour contrôler son affichage." --- Vous pouvez mesurer l'impact de votre flow ou paywall en lançant un test A/B avec une variante vide. Une variante affiche votre flow/paywall ; l'autre n'affiche rien. Votre application lit un indicateur dans le Remote Config pour décider si elle doit effectuer le rendu. ## Fonctionnement \{#how-it-works\} La configuration utilise deux flows/paywalls dans le même placement : - **Flow/Paywall A** : le flow ou paywall que vous souhaitez tester, avec `show_paywall` défini sur `true` dans son Remote Config. - **Flow/Paywall B** : un flow ou paywall vide avec `show_paywall` défini sur `false` dans son Remote Config. Quand le SDK retourne un flow ou un paywall, votre application lit l'indicateur `show_paywall`. Si la valeur est `true`, l'application effectue le rendu. Si la valeur est `false`, l'application ignore le rendu et l'utilisateur continue sans rien voir. ## 1. Ajouter l'indicateur show_paywall dans le Remote Config \{#1-add-the-show_paywall-flag-in-remote-config\} Vous avez besoin de deux flows ou paywalls dans le même placement : Flow/Paywall A (celui que vous voulez tester) et Flow/Paywall B (un flow/paywall vide). Ajoutez un champ `show_paywall` à chacun afin que votre application puisse se brancher sur la même clé pour les deux variantes. Pour ajouter l'indicateur au Flow/Paywall A : 1. Ouvrez la section [**Flows**](https://app.adapty.io/flows)/[**Paywalls**](https://app.adapty.io/paywalls) dans le menu principal d'Adapty et sélectionnez Flow/Paywall A. 2. Ouvrez la section **Remote config**. 3. Créez un champ avec le nom `show_paywall` et la valeur `true`. Dans la vue **JSON**, l'entrée ressemble à ceci : ```json showLineNumbers { "show_paywall": true } ``` 4. Enregistrez les modifications. Répétez les mêmes étapes pour Flow/Paywall B, mais définissez `show_paywall` sur `false`. Pour plus de détails sur le Remote Config, consultez [Personnaliser un flow avec le Remote Config](customize-flow-with-remote-config) ou [Concevoir un paywall avec le Remote Config](customize-paywall-with-remote-config). :::tip Définir `show_paywall` sur les deux variantes permet de conserver un chemin de code identique pour les deux groupes et facilite l'ajout de nouvelles variantes par la suite. ::: ## 2. Configurer le test A/B \{#2-set-up-the-ab-test\} 1. [Créez un test A/B](run_stop_ab_tests) sur le placement et ajoutez les deux flows/paywalls comme variantes. 2. Définissez les poids des variantes pour répartir le trafic entre les utilisateurs qui voient le flow/paywall et ceux qui ne le voient pas. ## 3. Vérifier l'indicateur dans votre application \{#3-check-the-flag-in-your-app\} Lisez `show_paywall` depuis le Remote Config retourné par le SDK. Si l'indicateur est à `false`, ignorez le rendu et laissez l'utilisateur continuer. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first let showPaywall = config?.dictionary?["show_paywall"] as? Bool ?? true if showPaywall { // render the flow or paywall } } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android"> ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value val showPaywall = paywall.remoteConfig?.dataMap?.get("show_paywall") as? Boolean ?: true if (showPaywall) { // Render the paywall } } is AdaptyResult.Error -> { // handle the error } } } ``` </TabItem> <TabItem value="react-native" label="React Native"> ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: "YOUR_PLACEMENT_ID" }); const showPaywall = paywall.remoteConfig?.data?.["show_paywall"] ?? true; if (showPaywall) { // Render the paywall } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(id: "YOUR_PLACEMENT_ID"); final bool showPaywall = paywall.remoteConfig?.dictionary?['show_paywall'] as bool? ?? true; if (showPaywall) { // Render the paywall } } on AdaptyError catch (adaptyError) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity"> ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } var showPaywall = paywall.RemoteConfig?.Dictionary?["show_paywall"] as bool? ?? true; if (showPaywall) { // Render the paywall } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform"> ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID" ).onSuccess { paywall -> val showPaywall = paywall.remoteConfig?.dataMap?.get("show_paywall") as? Boolean ?: true if (showPaywall) { // Render the paywall } }.onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor"> ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID' }); const showPaywall = paywall.remoteConfig?.data?.['show_paywall'] ?? true; if (showPaywall) { // Render the paywall } } catch (error) { // handle the error } ``` </TabItem> </Tabs> La valeur de secours `true` maintient le flow/paywall visible lorsque l'indicateur est absent, de sorte que les flows/paywalls existants sans cet indicateur ne sont pas affectés. :::important Si vous effectuez le rendu du paywall vous-même (sans le [Flow Builder](adapty-flow-builder) ni le [Paywall Builder](adapty-paywall-builder)), appelez [`logShowFlow` (SDK iOS v4+) / `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) lorsque vous affichez Flow/Paywall A. Sans cela, Adapty ne peut pas comptabiliser les vues dans le test. N'enregistrez pas de vue pour Flow/Paywall B, puisqu'il n'est jamais affiché. ::: ## Prochaines étapes \{#next-steps\} - [Créer, lancer et arrêter un test A/B](run_stop_ab_tests) — Configurez le test incluant les deux variantes - [Résultats et métriques du test A/B](results-and-metrics) — Comparez la variante vide avec votre flow/paywall --- # File: results-and-metrics --- --- title: "Résultats et métriques des tests A/B" description: "Analysez les résultats et les métriques clés dans Adapty pour améliorer les performances d'abonnement et l'engagement des utilisateurs de votre application." --- Découvrez des données et des insights importants grâce à nos [tests A/B](ab-tests), en comparant différents paywalls et onboardings pour voir comment ils influencent le comportement des utilisateurs, l'engagement et les taux de conversion. En examinant les métriques et les résultats présentés ici, vous pouvez prendre des décisions éclairées et améliorer les performances de votre application. Plongez dans les données pour trouver des insights actionnables et booster le succès de votre application. ## Résultats des tests A/B \{#ab-test-results\} Voici les trois métriques qu'Adapty fournit pour les résultats des tests A/B : <img src="/assets/shared/img/ab-test-results.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: **Revenue** : cette métrique affiche le montant total généré en USD par les achats et les renouvellements, déduction faite des remboursements accordés aux utilisateurs. Elle inclut à la fois l'achat initial et les renouvellements d'abonnement ultérieurs. Revenue vous permet de comprendre comment chaque variante du test A/B se comporte financièrement et de déterminer laquelle génère le plus de revenus. En savoir plus sur les métriques [paywall](paywall-metrics). **Probability to be best** : Adapty utilise un cadre d'analyse mathématique robuste pour analyser les résultats des tests A/B et fournit une métrique appelée Probability to be best. Cette métrique évalue la probabilité qu'une variante particulière soit la meilleure option (en termes de revenus à long terme) parmi toutes les variantes testées. La métrique est exprimée en pourcentage allant de 1 % à 100 %. Pour des informations détaillées sur le calcul de cette métrique par Adapty, consultez la [documentation.](maths-behind-it) La meilleure option, déterminée par le Revenue per 1K user, est mise en évidence en vert et automatiquement sélectionnée par défaut. **Revenue per 1K users** : la métrique Revenue per 1K users calcule le revenu moyen généré pour 1 000 utilisateurs pour chaque variante du test A/B. Cette métrique vous aide à comprendre l'efficacité des revenus de vos variantes, indépendamment du nombre total d'utilisateurs. Elle vous permet de comparer les performances des différentes variantes sur une échelle standardisée et de prendre des décisions éclairées basées sur l'efficacité de génération de revenus. **Intervalles de prédiction pour le Revenue 1K users** : la métrique Revenue per 1K users inclut également des intervalles de prédiction. Ces intervalles représentent la plage dans laquelle le vrai revenu pour 1 000 utilisateurs d'une variante donnée est prédit de se situer, en se basant sur les données disponibles et l'analyse statistique. Dans le contexte des tests A/B, lors de l'analyse des revenus générés par différentes variantes, nous calculons le revenu moyen pour 1 000 utilisateurs pour chaque variante. Comme les revenus peuvent varier d'un utilisateur à l'autre, les intervalles de prédiction fournissent une indication claire des valeurs plausibles pour le revenu pour 1 000 utilisateurs, en tenant compte de la variabilité et de l'incertitude associées au processus de prédiction. En intégrant des intervalles de prédiction dans la métrique Revenue per 1K users, Adapty vous permet d'évaluer l'efficacité des revenus de vos variantes de test A/B tout en prenant en compte la plage des résultats de revenus potentiels. Ces informations vous aident à prendre des décisions basées sur les données et à optimiser efficacement votre stratégie d'abonnement, en tenant compte de l'incertitude dans le processus de prédiction et des valeurs plausibles pour le revenu pour 1 000 utilisateurs. En analysant ces métriques fournies par Adapty, vous pouvez obtenir des insights sur les performances financières, la significativité statistique et l'efficacité des revenus de vos variantes de test A/B, vous permettant de prendre des décisions basées sur les données et d'optimiser efficacement votre stratégie d'abonnement. ## Métriques des tests A/B \{#ab-test-metrics\} Adapty fournit un ensemble complet de métriques pour vous aider à mesurer efficacement les performances de vos tests A/B réalisés sur vos variantes de paywall ou d'onboarding. Ces métriques sont mises à jour en temps réel, à l'exception des vues qui sont mises à jour périodiquement. Comprendre ces métriques vous aidera à évaluer l'efficacité des différentes variantes et à prendre des décisions basées sur les données pour optimiser votre stratégie de paywall ou d'onboarding. Les métriques des tests A/B sont disponibles dans la liste des tests A/B, où vous pouvez avoir une vue d'ensemble des performances de tous vos tests A/B. Cette vue complète offre des métriques agrégées pour chaque variante de test, vous permettant de comparer leurs performances et d'identifier les différences significatives. Pour une analyse plus détaillée de chaque test A/B, vous pouvez accéder aux métriques détaillées du test A/B. Cette section fournit des métriques approfondies spécifiques au test A/B sélectionné, vous permettant d'explorer les performances des variantes individuelles. Toutes les métriques, à l'exception des vues, sont attribuées au produit au sein du paywall ou de l'onboarding. ## Filtrer les métriques par date d'installation \{#filter-metrics-by-install-date\} Les métriques de paywall, d'essai et d'achat peuvent être regroupées selon deux dates différentes : - **La date de l'événement** — quand le paywall a été consulté, l'essai commencé ou l'achat effectué. - **La date d'installation** — quand l'utilisateur a ouvert l'application pour la première fois. Les deux vues peuvent afficher des chiffres très différents pour la même plage de dates. La case **Filter metrics by install date** contrôle laquelle le tableau de bord utilise : - **Décochée (par défaut)** : les métriques sont regroupées par date d'événement. - **Cochée** : les métriques sont regroupées par date d'installation. **Exemple.** Vous définissez la plage de dates du 1er au 30 avril et vous regardez les essais. - **Décochée** : affiche les essais qui ont *démarré* en avril, quelle que soit la date d'installation de ces utilisateurs. - **Cochée** : affiche les essais des utilisateurs qui se sont *installés* en avril, quelle que soit la date de début de leur essai. Utilisez la vue par date d'installation pour mesurer les performances d'acquisition d'utilisateurs pour une cohorte spécifique. Utilisez la vue par date d'événement pour mesurer l'activité d'un paywall ou d'un onboarding sur une période donnée. ## Contrôles des métriques \{#metrics-controls\} Le système affiche les métriques en fonction de la période sélectionnée et les organise selon le paramètre de la colonne de gauche avec trois niveaux d'indentation. ### Plages de temps \{#time-ranges\} Vous pouvez choisir parmi différentes périodes pour analyser les données de métriques, ce qui vous permet de vous concentrer sur des durées spécifiques comme des jours, des semaines, des mois ou des plages de dates personnalisées. <img src="/assets/shared/img/ab-test-time-ranges.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: Adapty propose des outils puissants pour filtrer et personnaliser l'analyse des métriques selon vos besoins. Depuis la page des métriques d'Adapty, vous avez accès à différentes plages de temps, options de regroupement et possibilités de filtrage. - ✅ Filtrer par : Audience, attribution, pays, paywall, état du paywall, groupe de paywalls, onboarding, placement, pays, store, produit et store du produit. - ✅ Regrouper par : Produit et store. :::note Lorsque vous filtrez par test A/B, les tests A/B cross-placement apparaissent comme des tests enfants séparés (par ex. `My test child-0`, `My test child-1`), un par placement. Consultez [Limitations des tests A/B cross-placement](ab-test-types#crossplacement-ab-test-limitations) pour plus de détails. ::: ## Graphique de métrique unique \{#single-metrics-chart\} L'un des éléments clés de la page des métriques de paywall ou d'onboarding est la section graphique, qui représente visuellement les métriques sélectionnées et facilite l'analyse. <img src="/assets/shared/img/e6b0674-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> La section graphique de la page des métriques du test A/B comprend un graphique à barres horizontales qui représente visuellement les valeurs des métriques choisies. Chaque barre du graphique correspond à une valeur de métrique et est proportionnelle en taille, ce qui facilite la compréhension des données d'un coup d'œil. La ligne horizontale indique la période analysée, et la colonne verticale affiche les valeurs numériques des métriques. La valeur totale de toutes les valeurs de métriques est affichée à côté du graphique. De plus, cliquer sur l'icône de flèche dans le coin supérieur droit de la section graphique développe la vue, affichant les métriques sélectionnées sur toute la ligne du graphique. ## Résumé du test A/B \{#ab-test-summary\} À côté du graphique de métrique unique, la section de résumé des détails du test A/B est affichée. Elle comprend des informations sur l'état, la durée, les placements et d'autres détails relatifs au test A/B. <img src="/assets/shared/img/90fa3f5-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Définitions des métriques \{#metrics-definitions\} Voici les métriques clés disponibles pour les tests A/B : <img src="/assets/shared/img/30c7b68-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Revenue \{#revenue\} Revenue représente le montant total généré en USD par les achats et les renouvellements résultant du test A/B. Il inclut l'achat initial et les renouvellements d'abonnement ultérieurs. La métrique Revenue est calculée avant déduction de la commission de l'App Store ou du Play Store. En savoir plus sur les métriques [paywall](paywall-metrics#revenue) Revenue. ### CR to purchases \{#cr-to-purchases\} Le taux de conversion vers les achats mesure l'efficacité de votre test A/B à convertir les vues en achats réels. Il est calculé en divisant le nombre d'achats par le nombre de vues. Par exemple, si vous avez 10 achats et 100 vues, le taux de conversion vers les achats serait de 10 %. ### CR trials \{#cr-trials\} Le taux de conversion (CR) vers les essais est le nombre d'essais démarrés depuis le test A/B divisé par le nombre de vues. Le taux de conversion vers les essais mesure l'efficacité de votre test A/B à convertir les vues en activations d'essai. Il est calculé en divisant le nombre d'essais démarrés par le nombre de vues. ### Purchases \{#purchases\} La métrique Purchases représente le nombre total de transactions effectuées dans le paywall ou l'onboarding résultant du test A/B. Elle inclut les types d'achats suivants : - Nouveaux achats effectués. - Conversions d'essais qui ont été activés. - Déclassements, mises à niveau et changements de niveaux d'abonnements. - Restaurations d'abonnement (par ex. lorsqu'un abonnement expire sans renouvellement automatique et est ensuite restauré). Veuillez noter que les renouvellements ne sont pas inclus dans la métrique Purchases. ### Trials \{#trials\} La métrique Trials indique le nombre total d'essais activés résultant du test A/B. ### Trials cancelled \{#trials-cancelled\} La métrique Trials cancelled représente le nombre d'essais pour lesquels le renouvellement automatique a été désactivé. Cela se produit lorsque les utilisateurs se désinscrivent manuellement de l'essai. ### Refunds \{#refunds\} Les Refunds pour le test A/B représentent le nombre d'achats et d'abonnements remboursés spécifiquement liés aux variantes testées. ### Views \{#views\} Views est le nombre de vues des paywalls ou des onboardings qui composent le test A/B. Si l'utilisateur visite deux fois, cela compte comme deux visites. ### Unique views \{#unique-views\} Unique views est le nombre de vues uniques du paywall ou de l'onboarding. Si l'utilisateur le visite deux fois, cela compte comme une seule vue unique. ### Probability to be the best \{#probability-to-be-the-best\} La métrique Probability to be the best quantifie la probabilité qu'une variante spécifique d'un test A/B soit la meilleure option parmi tous les paywalls ou onboardings testés. Elle fournit une probabilité numérique indiquant les performances relatives de chaque paywall ou onboarding. La métrique est exprimée en pourcentage allant de 1 % à 100 %. ### ARPU (Average revenue per user) \{#arpu-average-revenue-per-user\} Pour les tests A/B d'onboarding uniquement. Mesure le revenu moyen généré par chaque utilisateur sur une période donnée. Il est calculé en divisant le revenu total par le nombre d'utilisateurs uniques. ### ARPPU (Average revenue per paying user) \{#arppu-average-revenue-per-paying-user\} ARPPU signifie Average Revenue Per Paying User résultant du test A/B. Il est calculé comme le revenu total divisé par le nombre d'utilisateurs payants uniques. Par exemple, si vous avez généré 15 000 $ de revenus auprès de 1 000 utilisateurs payants, l'ARPPU serait de 15 $. ### ARPAS (Average revenue per active subscriber) \{#arpas-average-revenue-per-active-subscriber\} ARPAS est une métrique qui vous permet de mesurer le revenu moyen généré par abonné actif grâce à l'exécution du test A/B. Il est calculé en divisant le revenu total par le nombre d'abonnés ayant activé un essai ou un abonnement. Par exemple, si le revenu total est de 5 000 $ et que vous avez 1 000 abonnés, l'ARPAS serait de 5 $. Cette métrique aide à évaluer le potentiel de monétisation moyen par abonné. ### Proceeds \{#proceeds\} La métrique Proceeds pour le test A/B représente le montant réel d'argent reçu par le propriétaire de l'application en USD provenant des achats et des renouvellements, après déduction de la commission applicable de l'App Store / Play Store. Elle reflète les revenus nets spécifiquement associés aux variantes testées dans le test A/B, contribuant directement aux gains de l'application. Pour plus d'informations sur le calcul des proceeds, vous pouvez consulter la [documentation](analytics-cohorts#revenue-vs-proceeds) Adapty. ### Unique subscribers \{#unique-subscribers\} La métrique Unique subscribers représente le nombre de personnes distinctes qui se sont abonnées ou ont activé un essai via les variantes du test A/B. Elle ne compte chaque abonné qu'une seule fois, quel que soit le nombre d'abonnements ou d'essais qu'il initie. ### Unique paid subscribers \{#unique-paid-subscribers\} La métrique Unique paid subscribers représente le nombre de personnes uniques qui ont réalisé un achat avec succès et sont devenues des abonnés payants via les variantes du test A/B. ### Refund rate \{#refund-rate\} Le taux de remboursement pour le test A/B est calculé en divisant le nombre de remboursements spécifiquement associés aux variantes du test par le nombre de premiers achats (les renouvellements sont exclus). Par exemple, s'il y a 5 remboursements et 1 000 premiers achats, le taux de remboursement serait de 0,5 %. ### Unique CR purchases \{#unique-cr-purchases\} Le taux de conversion unique vers les achats pour le test A/B est calculé en divisant le nombre d'achats spécifiquement associés aux variantes du test par le nombre de vues uniques. Par exemple, s'il y a 10 achats et 100 vues uniques, le taux de conversion unique vers les achats serait de 10 %. ### Unique CR trials \{#unique-cr-trials\} Le taux de conversion unique vers les essais pour le test A/B est calculé en divisant le nombre d'essais démarrés spécifiquement associés aux variantes du test par le nombre de vues uniques. Par exemple, s'il y a 30 essais démarrés et 100 vues uniques, le taux de conversion unique vers les essais serait de 30 %. ### Completions & unique completions \{#completions--unique-completions\} Pour les tests A/B d'onboarding uniquement. Les Completions comptent le nombre de fois où les utilisateurs complètent votre onboarding via les variantes du test A/B, c'est-à-dire qu'ils passent du premier au dernier écran. Si quelqu'un le complète deux fois, cela compte comme deux **completions** mais une seule **unique completion**. ### Unique completions rate \{#unique-completions-rate\} Pour les tests A/B d'onboarding uniquement. Le nombre de completions uniques divisé par le nombre de vues uniques. Cette métrique vous aide à comprendre comment les utilisateurs s'engagent avec l'onboarding via les variantes du test A/B et à apporter des modifications si vous constatez que les utilisateurs l'ignorent. --- # File: maths-behind-it --- --- title: "Les mathématiques derrière les tests A/B" description: "Comprenez les mathématiques derrière l'analyse des abonnements pour de meilleures perspectives de revenus." --- Les tests A/B sont une technique puissante permettant de comparer les performances de deux versions différentes d'un flow, d'un paywall ou d'un onboarding. L'objectif final est de déterminer quelle version est la plus efficace en se basant sur le revenu moyen par utilisateur sur une période de 12 mois. Cependant, attendre une année entière pour collecter des données et prendre des décisions n'est pas pratique. C'est pourquoi le revenu par utilisateur sur 2 semaines est utilisé comme métrique proxy, choisi sur la base d'une analyse des données historiques pour approximer la métrique cible. Pour obtenir des résultats précis et fiables, il est crucial d'employer une méthode statistique robuste capable de gérer des types de données variés. La statistique bayésienne, une approche populaire dans l'analyse de données moderne, fournit un cadre flexible et intuitif pour les tests A/B. En intégrant des connaissances préalables et en les mettant à jour avec de nouvelles données, les méthodes bayésiennes permettent une meilleure prise de décision dans des situations d'incertitude. Ce document fournit un guide complet de l'analyse mathématique employée par Adapty pour évaluer les résultats des tests A/B et fournir des informations précieuses pour une prise de décision basée sur les données. ## Approche d'Adapty en matière d'analyse statistique \{#adaptys-approach-to-statistical-analysis\} Adapty emploie une approche complète de l'analyse statistique afin d'évaluer les performances des tests A/B et de fournir des informations précises et fiables. Notre méthodologie comprend les étapes clés suivantes : 1. **Définition de la métrique :** Pour mener un test A/B avec succès, vous devez identifier et définir la métrique clé qui correspond aux objectifs spécifiques de l'analyse. Adapty a exploité une grande quantité de données historiques d'applications d'abonnement pour déterminer celle qui joue le rôle de métrique proxy pour l'objectif à long terme du revenu moyen après 1 an — il s'agit de l'ARPU après 14 jours. 2. **Formulation des hypothèses :** Nous créons deux hypothèses pour le test A/B. L'hypothèse nulle (H0) suppose qu'il n'y a pas de différence significative entre le groupe de contrôle (A) et le groupe de test (B). L'hypothèse alternative (H1) suggère qu'il existe une différence significative entre deux groupes ou plus. 3. **Sélection de la distribution :** Nous choisissons la famille de distribution la mieux adaptée en fonction des caractéristiques des données et de la métrique observée. Le choix le plus fréquent est la distribution log-normale (en tenant compte des valeurs nulles). 4. **Calcul de la probabilité d'être le meilleur :** En utilisant l'approche bayésienne des tests A/B, nous calculons la probabilité d'être la meilleure option pour chaque variante de paywall ou d'onboarding participant au test. Cette valeur est certes liée aux p-values que nous utilisions auparavant, mais il s'agit essentiellement d'une approche différente, plus robuste et plus facile à comprendre. 5. **Interprétation des résultats :** La probabilité d'être le meilleur est exactement ce que cela suggère. Plus la probabilité est élevée, plus une option spécifique a de chances d'être le meilleur choix pour la tâche. Vous devez déterminer vous-même le seuil pour la prise de décision ; celui-ci doit dépendre de nombreux autres facteurs propres à votre situation, mais un seuil de probabilité couramment utilisé est de 95 %. 6. **Intervalles de prédiction :** Adapty calcule des intervalles de prédiction pour les métriques de performance de chaque groupe, fournissant une plage de valeurs dans laquelle le vrai paramètre de la population est susceptible de se situer. Cela permet de quantifier l'incertitude associée aux métriques de performance estimées. ## Détermination de la taille de l'échantillon \{#sample-size-determination\} Déterminer une taille d'échantillon appropriée est essentiel pour obtenir des résultats de tests A/B fiables et concluants. Adapty prend en compte des facteurs tels que la puissance statistique et la taille d'effet attendue, qui restent importants même avec l'approche bayésienne, afin de garantir une taille d'échantillon adéquate. Les méthodes d'estimation de la taille d'échantillon requise, spécifiques à l'approche bayésienne que nous employons désormais, garantissent la fiabilité de l'analyse. Pour en savoir plus sur les fonctionnalités des tests A/B, nous vous recommandons de consulter notre documentation sur la [création](ab-tests) et [l'exécution des tests A/B](run_stop_ab_tests), ainsi que la compréhension des différentes [métriques et résultats des tests A/B](results-and-metrics). Le cadre analytique d'Adapty pour les tests A/B emploie désormais une approche bayésienne, mais l'accent reste mis sur la définition des métriques, la formulation des hypothèses et la sélection des distributions. Cependant, au lieu de déterminer des p-values, nous calculons désormais les distributions a posteriori et la probabilité que chaque variante soit la meilleure. Nous déterminons également les intervalles de prédiction. Cette approche révisée, bien que toujours complète et encore plus robuste, est conçue pour fournir des informations plus intuitives et plus faciles à interpréter. L'objectif reste d'aider les entreprises à optimiser leurs stratégies, améliorer leurs performances et stimuler leur croissance grâce à une analyse statistique rigoureuse de leurs tests A/B. --- # File: autopilot --- --- title: "Conseiller IA de croissance" description: "Optimisez vos paywalls pour maximiser vos revenus." --- Growth Advisor est un outil de croissance dopé à l'IA pour les applications par abonnement. Il élabore un plan à long terme pour augmenter vos revenus grâce à des tests A/B, en s'appuyant sur des données marché issues de plus de 20 000 applications suivies par Adapty. <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/xxp-H_hzEPA?si=kEbAHsTOTwsAZNsm" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## Prérequis \{#prerequisites\} - **Accès App Store Connect** — AI Growth Advisor s'appuie sur les données App Store pour ses comparatifs. [Importez vos identifiants App Store Connect](set-up-app-store-connect) avant de lancer votre première analyse. - **Au moins un produit App Store payant sur le paywall sélectionné** — les paywalls configurés uniquement pour Google Play ne peuvent pas être analysés. Ajoutez un produit App Store dans la section **Products** avant de commencer. - **Placement du paywall** — les placements de type [flow](adapty-flow-builder) sont en bêta et ne peuvent pas encore être analysés par AI Growth Advisor. - Remarque : AI Growth Advisor fonctionne pour toutes les applications — mais plus Adapty dispose de données financières à analyser, plus les recommandations sont fiables. ## Fonctionnement du conseiller de croissance IA \{#how-ai-growth-advisor-works\} :::link L'article [Conseiller de croissance IA : fonctionnement](autopilot-how-it-works) explique comment Adapty génère ses recommandations. ::: 1. AI Growth Advisor [analyse le contenu et le design de votre paywall](autopilot-analysis#paywall-analysis), met en avant ce qui fonctionne et détecte les **opportunités d'amélioration de la conversion**. - Les recommandations comparent votre design aux modèles des applications les plus performantes dans votre catégorie. - L'analyse porte uniquement sur les produits par abonnement. Les achats intégrés consommables ne sont pas inclus. 2. Sur vos principaux marchés, AI Growth Advisor [recommande des ajustements de prix par pays](autopilot-growth-plan#geo-pricing-hypotheses) et [compare votre conversion à celle d'applications similaires](autopilot-analysis#market-and-competitor-analysis). - Les benchmarks de conversion s'appuient sur des données anonymisées couvrant les 20 000 applications du réseau Adapty. - Les recommandations de prix s'appuient sur l'[Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf), un benchmark par pays de ce que paient réellement les abonnés. 3. Une fois l'analyse terminée, AI Growth Advisor présente un [plan de croissance actionnable](autopilot-growth-plan) pour le placement sélectionné. Chaque hypothèse correspond à un test A/B permettant d'expérimenter une nouvelle approche. À mesure que les conditions de marché évoluent, vous pouvez relancer l'analyse et enrichir votre plan avec de nouvelles hypothèses. 4. [Lancez les tests suggérés](autopilot-execute-plan) un par un. D'après nos estimations, exécuter l'ensemble des tests recommandés pourrait augmenter vos revenus **jusqu'à 80 %**. ## Lancer l'analyse \{#run-the-analysis\} :::link Article principal : [Analyse des paywalls et du marché](autopilot-analysis) ::: 1. Ouvrez la page **AI Growth Advisor** et cliquez sur le bouton [Get Growth plan](https://app.adapty.io/ab-tests/analysis/start). 2. [Sélectionnez un placement et un paywall](autopilot-analysis#select-a-paywall-for-analysis). Vérifiez que les produits affichés sont corrects. Téléchargez une capture d'écran et cliquez sur **Confirm & Analyze**. 3. Adapty [analyse](autopilot-analysis#paywall-analysis) le design, le contenu et les métriques de revenus de votre paywall. Consultez le rapport pour savoir ce qui fonctionne et ce qui doit être amélioré. 4. [Sélectionnez jusqu'à 5 concurrents](autopilot-analysis#select-competitors) pour une comparaison approfondie. Cliquez sur **Generate report**. 5. Consultez le rapport [market insights](autopilot-analysis#market-and-competitor-analysis). Il compare les performances de votre paywall avec celles des concurrents et les benchmarks du marché par pays. Vous pouvez changer de pays pour modifier le contexte de l'analyse. * Distribution géographique des revenus * Tarification des concurrents (par pays) * Benchmarks du tunnel de conversion (par pays, moyenne du marché) * Distribution des revenus par durée d'abonnement (par pays, moyenne du marché) * ARPU d'activation (par pays, moyenne du marché) ## Gérez votre plan de croissance \{#manage-your-growth-plan\} :::link Article principal : [Gérez votre plan de croissance](autopilot-growth-plan) ::: 6. Ouvrez le [plan de croissance](autopilot-growth-plan) et passez en revue les hypothèses basées sur les données d'Adapty. Chacune est un test A/B ciblant un seul changement de prix ou de design. Ajoutez vos propres hypothèses pour enrichir le plan. 7. Pour garder votre plan de croissance pertinent, [relancez régulièrement l'analyse](autopilot-growth-plan#get-new-ai-generated-hypotheses). Chaque nouvelle exécution intègre des données de marché récentes et ajoute de nouvelles hypothèses à votre plan existant. ## Exécutez votre plan de croissance \{#execute-your-growth-plan\} :::link Article principal : [Exécutez votre plan de croissance](autopilot-execute-plan) ::: 8. [Lancez les tests](autopilot-execute-plan) un par un. Créez de nouveaux produits, dupliquez votre paywall avec les modifications suggérées, et lancez le test A/B. La configuration gagnante participera au test suivant. --- # File: autopilot-how-it-works --- --- title: "AI Growth Advisor : fonctionnement" description: "Comprenez la logique derrière l'AI Growth Advisor et faites-nous confiance pour développer vos revenus." --- [AI Growth Advisor](autopilot) vous aide à déterminer quelles expériences lancer en s'appuyant sur vos données de performance réelles et sur les tendances observées chez des applications similaires dans votre marché. Plutôt que de deviner ce qui pourrait fonctionner, vous obtenez des recommandations concrètes pour des tests qui ont davantage de chances d'améliorer vos résultats. Cet article propose un regard transparent sur le fonctionnement de l'AI Growth Advisor — quelles données il utilise, comment il évalue les opportunités, et pourquoi certaines recommandations apparaissent. L'objectif est de vous aider à l'intégrer avec confiance dans votre workflow de croissance. ## Ce que fait réellement AI Growth Advisor \{#what-ai-growth-advisor-actually-does\} AI Growth Advisor analyse vos métriques d'application et de paywall pour identifier les expériences les plus susceptibles d'augmenter vos revenus. Il examine : - **Votre configuration actuelle** : tarification, essais, produits et leurs taux de conversion - **Les tendances du marché** : comment des applications similaires structurent leurs offres et fixent leurs prix - **Votre historique de tests** : les expériences que vous avez déjà menées et ce qu'elles ont révélé - **Le potentiel de croissance** : les changements qui ont le plus de chances de faire une différence Growth Advisor utilise l'IA pour évaluer ces facteurs ensemble et les transformer en tests A/B que vous pouvez lancer immédiatement. Vous obtenez un plan prêt à l'emploi sans avoir à analyser la concurrence ni deviner ce qu'il faut tester ensuite. ## Les données qui alimentent l'IA Growth Advisor \{#the-data-behind-ai-growth-advisor\} Chaque recommandation repose sur trois sources de données principales qui fonctionnent ensemble. #### Les données de votre application \{#your-apps-own-data\} L'IA Growth Advisor analyse les performances actuelles de votre application : - Les métriques de conversion sur vos paywalls - La structure des prix et des produits Cela donne à l'IA Growth Advisor une base de référence avant de suggérer des modifications. :::note Nous n'utilisons pas les données de performance de votre application pour entraîner des recommandations destinées à d'autres applications. Vos données restent privées. ::: #### Analyse des paywalls \{#paywall-analysis\} L'AI Growth Advisor analyse votre capture d'écran de paywall et compare sa conception aux modèles établis par les applications les plus performantes de votre catégorie. Il évalue les choix de mise en page, le texte, les détails des abonnements et les éléments orientés conversion comme les badges de réduction ou les sections d'avis. Cette analyse produit deux types de recommandations : - **Recommandations de référence** basées sur ce que font différemment les applications les plus performantes — chacune étayée par une statistique précise (par exemple, « Utilisée par 72 % des meilleures applications Éducation »). - **Recommandations d'analyse visuelle** générées par l'IA à partir de votre capture d'écran, couvrant les améliorations de texte, les modifications de mise en page et d'autres ajustements de design. Ces recommandations s'intègrent directement dans votre [plan de croissance](autopilot-growth-plan) sous forme d'hypothèses que vous pouvez [lancer en tests A/B](autopilot-execute-plan). #### Données concurrentes AI Growth Advisor compare votre configuration avec des applications similaires sur votre marché en s'appuyant sur des informations publiques telles que les prix, les structures d'abonnement et les tendances courantes dans votre catégorie. Ces comparaisons sont spécifiques à chaque pays, car les prix et les structures des concurrents varient selon les marchés. Les prix des concurrents proviennent de sources tierces et publiques comme l'App Store — distinctes des données anonymisées du réseau Adapty utilisées par l'analyse des métriques. De cette façon, vous testez des stratégies qui fonctionnent déjà pour des applications similaires à la vôtre, et pas seulement des idées au hasard. En consultant l'analyse, vous pouvez comparer vos benchmarks et les prix de vos concurrents côte à côte. Si des applications similaires obtiennent de meilleurs résultats avec une tarification ou une structure différente, c'est un bon signal que la même approche pourrait également fonctionner pour vous. :::tip AI Growth Advisor sélectionne automatiquement les concurrents pertinents en fonction de ce avec quoi vous pouvez réellement rivaliser. Nous recommandons généralement de vous en tenir à ces suggestions plutôt que d'ajouter des applications trop en avance ou trop en retard sur vous. Si votre application appartient à plusieurs catégories, vous pouvez ajuster la liste pour vous concentrer sur le segment de marché le plus pertinent. ::: #### Benchmarks sectoriels \{#industry-benchmarks\} L'AI Growth Advisor s'appuie sur des données anonymisées provenant de 20 000 applications d'abonnement suivies par Adapty pour vous montrer comment vous vous situez par rapport à la moyenne de votre catégorie dans un pays donné. Les données sont agrégées à l'échelle du réseau et ne sont jamais associées à une application spécifique. Par exemple, votre entonnoir de conversion et vos revenus par installation sont comparés à la moyenne des applications de votre catégorie et de votre pays. Cela vous permet de savoir si vous êtes en dessous de la moyenne, dans la norme, ou déjà en avance. #### Données du marché géographique \{#geographic-market-data\} L'AI Growth Advisor analyse les marchés géographiques individuels — en s'appuyant sur les tendances observées sur le réseau Adapty de 20 000 applications — pour identifier où des ajustements de prix régionaux pourraient générer davantage de revenus. Pour chaque pays, il évalue : - **Taux de conversion** : Comment le taux d'installation-vers-payant se compare à la moyenne mondiale. Un taux plus élevé peut indiquer une marge pour augmenter les prix ; un taux plus bas peut signaler une sensibilité au prix. - **Indice de prix** : La position du pays dans l'[Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf), qui indique le pouvoir d'achat de ses résidents. Vous pouvez agir sur ces recommandations en créant des tests A/B à partir des [suggestions de tarification géographique](autopilot-growth-plan#geo-pricing-hypotheses) de votre plan de croissance. ## Comment l'IA Growth Advisor décide quoi recommander \{#how-ai-growth-advisor-decides-what-to-recommend\} L'IA Growth Advisor génère un ensemble de suggestions pour améliorer la conversion de votre paywall. Ces suggestions sont conçues pour être testées une par une afin de mesurer de manière fiable l'impact de chaque changement. Voici comment l'IA Growth Advisor élabore ses suggestions : 1. **Trouver les plus grandes opportunités** AI Growth Advisor examine vos tarifs, produits et performances de l'entonnoir, puis les compare avec les tendances du secteur et les applications similaires. L'analyse s'effectue dans la devise de votre marché principal — pas uniquement en USD — afin que les recommandations de prix correspondent à ce que vos abonnés paient réellement. Il identifie là où vous avez le plus de marge d'amélioration, que ce soit en ajustant votre prix, en ajoutant un essai gratuit ou en modifiant la structure de votre offre. 2. **Sélectionner la prochaine expérience** Chaque hypothèse est générée à partir de votre historique de tests existant. L'AI Growth Advisor sait quelles expériences vous avez déjà menées, lesquelles ont gagné et quelles directions valent encore la peine d'être explorées. La suggestion suivante s'appuie sur ce que la précédente a révélé, plutôt que de suivre une séquence fixe. 3. **Testez le gagnant face au challenger** Après chaque expérience, le gagnant devient votre nouvelle référence. Ce résultat oriente la prochaine recommandation de votre plan de croissance — l'AI Growth Advisor conserve ce qui a fonctionné, écarte ce qui n'a pas marché et sélectionne le test suivant à partir de là. 4. **Restez pragmatique** L'AI Growth Advisor ne suggère que des tests que vous pouvez lancer avec vos produits et votre configuration actuels, ou avec de petits ajustements comme la création d'un nouveau produit ou la modification d'un prix. L'objectif est de garder les tests rapides et faciles à gérer. 5. **Vous expliquer le raisonnement** Pour chaque recommandation, l'AI Growth Advisor fournit une hypothèse claire qui explique précisément pourquoi ce test vaut la peine d'être lancé. Vous verrez comment vos métriques actuelles se comparent à celles de vos concurrents et aux moyennes du secteur, quelle est l'opportunité, et quelles métriques clés nous nous attendons à améliorer. Cela transforme l'expérimentation en un processus reproductible où chaque test vous apprend quelque chose et vous rapproche d'un paywall plus efficace. ## Ce qui se passe après chaque expérience \{#what-happens-after-each-experiment\} Les recommandations ne s'épuisent pas. Chaque test terminé devient la base de nouvelles expériences. Tant que vous continuez à tester, AI Growth Advisor continue de suggérer quoi essayer ensuite. Pour actualiser les données de marché sous-jacentes, relancez l'analyse sur le même placement. Chaque nouvelle exécution récupère les dernières données tarifaires des concurrents, les benchmarks de conversion et les tendances de catégorie, et ajoute les nouvelles hypothèses identifiées à votre plan de croissance sans perturber ce qui existe déjà. Vos hypothèses générées par l'IA, vos hypothèses personnalisées et vos tests A/B en cours sont préservés d'une exécution à l'autre. Une fois votre base optimisée, vous pouvez également vous mesurer à des concurrents plus avancés. Cette approche itérative vous aide à maximiser vos revenus au fur et à mesure que votre application se développe et que le marché évolue. :::tip Prêt à vous lancer ? Utilisez [AI Growth Advisor](autopilot-analysis) pour analyser vos paywalls et générer un plan de croissance avec des tests A/B. Servez-vous de [l'assistant intégré](autopilot-execute-plan) pour lancer facilement des tests complexes : il vous guidera à travers la création de produits, la duplication de paywalls et la configuration de segments. ::: --- # File: autopilot-analysis --- --- title: "Analyse des paywalls et du marché" description: "Générez un plan de croissance basé sur les données, adapté à votre application." --- Suivez les étapes de cet article pour lancer l'analyse AI Growth Advisor et générer un plan de croissance. Si vous avez déjà généré un plan de croissance pour le placement cible, cette analyse produira de nouvelles hypothèses parmi lesquelles choisir. :::tip Assurez-vous de remplir les [conditions requises pour l'analyse](autopilot#prerequisites) avant de commencer. ::: ## Analyse du paywall \{#paywall-analysis\} ### Sélectionner un paywall à analyser \{#select-a-paywall-for-analysis\} 1. Ouvrez la page **AI Growth Advisor** et cliquez sur le bouton [Get Growth plan](https://app.adapty.io/ab-tests/analysis/start). 2. Sur la page **Paywall Diagnostic**, sélectionnez un **Placement** et un **Paywall** dans les menus déroulants. Adapty présélectionne le placement générant le plus de revenus et son paywall principal. Pour analyser un autre paywall, commencez par changer le placement. 3. Importez une capture d'écran. L'AI Growth Advisor a besoin d'une capture d'écran pour analyser le design et le contenu de votre paywall. 4. Vérifiez les produits actifs du paywall. Les fiches produit à droite affichent la durée d'abonnement, le prix et la période d'essai de chaque produit. 5. Cliquez sur **Confirm & Analyze** pour continuer. Adapty analyse votre paywall et affiche le rapport de diagnostic. ### Rapport d'analyse de paywall Après avoir sélectionné un paywall et téléchargé une capture d'écran, Adapty analyse votre paywall pour y identifier des modèles de conception établis, en mettant en évidence les bons choix et les axes d'amélioration. #### Ce qui fonctionne bien Cette section met en évidence votre utilisation de modèles établis qui maximisent la conversion. Par exemple : un badge d'économies visible, une section d'avis utilisateurs bien mise en avant ou des détails d'abonnement clairs. #### Ce qu'il faut corriger sur votre paywall Adapty regroupe ses recommandations en deux catégories : - **Recommandations basées sur des benchmarks** : suggestions fondées sur les données des applications les plus performantes dans votre catégorie. Chaque recommandation inclut une statistique de référence (par exemple, « Utilisé par 72 % des applications Éducation les plus performantes ») et une description de ce qu'il faut modifier. - **Recommandations d'analyse visuelle** : suggestions générées par l'IA à partir de la capture d'écran de votre paywall. Elles comprennent : des améliorations de contenu textuel, des modifications de mise en page, et bien plus encore. :::tip Votre [plan de croissance](autopilot-growth-plan) inclura des hypothèses basées sur les recommandations issues des benchmarks. Vous pouvez ajouter manuellement les suggestions d'analyse visuelle au plan. ::: Cliquez sur **Get Market Insights** pour continuer. ## Analyse du marché et de la concurrence \{#market-and-competitor-analysis\} :::note L'analyse du marché et de la concurrence nécessite d'avoir complété au préalable l'[analyse des paywalls](#paywall-analysis). ::: L'analyse Market Insights compare les prix et les métriques de conversion de votre application à ceux de ses concurrents et à la moyenne du secteur. Les comparaisons sont spécifiques à chaque pays. Pour établir un référentiel, Adapty agrège et analyse les données des applications App Store de votre sous-catégorie et de votre pays. Ces données ne sont pas disponibles publiquement ailleurs. ### Sélectionner des concurrents \{#select-competitors\} Sélectionnez jusqu'à 5 concurrents pour la comparaison. Adapty en choisit 5 automatiquement et en suggère 5 autres. Vous pouvez ajouter manuellement des applications via un lien App Store. Pour de meilleurs résultats, sélectionnez des applications avec un MRR supérieur au vôtre. Cliquez sur **Generate report** pour confirmer la liste et attendez la fin de l'analyse. ### Sélectionner un pays \{#select-a-country\} Utilisez le menu déroulant **Country** pour sélectionner l'un de vos principaux pays et obtenir une analyse détaillée. ### Répartition des revenus \{#revenue-distribution\} Ce graphique de répartition des revenus indique la provenance géographique de vos revenus, avec des détails en pourcentage. Il met en avant vos 5 premiers pays, qui constituent le cœur de l'analyse suivante. ### Tarifs des concurrents \{#competitor-pricing\} Le tableau des tarifs des concurrents compare les prix des abonnements de votre paywall à ceux de vos concurrents dans le [pays sélectionné](#select-a-country). Il inclut des colonnes séparées pour chaque durée d'abonnement. ### Entonnoir de conversion \{#conversion-funnel\} Le graphique affiche vos taux de conversion — Vues-vers-Essai, Essai-vers-Payant et Vues-vers-Payant — ainsi que les moyennes des applications similaires. ### Répartition des revenus par durée \{#revenue-distribution-by-duration\} Ce graphique montre quelles durées d'abonnement contribuent le plus à vos revenus, comparées à la moyenne du secteur. Si vos revenus sont fortement concentrés sur une seule durée, cela peut indiquer une opportunité d'optimiser votre stratégie de tarification. ### ARPU d'activation Le graphique **Activation ARPU: your app vs. category** compare le revenu moyen par nouvelle installation de votre app à la moyenne de la catégorie. Utilisez-le conjointement avec l'[entonnoir de conversion](#conversion-funnel) : - L'entonnoir montre combien d'utilisateurs paient. - L'ARPU d'activation indique le revenu moyen par utilisateur. Un taux de conversion élevé avec un ARPU d'activation faible peut indiquer des offres sous-tarifées. La métrique est **basée sur les cohortes**. Adapty prend les utilisateurs qui ont installé l'app au cours des 90 derniers jours et divise le revenu qu'ils ont généré par leur nombre. #### Comparaison avec d'autres métriques \{#comparison-to-other-metrics\} L'ARPU d'activation ne correspondra pas aux valeurs d'ARPU visibles ailleurs dans votre tableau de bord — chaque métrique mesure quelque chose de différent. - **[Le graphique analytique ARPU](arpu)** : inclut les renouvellements des anciennes cohortes, ce qui rend ce chiffre plusieurs fois supérieur à l'ARPU d'activation. - **[Graphique des revenus](revenue), filtre Période défini sur « Activation »** : ne comptabilise que le premier paiement de chaque utilisateur. Ne tient pas compte des renouvellements effectués par la cohorte dans la fenêtre de 90 jours. - **[Revenus par cohorte](analytics-cohorts) (90 jours)** : l'équivalent le plus proche — utilisez cette métrique comme référence. ## Étapes suivantes \{#next-steps\} Consultez [Exécuter votre plan de croissance](autopilot-execute-plan) pour apprendre à lancer des tests A/B basés sur les résultats de l'analyse. Vous pouvez toujours consulter le rapport d'analyse de votre plan de croissance — accédez à l'onglet **Analysis Results**. --- # File: autopilot-growth-plan --- --- title: "Gérer votre plan de croissance" description: "Ajoutez des hypothèses personnalisées, archivez-les et mettez à jour le plan de croissance." --- Après avoir terminé [l'analyse](autopilot-analysis), Adapty présente votre plan de croissance — une liste d'**hypothèses d'amélioration concrètes**. Chaque élément suggère un nouveau prix ou une amélioration visuelle. Ouvrez une hypothèse pour [la tester avec un test A/B](autopilot-execute-plan). Chaque placement dispose de son propre plan de croissance. À mesure que les conditions du marché évoluent, vous pouvez relancer l'analyse pour actualiser les suggestions. Les exécutions passées restent dans l'historique des versions. ## Hypothèses \{#hypotheses\} Passez d'un onglet à l'autre en haut du plan de croissance pour filtrer les hypothèses par type : - **Top priority** regroupe les hypothèses à fort impact qui méritent votre attention. Cet onglet est masqué lorsqu'aucune hypothèse n'est éligible. - **All** affiche toutes les hypothèses de votre plan actif. - Les hypothèses **Pricing** explorent de nouveaux prix ou configurations d'essai. Chacune est basée sur une recommandation spécifique issue du diagnostic paywall ou du rapport d'analyse du marché. - Les hypothèses **Visual** sont des suggestions d'amélioration visuelle. Elles peuvent concerner des modifications du texte, de la mise en page ou d'autres éléments visuels. - Les hypothèses [**Geo-pricing**](#geo-pricing-hypotheses) testent des ajustements de prix par pays. - Les hypothèses [**Archived**](#archive-a-hypothesis) sont des suggestions que vous avez retirées de votre plan actif. Vous pouvez les restaurer à tout moment. Vous pouvez [ajouter votre propre hypothèse](#add-your-own-hypothesis) ou [archiver](#archive-a-hypothesis) celles que vous ne souhaitez pas tester. Testez ces hypothèses une par une, dans l'ordre de votre choix. Les tests de geo-pricing font exception — leurs audiences ne se chevauchent pas, ils peuvent donc s'exécuter en parallèle. ### Hypothèses de geo-pricing \{#geo-pricing-hypotheses\} :::important Les achats uniques ne sont pas éligibles à l'optimisation des prix par région. ::: Ouvrez l'onglet **Geo-pricing** pour consulter la liste des recommandations de geo-pricing. Chaque recommandation cible un pays avec un seul changement de prix et s'exécute comme un test A/B distinct. Adapty détecte les pays qui nécessitent des ajustements de prix et fournit des recommandations basées sur les données, validées par l'[Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf). <br /> #### Comment Adapty formule ses suggestions de geo-pricing \{#how-adapty-makes-geo-pricing-suggestions\} - Les recommandations de prix sont basées sur les données de l'App Store. Le test A/B résultant peut s'exécuter sur l'App Store et Google Play. - Le pourcentage de variation de prix est le même pour toutes les durées d'abonnement. - Tous les prix sont arrondis au niveau de prix App Store le plus proche. - Les prix s'affichent en devise locale (par exemple, EUR ou GBP) si Adapty dispose de données de transaction pour ce pays. En l'absence de données locales, les prix sont affichés en USD. ### Badges de statut des hypothèses \{#hypothesis-status-badges\} 1. **Éclair** — indique les suggestions prioritaires. 2. **Statut de synchronisation du produit** — s'affiche lorsqu'une action sur un produit est requise pour lancer le test A/B. - **Draft** — la configuration du produit est incomplète (côté Adapty) - **Action required** — la configuration du produit est incomplète (côté Store) - **Pending...** — Adapty attend que le store finalise la révision ou la synchronisation initiale. - **Approved** — le produit a été approuvé par le store et est prêt pour les tests. - **Rejected** — le store a rejeté le produit. - **Not connected** — le produit n'est pas encore lié au store. 3. **Statut du test A/B** — s'affiche lorsque vous lancez le test A/B : - **Draft test** — le test est en brouillon mais pas encore en cours. - **Running** — le test est actif. - **Completed** — le test est terminé. - **Archived test** — le test a été archivé sans conclusion. ## Obtenir de nouvelles hypothèses générées par l'IA \{#get-new-ai-generated-hypotheses\} Après chaque test, Adapty met automatiquement à jour vos hypothèses en fonction des résultats. Pour récupérer les derniers prix des concurrents, les benchmarks de conversion et les tendances de catégorie, cliquez sur **Update** Refresh dans l'en-tête du plan de croissance — ou sur **Update Analysis** sur la page d'accueil de l'AI Growth Advisor. Cliquez sur **Get New Ideas** lorsque vous y êtes invité. Adapty ouvre l'assistant d'analyse avec votre placement présélectionné. Répétez l'analyse du paywall et la recherche sur les concurrents, et Adapty identifie de nouvelles hypothèses à partir des résultats. Sélectionnez celles que vous souhaitez ajouter, ou cliquez sur **Add All To Plan** Plus pour tout accepter. Les hypothèses nouvellement ajoutées apparaissent en haut de la liste. Vos hypothèses existantes générées par l'IA, vos hypothèses personnalisées et les tests A/B en cours ne sont pas affectés. Si vous quittez une mise à jour avant de la terminer, vous pouvez **la reprendre** pour continuer, ou **la supprimer** pour repartir de zéro. ## Ajouter votre propre hypothèse \{#add-your-own-hypothesis\} Cliquez sur **Add Hypothesis** Plus pour créer votre propre suggestion de prix ou visuelle. Remplissez le formulaire : titre, description et type d'hypothèse (**Monetization** ou **Visual**). - Sélectionnez les métriques que vous espérez améliorer dans le menu déroulant. - Les hypothèses de type Monetization nécessitent également de sélectionner des produits de test. ## Archiver une hypothèse \{#archive-a-hypothesis\} Pour archiver une hypothèse, cliquez sur le bouton Close, puis sur Skip pour confirmer. Vous pouvez éventuellement expliquer pourquoi — cela aide Adapty à affiner les suggestions futures. L'hypothèse est déplacée vers l'onglet **Archived**. Pour restaurer une hypothèse archivée dans votre plan actif, cliquez sur **Restore** sur la carte. ## Consulter et réutiliser d'anciennes hypothèses \{#revisit-and-reuse-old-hypotheses\} Pour parcourir les suggestions générées par des analyses passées, cliquez sur **Clock** Clock dans l'en-tête du plan de croissance. La fenêtre **Version history** liste toutes les exécutions passées pour le placement — date, paywall et nombre d'hypothèses acceptées à l'époque. Cliquez sur une exécution passée pour voir les hypothèses qu'elle a produites. Vous pouvez en ajouter n'importe lesquelles à votre plan actif avec **Add to Plan** Plus — pratique pour revenir sur des suggestions que vous n'aviez pas retenues la première fois. --- # File: autopilot-execute-plan --- --- title: "Exécuter votre plan de croissance" description: "Lancez des tests A/B à partir des hypothèses de votre plan de croissance." --- Vous pouvez lancer les tests dans n'importe quel ordre, mais vous devez les exécuter **un à la fois**. Étant donné que les audiences des tests de géo-tarification ne se chevauchent pas, ceux-ci peuvent être exécutés en parallèle. Une fois un test terminé, faites passer la stratégie gagnante au tour suivant. Chaque tour converge vers une configuration plus efficace pour votre application. Selon nos estimations, l'exécution de l'ensemble des tests recommandés pourrait augmenter vos revenus **jusqu'à 80 %**. :::important Chaque suggestion inclut la durée minimale du test A/B. Suivez ces recommandations pour obtenir les données les plus précises avant de passer à l'étape suivante. Vous devrez arrêter le test A/B manuellement. ::: Ouvrez une hypothèse et cliquez sur **Set Up & Run Test** pour lancer l'assistant de création de test A/B. ## Étape 1 : Consulter l'hypothèse \{#step-1-view-the-hypothesis\} La première étape présente un aperçu de l'hypothèse. Elle décrit les modifications suggérées et explique la logique qui les sous-tend. Cliquez sur « Set up & Run Test » pour passer à l'étape suivante. {/* TODO: REPLACE SCREENSHOT */} ## Étape 2 : Créer de nouveaux produits \{#step-2-create-new-products\} Si le test implique un changement de prix, la deuxième étape vous aide à créer de nouveaux produits pour la variante du test. Les hypothèses visuelles passent cette étape. * Cliquez sur **Create a new product and push to stores** pour créer un nouveau produit de zéro. * Cliquez sur **Connect an existing product** si le produit nécessaire existe déjà dans la configuration de votre store. ## Étape 3 : Configurer le segment et le paywall \{#step-3-set-up-segment-and-paywall\} La troisième étape vous permet de configurer la variante du paywall pour le test. Adapty vous invite à dupliquer le paywall et à appliquer les modifications suggérées. Pour les **hypothèses de géo-tarification**, l'assistant vous invite à sélectionner un segment géo-délimité existant ou à en créer un nouveau. Cliquez sur **Next** une fois que le nouveau paywall est prêt et que le segment est configuré. ## Étape 4 : Vérifier et lancer \{#step-4-review--launch\} La dernière étape est un récapitulatif du test à venir. Elle comprend : - Les métriques clés pour la **Variante A vs Variante B** — nom du paywall, sélection de produits, durée d'essai et prix. - La **Durée**, le **Trafic** (répartition) et les **Abonnés** (taille minimale de l'échantillon) pour le test. - Une section **How to interpret results** qui décrit les signaux indiquant la réussite du test. Vérifiez la configuration et cliquez sur **Launch Test** pour démarrer le test A/B. --- # File: analytics --- --- title: "Analytics" description: "Fonctionnalités d'Adapty Analytics" --- Adapty Analytics est une suite d'outils puissants pour la visualisation et l'analyse de données. Conçue pour les équipes de développement d'applications, elle se concentre sur les performances financières de votre app et le comportement de vos utilisateurs. En plus des métriques standard disponibles dans les analytics de votre store (comme les revenus ou les installations), Adapty calcule des métriques composites : valeur vie utilisateur, analyse de cohortes, et bien d'autres. Des sections dédiées analysent les comportements qui entraînent des pertes de revenus : graphiques de rétention, données de résolution de problèmes de facturation. Parcourez les graphiques pour mieux comprendre le comportement des utilisateurs et optimisez votre application grâce à des décisions basées sur les données. Lisez le guide [Comment fonctionne Adapty Analytics](how-adapty-analytics-works) pour en savoir plus sur la façon dont les données sont collectées et traitées. Pour un aperçu rapide de toutes les métriques disponibles et de leurs différences, consultez l'article [Tableau de comparaison des métriques](metric-comparison-table). :::tip Activez [Adapty Attribution](adapty-user-acquisition) pour enrichir les capacités analytiques d'Adapty. Adapty Attribution utilise les données marketing pour analyser la relation entre les campagnes publicitaires et le comportement des utilisateurs. Ses graphiques offrent une vue complète de l'économie de votre application, avec des calculs de ROI et des données d'attribution précises. ::: ## Vue d'ensemble \{#overview\} :::link Article principal : [Page Vue d'ensemble d'Analytics](overview) ::: La page Vue d'ensemble présente un résumé en un coup d'œil des métriques de performance clés de vos applications. Pour personnaliser les graphiques affichés, cliquez sur **Edit Metrics**. ## Graphiques \{#charts\} :::link Article principal : [Graphiques Analytics](charts) ::: L'onglet Graphiques visualise les métriques liées aux revenus, aux abonnements, aux essais et aux problèmes de facturation. ## LTV \{#ltv\} :::link Article principal : [Valeur Vie (LTV)](ltv) ::: L'onglet LTV affiche un graphique de la valeur vie de vos utilisateurs dans le temps. ## Cohortes \{#cohorts\} :::link Article principal : [Analyse de cohortes](analytics-cohorts) ::: L'onglet Cohortes vous permet d'isoler des groupes d'utilisateurs en fonction de leur date d'installation et affiche les taux de conversion de chaque groupe. ## Entonnoirs \{#funnels\} :::link Article principal : [Entonnoirs](analytics-funnels) ::: L'onglet Entonnoirs visualise les étapes d'engagement des utilisateurs avec votre app. Vous pouvez voir quelle proportion des installations débouche sur des abonnements, et combien de temps les utilisateurs restent abonnés. Repérez les points de sortie les plus fréquents pour optimiser votre stratégie. ## Rétention \{#retention\} :::link Article principal : [Rétention](analytics-retention) ::: L'onglet Rétention affiche un graphique de la rétention des utilisateurs dans le temps. ## Conversion \{#conversion\} :::link Article principal : [Conversion](analytics-conversion) ::: L'onglet Conversion affiche des graphiques des taux de conversion aux différentes étapes du parcours utilisateur. Il met en évidence les choix les plus courants aux points de transition, comme le passage de l'essai à l'abonnement, ou d'un problème de facturation au renouvellement réussi. ## Analytics prédictive \{#predictive-analytics\} :::link Article principal : [LTV et revenus prédits](predicted-ltv-and-revenue) ::: Les utilisateurs des offres payantes peuvent consulter des prédictions de LTV et de revenus par cohorte. Adapty analyse les données historiques à l'aide d'algorithmes avancés de machine learning pour estimer les valeurs futures. ## Filtres et contrôles de regroupement \{#filters-and-grouping-controls\} :::link Article principal : [Contrôles](controls-filters-grouping-compare-proceeds) ::: Utilisez les filtres et les contrôles de regroupement pour afficher les données d'un segment d'utilisateurs spécifique. Par exemple, vous pouvez filtrer le graphique de rétention par store et comparer le comportement des utilisateurs entre Android et iOS. Dans n'importe quelle vue d'Adapty Analytics, vous pouvez : * Modifier la plage de dates pour la visualisation des données. * Filtrer les données par store, attribution ou d'autres paramètres. * Regrouper les données dans le graphique par pays, [segment d'utilisateurs](segments) ou d'autres critères. Les [Graphiques](charts) permettent également de comparer la même métrique sur deux périodes différentes. ## Recevoir des rapports analytics automatisés \{#receive-automated-analytics-reports\} :::link Article principal : [Rapports](reports) ::: Adapty peut envoyer des rapports automatisés avec des données analytics directement dans votre boîte mail. Vous pouvez configurer le contenu et la fréquence de ces rapports. ## Voir aussi \{#see-also\} * [Adapty Attribution](adapty-user-acquisition) * [Exporter les analytics via l'API](export-analytics-api) * [Intégrations tierces](configuration) --- # File: how-adapty-analytics-works --- --- title: "Fonctionnement des analytiques Adapty" description: "Découvrez comment les analytiques Adapty fonctionnent pour suivre efficacement les performances des abonnements." --- Cet article décrit le fonctionnement des analytiques Adapty : quelles données elles affichent, d'où viennent ces données et comment elles sont traitées. Il explique aussi les choix de conception qui distinguent Adapty Analytics, et en quoi ils vous sont utiles. ## Adapty Analytics vs analytiques du store \{#adapty-analytics-vs-store-analytics\} - **Variété des données** : les stores ne peuvent afficher que leurs propres données et n'ont pas accès au comportement des utilisateurs dans l'app. Adapty peut combiner les données de plusieurs stores, ainsi que des sources supplémentaires — plateformes marketing et réseaux publicitaires. Le SDK Adapty suit les interactions des utilisateurs avec les paywalls et les onboardings. - **Fréquence de mise à jour** : les app stores mettent généralement leurs données à jour une fois par jour, ce qui peut limiter votre capacité à prendre des décisions en temps réel. Adapty propose des analytiques [proches du temps réel](#data-processing). - **Métriques avancées** : les app stores affichent des métriques de base telles que les téléchargements, les revenus et les taux de rétention. Adapty calcule également des métriques avancées, comme les revenus récurrents ou le revenu moyen par utilisateur. Des sections dédiées analysent les problèmes d'abonnement : attrition des utilisateurs, échecs de facturation, etc. Consultez l'article [Tableau comparatif des métriques](metric-comparison-table) pour la liste complète. - **Prédictions** : Adapty utilise des algorithmes avancés de machine learning pour [prédire la LTV et les revenus futurs](predicted-ltv-and-revenue). ## Les données et leurs sources \{#data-and-its-sources\} Adapty Analytics traite les données suivantes dans des [graphiques et tableaux](analytics) : - Les [événements d'abonnement](events) générés tout au long du cycle de vie de l'utilisateur — démarrages d'essai, achats, renouvellements, annulations, échecs de facturation, remboursements. Adapty les agrège dans les [graphiques analytiques](analytics) et les transmet en temps réel aux [webhooks](webhook), au [fil d'événements](event-feed) et aux [intégrations basées sur les événements](analytics-integration). - Les [données de transaction](revenue) — revenus, remboursements, pays de l'acheteur, etc. - Les **données applicatives** telles que le nombre d'installations ou les [interactions avec les paywalls](paywalls). - Les [données d'attribution pour les transactions](attribution-integration) : sources de trafic et campagnes publicitaires. Ces données proviennent des sources suivantes : - Le <InlineTooltip tooltip="SDK Adapty">[iOS](ios-sdk-overview), [Android](android-sdk-overview), [React Native](react-native-sdk-overview), [Flutter](flutter-sdk-overview), [Unity](unity-sdk-overview), [Kotlin Multiplatform](kmp-sdk-overview), [Capacitor](capacitor-sdk-overview) </InlineTooltip> remonte les données de comportement utilisateur depuis l'intérieur de l'app. Si Adapty gère votre flux d'achat, le SDK partage des informations de première main sur les événements d'achat. Si vous utilisez le [mode observateur](observer-vs-full-mode), le SDK reçoit les [rapports d'événements](report-transactions-observer-mode) que vous configurez manuellement. - Les stores utilisent une communication serveur à serveur pour notifier Adapty des transactions (essais, renouvellements d'abonnement, annulations, etc.). - Les [services d'attribution](attribution-integration) tiers (Appsflyer, Adjust, Branch, etc.) partagent les données sur les sources de trafic et les campagnes publicitaires. Si vous configurez [Adapty Attribution](adapty-user-acquisition), Adapty peut gérer vos données de campagne publicitaire de manière autonome, sans passer par cette étape. - Les utilisateurs peuvent [importer manuellement des données de transactions historiques](importing-historical-data-to-adapty) pour qu'Adapty les analyse et les affiche. Un problème avec l'une des sources peut impacter la qualité globale de vos données analytiques. Consultez la section [Dépannage](#troubleshooting) pour plus d'informations. ## Intégrations tierces \{#third-party-integrations\} Vous pouvez activer [Adapty Attribution](adapty-user-acquisition) pour enrichir les capacités analytiques d'Adapty avec des données de campagnes publicitaires. Cela vous aidera à découvrir les corrélations entre les dépenses publicitaires et le comportement des utilisateurs. De même, vous pouvez [exporter](analytics-integration) des données analytiques vers des plateformes tierces ou un [serveur privé](webhook), et analyser les données d'Adapty sur une autre plateforme. ## Traitement des données \{#data-processing\} Adapty propose des analytiques proches du temps réel, ce qui permet aux utilisateurs de réagir rapidement aux changements dans les métriques clés. - **Graphiques analytiques** : les données apparaissent avec un **délai de 15 à 30 minutes** après qu'une transaction a lieu. Adapty a besoin de ce délai pour valider la transaction, appliquer les commissions et taxes, et agréger les données. - **[Fil d'événements](event-feed)** : se met à jour en temps réel, dès que les stores délivrent un événement. - **[Webhooks](webhook) et intégrations basées sur les événements** (AppsFlyer, Branch, etc.) : Adapty transmet les événements au fur et à mesure — le délai de 15 à 30 minutes des graphiques analytiques ne s'applique pas. Le service destinataire peut introduire son propre délai de traitement. Chaque interface a son propre timing. Un même événement peut apparaître à des moments légèrement différents dans les graphiques, le fil d'événements et vos intégrations. De petits décalages entre eux sont attendus. ## Commissions et taxes \{#commissions-and-taxes\} Lorsque vous consultez les graphiques liés aux revenus, vous pouvez choisir entre **Revenus bruts**, **Revenus après commissions** et **Revenus après commissions et taxes**. ### Commissions \{#commissions\} Les stores déduisent une commission de chaque transaction. Si votre organisation est inscrite à un programme de commission réduite, modifiez vos paramètres Adapty pour ajuster les calculs du taux de commission : * [Programme Small Business de l'App Store](app-store-small-business-program) * [Programme de frais de service réduits](google-reduced-service-fee) de Google Les stores signalent automatiquement si d'autres facteurs réduisent votre commission de transaction : * [Renouvellements pour les abonnements App Store de plus d'un an](https://developer.apple.com/app-store/subscriptions/) — commission de 15 % * Taux spécifiques par pays (par exemple, [21 % pour les apps App Store distribuées au Japon](https://developer.apple.com/support/app-distribution-in-japan/#business-terms)) ### Taxes \{#taxes\} **Adapty ne calcule pas les taxes.** Apple et Google déterminent le taux de taxe applicable à chaque transaction et le communiquent à Adapty, qui affiche la valeur telle quelle. Le taux de taxe affiché pour une transaction donnée dépend de : - Le **pays de facturation de l'acheteur** et le taux de taxe local en vigueur. - Les **règles de gestion fiscale du store**. Dans certaines juridictions, le store collecte et reverse la taxe au nom du développeur ; dans d'autres, c'est la responsabilité du développeur. - Pour les transactions App Store, la **catégorie fiscale** assignée à l'app ou à l'achat intégré (livres, actualités, vidéos, etc.) — les catégories peuvent être taxées à des taux différents selon les règles locales. Les taux de taxe peuvent varier significativement d'une app à l'autre — et même entre transactions au sein d'une même app — en raison de la diversité des pays des acheteurs, des règles de gestion fiscale des stores et (pour l'App Store) de la catégorie fiscale attribuée. Pour les règles officielles, consultez la documentation officielle des stores : - [App Store : Comprendre les taxes](https://developer.apple.com/help/app-store-connect/making-payments-to-apple/understanding-taxes/) - [Google Play : Taux de taxe et TVA](https://support.google.com/googleplay/android-developer/answer/138000) ## Dépannage \{#troubleshooting\} :::link Article principal : [Écarts et dépannage](discrepancies-and-troubleshooting) ::: * Une source de données mal configurée ou manquante peut affecter négativement l'ensemble du système analytique. Si vous rencontrez des problèmes de données, vérifiez que vos intégrations avec les stores et les plateformes tierces sont configurées et actives. * Si vous comparez les graphiques Adapty à d'autres plateformes analytiques, vous pouvez constater des écarts. Il s'agit d'un comportement attendu qui peut résulter de différences dans le traitement des données. Lisez l'article [guide des écarts](discrepancies-and-troubleshooting) pour en savoir plus sur les causes courantes des écarts de données. --- # File: metric-comparison-table --- --- title: "Comparer différentes métriques" description: "Tableaux de référence pour les métriques d'analytics Adapty, organisés par catégorie." --- Voici un aperçu des métriques disponibles dans Adapty Analytics. Utilisez-le pour comprendre ce que mesure chaque métrique et en quoi elle diffère des métriques associées. Pour une explication approfondie du fonctionnement du traitement des données analytics par Adapty, consultez [Comment fonctionne Adapty Analytics](how-adapty-analytics-works). :::note Cet article ne couvre pas les métriques [Adapty Attribution](adapty-user-acquisition). Lisez [Adapty Attribution analytics](ua-analytics) pour en savoir plus sur les métriques de campagnes publicitaires (Dépenses, CPI, ROAS, CTR, entre autres). ::: ## Métriques globales \{#global-metrics\} Les métriques globales suivent les performances de l'ensemble de votre application, sur tous les placements et paywalls. ### Revenus \{#revenue\} Ces métriques mesurent combien d'argent l'application génère et depuis quelles sources. | Métrique | Description | Différence clé | |--------|-------------|----------------| | [Revenue](revenue) | Revenus totaux issus des abonnements et des achats uniques, moins les remboursements | Revenus réellement générés. Peut afficher les revenus bruts, les revenus après commission, ou les revenus après taxes et commission selon les [contrôles du graphique](controls-filters-grouping-compare-proceeds) | | [MRR](mrr) | Revenus récurrents mensuels issus des abonnements actifs | Revenus mensuels prévisibles de votre application. Exclut les achats uniques et les abonnements non récurrents. | | [ARR](arr) | Revenus récurrents annuels issus des abonnements actifs | Calculé comme le MRR mais à l'échelle annuelle. Utile pour projeter les revenus annuels | | [ARPU](arpu) | Revenu moyen par utilisateur | Divise les revenus par le nombre total d'utilisateurs — payants et non payants. Indique le revenu moyen généré par chaque utilisateur | | [ARPPU](arppu) | Revenu moyen par utilisateur payant | Ne compte que les utilisateurs ayant effectué un achat pendant la période sélectionnée, y compris les transactions remboursées. Toujours supérieur à l'ARPU | | [LTV (lifetime value)](ltv) | Revenus des clients payants divisés par le nombre de clients payants dans une cohorte | Valeur réalisée par client payant dans le temps. Contrairement à l'ARPPU (période unique), la LTV représente les revenus totaux sur toute la durée de la relation client. Peut être consultée par renouvellements ou par jours calendaires | | [LTV prédite](predicted-ltv-and-revenue) | Valeur estimée à vie par utilisateur dans une cohorte | Estimation prospective. Contrairement à la LTV réalisée, projette la valeur future à partir des tendances historiques de rétention des cohortes. Disponible pour 3, 6, 9, 12, 18 et 24 mois | | [Revenus prédits](predicted-ltv-and-revenue) | Estimation des revenus totaux qu'une cohorte va générer | Estimation prospective. Contrairement aux revenus réalisés, prédit le total qu'une cohorte générera sur la période sélectionnée. Mis à jour quotidiennement | | [Non-subscriptions](non-subscriptions) | Nombre d'achats intégrés : consommables, non-consommables et abonnements non renouvelables | Exclut les abonnements à renouvellement automatique. | | [Refund events](refund-events) | Nombre d'achats ou d'abonnements remboursés | Attribué à la date du remboursement, et non à la date d'achat initiale. | | [Refund money](refund-money) | Montant total remboursé pendant la période sélectionnée | Impact financier des remboursements. Calculé avant les frais du store. Contrairement à Refund events (un comptage), cette métrique indique le montant monétaire | ### Abonnés et conversion \{#subscribers-and-conversion\} Ces métriques suivent comment les utilisateurs entrent dans l'application et progressent dans l'entonnoir. | Métrique | Description | Différence clé | |--------|-------------|----------------| | [Installs](installs) | Nombre d'installations de l'application pendant la période | Compte l'un des éléments suivants selon [la définition d'installation](general#4-installs-definition-for-analytics) : <br /> • Installations sur l'appareil (un utilisateur qui réinstalle l'application est compté à nouveau) <br /> • Utilisateurs uniques (ne compte que les utilisateurs qui ont défini un `customer_user_id`. Les utilisateurs anonymes sont entièrement exclus — si aucun utilisateur n'est identifié, le comptage est 0) | | [New trials](new-trials) | Essais activés pendant la période | Compte chaque début d'essai, même si l'essai a déjà expiré ou converti en payant au moment où vous consultez le graphique | | [Active trials](active-trials) | Nombre d'essais qui n'ont pas encore expiré | Ne compte que les essais actifs à la fin de la période | | [New subscriptions](reactivated-subscriptions) | Abonnements activés pour la première fois pendant la période, incluant les premiers achats sans essai et les conversions essai-vers-payant | Exclut les renouvellements et réactivations. Différent de l'événement d'intégration `subscription_started`, qui ne compte que les premiers achats sans essai — les conversions d'essai déclenchent `trial_converted` à la place | | [Active subscriptions](active-subscriptions) | Nombre d'abonnements payants qui n'ont pas encore expiré | Exclut les essais et les abonnements avec renouvellement annulé | | [Install to trial](analytics-conversion#install---trial) | Pourcentage d'utilisateurs installant l'application qui ont démarré un essai | Le dénominateur inclut tous les utilisateurs ayant installé l'app, pas seulement les visiteurs du paywall, ce qui peut donner un taux inférieur à Paywall view to trial. Les deux métriques peuvent aussi diverger si l'application n'enregistre pas les vues de paywall. Cela peut se produire avec un paywall personnalisé qui n'appelle pas `logShowFlow` (SDK iOS v4+) / `logShowPaywall`, ou lorsqu'un utilisateur démarre son essai depuis un [achat intégré promu](https://developer.apple.com/documentation/storekit/supporting-promoted-in-app-purchases-in-your-app). | | [Paywall view to trial](analytics-conversion#paywall-view---trial) | Pourcentage de visiteurs du paywall qui ont démarré un essai | Ne compte que les utilisateurs qui ont vu un paywall, donc le taux peut être supérieur à Install to trial | | [Trial to paid](analytics-conversion#trial---paid) | Pourcentage d'utilisateurs en essai qui ont souscrit un abonnement | Mesure la qualité de l'essai et l'efficacité de la conversion. Contrairement à Install to paid, se concentre uniquement sur les utilisateurs qui ont terminé un essai | | [Install to paid](analytics-conversion#install---paid) | Pourcentage d'utilisateurs installant l'app qui ont souscrit un premier abonnement | Compte tous les utilisateurs ayant installé, pas seulement les visiteurs du paywall. Le taux peut être inférieur à Paywall view to paid. Inclut les achats directs et les conversions essai-vers-payant | | [Paywall view to paid](analytics-conversion#paywall-view---paid) | Pourcentage de visiteurs du paywall qui ont finalement souscrit un abonnement | Ne compte que les utilisateurs qui ont vu un paywall, donc le taux peut être supérieur à Install to paid. Inclut les utilisateurs qui ont d'abord terminé un essai | ### Rétention et renouvellement d'abonnement \{#retention-and-subscription-renewal\} Ces métriques suivent à quel point l'application fidélise les abonnés payants dans le temps. | Métrique | Description | Différence clé | |--------|-------------|----------------| | [Retention](analytics-retention) | Part des abonnés d'origine restant après chaque période de facturation — 1er renouvellement, 2e renouvellement, etc. | Suit les abonnés à partir du premier paiement. Contrairement aux métriques période à période ci-dessous, compare toujours par rapport au groupe d'origine, ce qui donne une vue d'ensemble en un coup d'œil | | [Paid to 2nd period](analytics-conversion#paid---2nd-period) | Pourcentage de nouveaux abonnés ayant renouvelé pour la deuxième période | Mesure la transition entre deux périodes adjacentes spécifiques. Contrairement à la Rétention, se concentre sur le renouvellement le plus critique — le premier | | [2nd to 3rd period](analytics-conversion#2nd-period---3rd-period) | Pourcentage de renouvellement de la 2e à la 3e période | Indique la stabilité de la rétention précoce après le renouvellement initial | | [3rd to 4th period](analytics-conversion#3rd-period---4th-period) | Pourcentage de renouvellement de la 3e à la 4e période | Indicateur de rétention à moyen terme | | [4th to 5th period](analytics-conversion#4th-period---5th-period) | Pourcentage de renouvellement de la 4e à la 5e période | Indicateur de fidélité à long terme | | [6 Months+](analytics-conversion#6-months-) | Pourcentage de nouveaux abonnés restant abonnés pendant plus de 6 mois | Mesure le temps calendaire, pas le nombre de renouvellements. Un abonné annuel est considéré comme retenu à 6 mois même sans renouvellement | | [1 Year+](analytics-conversion#1-year-) | Pourcentage de nouveaux abonnés restant abonnés pendant plus de 12 mois | Jalon de rétention annuelle | | [2 Years+](analytics-conversion#2-years-) | Pourcentage de nouveaux abonnés restant abonnés pendant plus de 24 mois | Jalon de rétention à long terme | ### Désabonnement \{#churn\} Ces métriques mesurent combien d'abonnés et d'utilisateurs en essai l'application perd. | Métrique | Description | Différence clé | |--------|-------------|----------------| | [Trials renewal cancelled](trials-renewal-cancelled) | Essais pour lesquels l'utilisateur a désactivé le renouvellement automatique | L'utilisateur conserve l'accès à l'essai jusqu'à son expiration mais ne sera pas converti en payant automatiquement. Contrairement à Subscriptions renewal cancelled, s'applique aux utilisateurs en essai qui n'ont pas encore payé | | [Expired (churned) trials](expired-churned-trials) | Essais expirés — l'utilisateur a perdu l'accès aux fonctionnalités premium | L'utilisateur a déjà perdu l'accès. Attribué à la date d'expiration, même si l'utilisateur a annulé le renouvellement lors d'une période précédente. Peut être regroupé par raison (volontaire ou facturation) | | [Subscriptions renewal cancelled](cancelled-subscriptions) | Abonnements pour lesquels l'utilisateur a désactivé le renouvellement automatique | L'utilisateur a encore accès jusqu'à la fin de la période. Signal de risque de désabonnement, pas un désabonnement réel — l'utilisateur peut réactiver le renouvellement automatique avant la fin de la période | | [Churned (expired) subscriptions](churned-expired-subscriptions) | Abonnements expirés — l'utilisateur a perdu l'accès aux fonctionnalités premium | Désabonnement réel. L'utilisateur a déjà perdu l'accès. Attribué à la date d'expiration, même si l'utilisateur a annulé le renouvellement lors d'une période précédente. Peut être regroupé par raison (volontaire ou facturation) | ### Problèmes de facturation et récupération des revenus \{#billing-issues-and-revenue-recovery\} Ces métriques suivent l'efficacité avec laquelle l'application récupère les revenus perdus en raison de problèmes de facturation. | Métrique | Description | Différence clé | |--------|-------------|----------------| | [Grace period](grace-period) | Abonnements entrés en délai de grâce suite à un échec de facturation | Inclut les utilisateurs ayant dépassé le délai de grâce et ayant perdu l'accès | | [Grace period to paid](analytics-conversion#grace-period---paid) | Pourcentage d'utilisateurs en délai de grâce ayant renouvelé avant la fin du délai | Un taux (%). Répond à la question « quelle part des utilisateurs en délai de grâce s'est rétablie ? » | | [Grace period converted](grace-period-converted) | Nombre absolu d'abonnements en délai de grâce ayant été renouvelés avec succès | Mêmes événements que Grace period to paid, mais affichés sous forme de comptage plutôt que de pourcentage | | [Grace period converted revenue](grace-period-converted-revenue) | Revenus issus des récupérations en délai de grâce | Impact financier de la fonctionnalité de délai de grâce | | [Billing issue](billing-issue) | Abonnements entrés en état de problème de facturation | Commence après l'expiration du délai de grâce. Contrairement à Grace period, ne compte que les utilisateurs ayant déjà perdu l'accès premium | | [Billing issue to paid](analytics-conversion#billing-issue---paid) | Pourcentage d'utilisateurs avec un problème de facturation ayant renouvelé avant la fin du cycle de facturation | Un taux (%). Répond à la question « quelle part des utilisateurs avec un problème de facturation s'est rétablie ? » | | [Billing issue converted](billing-issue-converted) | Nombre absolu d'abonnements avec problème de facturation ayant été renouvelés avec succès | Un comptage des abonnements avec problème de facturation ayant été renouvelés avec succès. Mêmes événements que Billing issue to paid, mais affichés sous forme de comptage plutôt que de pourcentage | | [Billing issue converted revenue](billing-issue-converted-revenue) | Revenus issus des récupérations de problèmes de facturation | Impact financier de la récupération des problèmes de facturation | ## Métriques de paywall, de placement et d'onboarding \{#paywall-placement-and-onboarding-metrics\} Ces métriques sont calculées pour des [paywalls](paywall-metrics), [placements](placement-metrics) et onboardings individuels. Elles mesurent les performances d'un paywall ou d'un placement spécifique plutôt que de l'application dans son ensemble. La colonne **Métrique globale associée** indique la métrique correspondante dans la section analytics globale. | Métrique | Description | Différence clé | Métrique globale associée | |--------|-------------|----------------|---------------| | [Proceeds](paywall-metrics#proceeds) | Revenus après taxes et commission pour un placement individuel | Équivalent à [Revenue](revenue) après taxes et commission | [Revenue](revenue) | | [ARPPU](paywall-metrics#arppu) | Revenu moyen par utilisateur payant pour ce paywall ou placement | Même calcul que l'ARPPU global mais limité à un seul paywall ou placement | [ARPPU](arppu) | | [ARPAS](paywall-metrics#arpas) | Revenus divisés par le nombre d'abonnés actifs (essai et payants) | Compte les utilisateurs en essai. Contrairement à l'ARPPU, reflète le potentiel de revenus de l'ensemble de la base d'abonnés | — | | [Views](paywall-metrics#views) | Nombre total de fois qu'un paywall ou placement a été affiché | Compte chaque affichage. Un seul utilisateur qui voit le même paywall deux fois compte pour 2 vues | — | | [Unique views](paywall-metrics#unique-views) | Nombre d'utilisateurs uniques ayant vu un paywall ou placement | Chaque utilisateur compté une seule fois, quel que soit le nombre de fois qu'il l'a vu. Contrairement à Views, mesure la portée plutôt que la fréquence d'engagement | — | | [CR to purchases](paywall-metrics#cr-to-purchases) | Achats divisés par le nombre total de vues | Utilise le nombre total de vues (y compris les vues répétées par le même utilisateur) comme dénominateur | [Paywall view to paid](analytics-conversion#paywall-view---paid) | | [Unique CR to purchases](paywall-metrics#unique-conversion-rate-cr-to-purchases) | Achats divisés par les vues uniques | Utilise les vues uniques comme dénominateur. Taux plus élevé que le CR non unique car les visiteurs récurrents ne sont comptés qu'une fois | [Paywall view to paid](analytics-conversion#paywall-view---paid) | | [CR to trials](paywall-metrics#unique-cr-to-trials) | Essais démarrés divisés par le nombre total de vues | Mesure l'efficacité avec laquelle un paywall convertit les vues en essais | [Paywall view to trial](analytics-conversion#paywall-view---trial) | | [Unique CR to trials](paywall-metrics#unique-cr-to-trials) | Essais démarrés divisés par les vues uniques | Calculé comme CR to trials mais avec les visiteurs uniques comme dénominateur | [Paywall view to trial](analytics-conversion#paywall-view---trial) | | [Purchases](paywall-metrics#purchases) | Nombre total de transactions pour ce paywall : nouveaux achats, conversions d'essai, mises à niveau, rétrogradations et abonnements de retour | Exclut les renouvellements. | [Revenue](revenue) | | [Trials](paywall-metrics#trials) | Total des essais activés via ce paywall | Limité à ce paywall uniquement | [New trials](new-trials) | | [Trials canceled](paywall-metrics#trials-canceled) | Nombre d'essais pour lesquels l'utilisateur a désactivé le renouvellement automatique | Limité aux essais de ce paywall uniquement | [Trials renewal cancelled](trials-renewal-cancelled) | | [Refund rate](paywall-metrics#refund-rate) | Remboursements divisés par les premiers achats (renouvellements exclus) | Un taux (%), pas un comptage. Normalise les remboursements par rapport au nombre d'achats | [Refund events](refund-events) (comptage, pas taux) | | Completions | Nombre de fois où des utilisateurs ont terminé un flow d'onboarding du premier au dernier écran | Placement et onboarding uniquement. Compte chaque complétion, y compris les complétions répétées par le même utilisateur | — | | Unique completions | Nombre d'utilisateurs uniques ayant terminé un flow d'onboarding | Placement et onboarding uniquement. Chaque utilisateur compté une seule fois. Contrairement à Completions, mesure combien d'individus ont terminé le flow | — | | Unique completions rate | Complétions uniques divisées par les vues uniques | Placement et onboarding uniquement. Mesure l'efficacité de l'onboarding : quelle part des utilisateurs qui l'ont commencé l'ont réellement terminé | — | --- # File: overview --- --- title: "Page de vue d'ensemble des analytics" description: "Consultez plusieurs graphiques d'analytics Adapty sur une même page pour avoir une vue d'ensemble des performances de votre application" --- La [page Vue d'ensemble](https://app.adapty.io/overview) affiche les métriques combinées de toutes vos applications au même endroit. C'est la page d'accueil du tableau de bord, également accessible depuis le menu de gauche. Pour voir les données d'une seule application, ouvrez un [graphique](charts) individuel. ## Graphiques \{#charts\} La Vue d'ensemble affiche un sous-ensemble personnalisable des [graphiques d'analytics](charts) d'Adapty. Pour les descriptions et un tableau comparatif de tous les graphiques disponibles, consultez le [tableau de comparaison des métriques](metric-comparison-table). Pour personnaliser les graphiques affichés et leur ordre, cliquez sur **Edit** en haut à droite. Vous pouvez alors supprimer, ajouter ou réorganiser les graphiques : Les graphiques suivants sont disponibles : - [Revenue](revenue) - [MRR](mrr) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) - [ARPAS](placement-metrics#arpas) - [Installs](installs) - [New trials](new-trials) - [New subscriptions](reactivated-subscriptions) - [Active trials](active-trials) - [Active subscriptions](active-subscriptions) - [New non-subscriptions](non-subscriptions) - [Refund events](refund-events) - [Refund money](refund-money) - [Subscriptions renewal canceled](cancelled-subscriptions) - [Conversion rate from Install to Trial, Install to Paid, and Trial to Paid](analytics-conversion) ## Contrôles \{#controls\} La page Vue d'ensemble prend en charge la plupart des [contrôles d'analytics](controls-filters-grouping-compare-proceeds), notamment le filtrage, le regroupement et la comparaison de périodes. La fonctionnalité propre à la Vue d'ensemble est le regroupement et le filtrage par application. Comme la page combine les données de toutes vos applications, la vue par application montre la contribution de chacune à vos métriques métier : ## Nombre d'installations et fuseau horaire \{#install-count-and-timezone\} La Vue d'ensemble combine les données de toutes vos applications en utilisant **ses propres paramètres de fuseau horaire et de comptage des installations** — les valeurs par application ne s'appliquent pas ici. - **Installs** : choisissez comment comptabiliser les installations. **By device installations** traite chaque installation sur un appareil — y compris les réinstallations — comme distincte. **By unique users** ne compte que la première installation par utilisateur identifié. Pour modifier ce paramètre, cliquez sur **Edit Metrics** et sélectionnez une [autre option](general#4-installs-definition-for-analytics) dans le menu déroulant. - **Timezone** : pour modifier le fuseau horaire de la Vue d'ensemble, cliquez sur **Edit Metrics** et sélectionnez un fuseau horaire dans le menu déroulant. C'est particulièrement utile si différentes applications de votre compte utilisent des fuseaux horaires différents. --- # File: controls-filters-grouping-compare-proceeds --- --- title: "Contrôles analytiques" description: "Filtrez, regroupez et comparez vos données analytiques Adapty." --- Adapty propose des contrôles pour affiner les données dans chaque onglet analytique : plage de temps, comparaison de périodes, filtrage, regroupement et visualisation de graphique. La disponibilité varie selon l'onglet. **Contrôles disponibles par onglet analytique :** | Contrôle | Graphiques | Cohortes | Entonnoirs | Rétention | Conversion | LTV | | :--- | :---: | :---: | :---: | :---: | :---: | :---: | | Plage de dates | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Comparaison de périodes | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Filtre | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Regroupement | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | Visualisation de graphique | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Vue tableau | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Export CSV | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Commissions et taxes | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ### Définir la plage de dates \{#set-the-date-range\} Utilisez le calendrier **Date range** au-dessus de chaque graphique pour choisir la période. Les analyses Adapty utilisent le **fuseau horaire UTC** ; la [page Overview](overview) dispose de son propre fuseau horaire configurable. #### Plages prédéfinies \{#preset-ranges\} Utilisez l'option **Custom** pour spécifier des dates de début et de fin personnalisées. Les préréglages disponibles sont : | Préréglage | Début | Fin | | --- | --- | --- | | Last 7 days | Il y a 6 jours | Aujourd'hui | | Last 28 days | Il y a 27 jours | Aujourd'hui | | Last month | Même date le mois précédent | Aujourd'hui | | Last 3 months | Il y a 3 mois | Aujourd'hui | | Last 6 months | Il y a 6 mois | Aujourd'hui | | Last year | Il y a 1 an | Aujourd'hui | | Previous month | Premier jour du mois précédent | Dernier jour du mois précédent | | This month | 1er du mois en cours | Aujourd'hui | | This quarter | 1er du trimestre en cours | Aujourd'hui | | This year | 1er janvier de l'année en cours | Aujourd'hui | :::tip Utilisez **Last 28 days** pour suivre les produits en abonnement hebdomadaire — la plage couvre quatre cycles hebdomadaires complets, sans qu'une semaine partielle ne fausse la comparaison. ::: #### Échelle temporelle \{#time-scale\} Chaque point de données sur le graphique représente un bloc de temps — choisissez entre jour, semaine, mois, trimestre et année dans le menu déroulant. Le jour et la semaine montrent les variations à court terme ; le mois, le trimestre et l'année révèlent les tendances plus longues. Dans les analyses par [cohorte](analytics-cohorts) et [LTV](ltv), ce paramètre s'appelle **longueur de cohorte** — consultez les articles correspondants pour plus de détails. ### Comparer deux périodes \{#compare-two-time-periods\} Cliquez sur l'option de comparaison à côté du calendrier pour superposer la période actuelle à une période antérieure. La première comparaison d'Adapty porte sur la période qui précède immédiatement, de même durée. Pour modifier la plage de comparaison, cliquez à nouveau sur l'option et choisissez une plage personnalisée. La comparaison apparaît : - **Sur le graphique** — lignes, zones ou colonnes superposées, avec zéro ou un regroupement sélectionné. - **Sous forme de valeur numérique** — la différence entre les deux périodes, affichée en vert (valeur plus haute) ou en rouge (valeur plus basse). - **Dans une infobulle** — survolez un point de données pour voir la différence numérique pour ce point. ### Filtrer et regrouper les données \{#filter-and-group-data\} **Filtrez** pour restreindre le graphique aux données correspondant à un ou plusieurs attributs (par exemple, un seul pays ou produit). **Regroupez** pour décomposer le total du graphique en séries distinctes — une par valeur d'attribut. Par exemple, regroupez le revenu par pays pour obtenir une ligne de revenu distincte pour chaque pays plutôt qu'un total combiné. **Attributs de filtre et de regroupement disponibles :** | Attribut | Filtre | Groupe | Description | | --- | :---: | :---: | --- | | Attribution | ✅ | ✅ | Source, statut, canal, campagne, groupe d'annonces, ensemble d'annonces et créatif (mot-clé). Nécessite une [intégration d'attribution](attribution-integration). | | Audience | ✅ | ✅ | L'[audience](audience) à laquelle appartient l'utilisateur. | | Renewal status | ❌ | ✅ | Indique si l'abonnement sera renouvelé à la prochaine période. | | Period | ✅ | ✅ | Étape du cycle de vie de l'abonnement : **Trial**, **Activation** (premier paiement), ou **Renewal 1**–**Renewal 5**, **Renewals 6+** (renouvellements suivants). | | Country | ✅ | ✅ | Le pays du store de l'utilisateur. Si indisponible, Adapty le déduira du code de devise ou de l'IP de l'appareil. | | Offer Type | ✅ | ✅ | L'offre appliquée à la transaction : <ul><li>**Introductory** — une offre de lancement sur la période initiale d'abonnement. Utilisez **Offer Discount Type** pour distinguer les offres de lancement payantes des essais gratuits.</li><li>**Promotional** — offres promotionnelles App Store et équivalents.</li><li>**Offer Code** — codes promo que le client saisit dans le store.</li><li>**No offer** — aucune offre appliquée.</li></ul> | | Offer ID | ✅ | ✅ | Un identifiant d'offre spécifique. | | Offer Discount Type | ✅ | ✅ | Le modèle de tarification d'une offre de lancement ou promotionnelle : **Free Trial**, **Pay As You Go** ou **Pay Up Front**. Combinez avec **Offer Type** pour distinguer, par exemple, un essai gratuit d'introduction d'une offre de lancement payante. | | Paywall | ✅ | ✅ | Le [paywall](paywalls) utilisé pour l'achat. | | A/B tests | ✅ | ❌ | Le [test A/B](ab-tests) actif au moment de l'achat. | | Placement | ✅ | ✅ | Le [placement](placements) où l'achat a eu lieu. | | Store | ✅ | ✅ | Le store qui a traité la transaction : App Store, Google Play, Stripe, etc. | | Product | ✅ | ✅ | Le [produit](product) — abonnements et achats uniques. | | Duration | ✅ | ✅ | La durée du produit. | | Segment | ✅ | ✅ | Un [segment](segments) d'utilisateurs. Regroupez par segment pour comparer les performances d'un segment avec **All users**. <ul><li>Les entonnoirs ne prennent pas en charge le regroupement par segment.</li><li>Si vous modifiez un attribut personnalisé après qu'un segment l'utilise, Adapty peut exclure l'utilisateur du segment dans les analyses. Les données continuent d'afficher la valeur précédente.</li></ul> | | Refund Reason | ✅ | ✅ | La raison pour laquelle une transaction a été remboursée (par exemple, **Refund** ou **Upgraded**). Disponible sur les graphiques de remboursement et de résolution des problèmes de facturation. | | Expiration reason | ❌ | ✅ | La raison pour laquelle un abonnement ou un essai a expiré : **Cancelled by customer**, **Billing issue**, **Customer hasn't agreed to price increase**, **Unknown** ou **Refund**. Disponible sur les abonnements expirés (churned) et les essais expirés (churned). | | Cohort (LTV only) | ❌ | ✅ | Sur le graphique LTV, regroupez par longueur de cohorte : **Day**, **Week**, **Month** ou **Year**. Remplace le regroupement par attribution sur ce graphique. | Toutes les vues analytiques ne prennent pas en charge tous les attributs de filtre ou de regroupement ci-dessus. ARPU et Installs dans l'onglet Charts sont limités à Attribution, Country, Segment, Store et (filtre uniquement) A/B tests. Les onglets LTV, Cohorts, Funnels, Retention et Conversion prennent chacun en charge un sous-ensemble différent. Pour un support exact, consultez l'article correspondant à ce graphique ou cet onglet. ### Comment le pays est déterminé \{#how-country-is-determined\} Chaque transaction est associée à un pays au moment de sa création. La source de ce pays, par ordre de préférence, est : 1. Le **pays IP de l'appareil** de l'utilisateur au moment de la transaction. 2. Le **pays du store** de l'utilisateur — le pays de son compte App Store ou Google Play. 3. Le **pays IP** le plus récemment connu de l'utilisateur. Le pays du store n'est pas disponible pour les paiements web (Stripe, Paddle), les accès accordés manuellement, ou les transactions pour lesquelles le store ne l'a pas fourni. Dans ces cas, Adapty revient au pays basé sur l'IP. Comme le pays est capturé par transaction, un utilisateur qui change le pays de son App Store après l'installation aura des valeurs de pays différentes sur les transactions avant et après le changement. Les transactions passées conservent leur pays d'origine. **GB et United Kingdom.** Les données de pays sont stockées sous forme de codes ISO 3166-1 alpha-2 (donc « GB », pas « United Kingdom »). La couche d'affichage du tableau de bord associe les codes aux noms complets via une table de correspondance qui inclut un alias hérité `'UK' → 'United Kingdom'` — c'est pourquoi les deux peuvent apparaître comme options lors de la création d'un segment. ### Modifier la visualisation du graphique \{#change-the-chart-visualization\} Choisissez comment afficher le graphique depuis le menu déroulant de visualisation : - **Stacked column** — chaque colonne affiche le total, décomposé en segments colorés par groupe. - **Stacked area** — identique à la colonne empilée, mais avec des zones remplies reliant les points de données. - **Line** — une ligne par groupe, sans remplissage. - **100% stacked column** — chaque colonne atteint toute la hauteur du graphique ; les segments affichent la part relative (en pourcentage) de chaque groupe plutôt que les valeurs réelles. Utile pour visualiser les proportions dans le temps. - **100% stacked area** — identique à la colonne empilée à 100 %, mais avec des zones remplies plutôt que des colonnes. ### Afficher les données sous forme de tableau \{#view-data-as-a-table\} Sous chaque graphique se trouve un tableau des mêmes données, avec les dates en colonnes. La ligne et la colonne Total affichent des agrégats non visibles sur le graphique lui-même. ### Exporter les données en CSV \{#export-data-to-csv\} Cliquez sur le bouton **Export** pour télécharger les données sous-jacentes du graphique en fichier CSV. :::tip Pour un accès programmatique ou planifié, utilisez plutôt l'[Export API](export-analytics-api) — elle renvoie les mêmes données que le téléchargement CSV. ::: ### Afficher le revenu brut ou net \{#display-gross-or-net-revenue\} Pour les graphiques liés aux revenus ([Revenue](revenue), [MRR](mrr), [ARR](arr), [ARPU](arpu), [ARPPU](arppu)), Adapty propose un menu déroulant avec trois modes d'affichage : - **Gross revenue** — revenu total avant toute déduction. - **Proceeds after store commission** — revenu moins la commission du store, taxes comprises. - **Proceeds after store commission and taxes** — revenu moins la commission et les taxes. Pour plus de détails sur le calcul des commissions et des taxes, consultez [Commissions and taxes](how-adapty-analytics-works#commissions-and-taxes) dans *Comment fonctionne Adapty Analytics*. --- # File: charts --- --- title: "Graphiques Analytics" description: "Utilisez les graphiques et analyses d'Adapty pour suivre les performances de vos abonnements." --- L'onglet **[Charts](https://app.adapty.io/analytics/charts/)** affiche les revenus, abonnements, essais et problèmes de facturation de votre application au fil du temps. :::note **Les transactions sandbox sont exclues de tous les graphiques analytiques.** Elles apparaissent tout de même sur les pages de profil individuelles et dans le flux d'événements. ::: Pour les descriptions et comparaisons détaillées de chaque graphique, consultez le [tableau de comparaison des métriques](metric-comparison-table). Pour les filtres, regroupements et plages de dates, voir [Contrôles Analytics](controls-filters-grouping-compare-proceeds). Les paywalls et placements ont leurs propres pages de métriques : [Métriques des paywalls](paywall-metrics) et [Métriques des placements](placement-metrics). ### Graphiques abonnements et achats intégrés \{#subscription-and-in-app-charts\} - [Revenue](revenue) : Revenus totaux issus des abonnements et achats uniques, déduction faite des remboursements. - [MRR](mrr) : Revenu mensuel récurrent généré par les abonnements actifs. - [ARR](arr) : Revenu annuel récurrent généré par les abonnements actifs. - [ARPU](arpu) : Revenu moyen par utilisateur. - [ARPPU](arppu) : Revenu moyen par utilisateur payant. - [Installs](installs) : Nombre d'installations de l'application. - [Active subscriptions](active-subscriptions) : Abonnements payants non expirés. - [New subscriptions](reactivated-subscriptions) : Abonnements activés pour la première fois. - [Subscription renewal cancelled](cancelled-subscriptions) : Abonnements pour lesquels le renouvellement automatique a été désactivé. - [Expired (churned) subscriptions](churned-expired-subscriptions) : Abonnements arrivés à expiration. - [Non-subscriptions](non-subscriptions) : Nombre de consommables, non-consommables et abonnements non renouvelables. ### Graphiques essais \{#trial-charts\} - [Active trials](active-trials) : Essais non expirés. - [New trials](new-trials) : Essais activés. - [Trial renewal cancelled](trials-renewal-cancelled) : Essais pour lesquels le renouvellement automatique a été désactivé. - [Expired (churned) trials](expired-churned-trials) : Essais terminés sans conversion. ### Graphiques facturation et remboursements \{#billing-and-refund-charts\} - [Grace period](grace-period) : Abonnements entrés en délai de grâce après un échec de paiement. - [Grace period converted](grace-period-converted) : Abonnements en délai de grâce ayant été renouvelés avec succès. - [Grace period converted revenue](grace-period-converted-revenue) : Revenus issus des récupérations en délai de grâce. - [Billing issue](billing-issue) : Abonnements passés en état de problème de facturation. - [Billing issue converted](billing-issue-converted) : Abonnements en problème de facturation ayant été renouvelés avec succès. - [Billing issue converted revenue](billing-issue-converted-revenue) : Revenus issus des récupérations après problème de facturation. - [Refund events](refund-events) : Nombre d'achats ou d'abonnements remboursés. - [Refund money](refund-money) : Montant total remboursé. --- # File: revenue --- --- title: "Revenue" description: "Suivez et analysez les revenus de votre application grâce aux informations d'abonnement d'Adapty." --- Le graphique Revenue affiche le total des revenus générés par les abonnements et les achats uniques, déduction faite des remboursements. C'est la métrique principale pour surveiller la performance financière de votre application. Passez à une résolution mensuelle pour évaluer les tendances globales sur les 12 derniers mois. Groupez le graphique par produit, segment d'utilisateurs ou source d'attribution pour savoir d'où viennent les revenus, et observez la répartition nouveaux/renouvellements pour comprendre quel côté du business tire la croissance. ## Calcul \{#calculation\} :::warning La calculatrice ci-dessous **ne prend pas en compte** [les commissions des stores et la fiscalité](how-adapty-analytics-works#commissions-and-taxes). Comparez le résultat à vos calculs de **revenus bruts**. ::: Le revenue correspond au total de toutes les transactions payées sur la période (nouveaux abonnements, renouvellements, conversions d'essais, achats uniques), moins les remboursements traités sur la période : **Revenue = total des transactions − remboursements**. Le montant intégral de chaque transaction est comptabilisé le jour de l'achat, et non réparti sur la durée de l'abonnement. Le graphique affiche les revenus bruts par défaut. Utilisez les [contrôles du graphique](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) pour basculer entre la vue brute, post-commission ou post-commission-et-taxes. <CompoundCalculator client:load heading="Revenue" formuLatex="\sum P_i \times Q_i - D" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "Price per unit", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "Quantity", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "Amount refunded", variableValue: 35, global: true } ]} rowFormula="price * qty" resultFormula="_sum - refunds" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## Gestion des remboursements \{#refund-handling\} Le revenue soustrait chaque remboursement à la date à laquelle il a été traité — et non à la date d'achat d'origine. Le graphique peut afficher une valeur négative pour un groupe ou une journée spécifique lorsque les remboursements de ce segment dépassent les nouveaux revenus. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Devise \{#currency\} Adapty affiche tous les graphiques monétaires en **dollars américains**, quelle que soit la devise d'origine de la transaction. Cela inclut le chiffre d'affaires, le MRR, l'ARR, l'ARPU, l'ARPPU, la LTV, le chiffre d'affaires prédit, les remboursements, ainsi que les montants au sein des cohortes et des rapports de tests A/B. Il n'est pas possible d'afficher ces données dans une autre devise. Adapty convertit chaque transaction en USD en utilisant un taux de [currencylayer.com](https://currencylayer.com/) actualisé toutes les 8 heures, **fixé au moment de la transaction**. Les valeurs historiques en USD ne sont pas recalculées lorsque les taux de change évoluent. Les valeurs en devise locale sont disponibles par transaction dans : - Les champs `price_local` et `currency` dans les webhooks - Les colonnes `_local` (telles que `revenue_local` et `proceeds_local`) et `currency` dans les exports S3, GCS et BigQuery - La page de profil (vue par transaction) Pour les rapports financiers en devise locale, récupérez les valeurs en devise locale par transaction depuis un export et agrégez-les vous-même. ## Tarification des renouvellements \{#renewal-pricing\} Adapty calcule les revenus de renouvellement au prix actuel du produit, même pour les utilisateurs qui étaient sur un ancien tarif lors de leur première souscription. Après avoir modifié un prix dans App Store Connect ou Google Play, les chiffres Revenue, MRR et ARR du tableau de bord pour les abonnés existants peuvent diverger des revenus réellement encaissés — Adapty applique le nouveau prix, même si le store a maintenu ces utilisateurs à l'ancien tarif. Pour vérifier, comparez le champ `price` par transaction dans l'export S3, GCS ou BigQuery avec le tableau de bord pour les mêmes transactions. Le champ de l'export reflète ce que le store a communiqué (le prix effectivement payé par le client) ; le tableau de bord reflète le prix actuel du produit. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise de l'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Grouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise de l'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#revenue). - [MRR](mrr) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: mrr --- --- title: "MRR" description: "Comprenez et optimisez le revenu mensuel récurrent (MRR) dans Adapty." --- Le graphique du revenu mensuel récurrent (MRR) affiche les revenus générés par vos abonnements payants actifs, normalisés en équivalent mensuel. Il représente le revenu stable que votre activité d'abonnement génère, quelle que soit la durée des abonnements. Pour voir comment chaque cohorte d'abonnés contribue au revenu récurrent dans le temps, regroupez le graphique par mois du premier achat et passez à une résolution mensuelle. La vue en aires empilées révèle la contribution de chaque cohorte mois après mois. ## Calcul \{#calculation\} :::warning La calculatrice ci-dessous **ne prend pas en compte** [la commission du store et la fiscalité](how-adapty-analytics-works#commissions-and-taxes). Comparez le résultat avec vos calculs de **revenus bruts**. ::: Le MRR normalise le revenu de chaque abonnement en équivalent mensuel — un abonnement annuel à 240 $ contribue 20 $ par mois, et non 240 $ en une fois. Cela maintient le MRR stable, quelle que soit la répartition des périodes de facturation. Le MRR est la somme de (prix × abonnés actifs ÷ période de facturation en mois) pour tous vos types d'abonnement. Les abonnements hebdomadaires utilisent une période de facturation d'environ 0,23 mois. <SimpleCalculator client:load heading="MRR" formuLatex="\sum_{subscriptions}^{}\frac{P_s\times N_s}{D_m}" variables={[ { nameInTheFormula: "P_s", variableName: "subscriptionPrice", variableDescription: "Price", variableValue: 10 }, { nameInTheFormula: "N_s", variableName: "activeSubs", variableDescription: "Subscribers", variableValue: 1, isInteger: true }, { nameInTheFormula: "D_m", variableName: "duration", variableDescription: "Subscription period", variableValue: 1, options: [ { label: "Weekly", value: 0.23 }, { label: "Monthly", value: 1 }, { label: "2 months", value: 2 }, { label: "3 months", value: 3 }, { label: "6 months", value: 6 }, { label: "Annual", value: 12 } ] } ]} formulaCalculation="(subscriptionPrice * activeSubs) / duration" isSum={true} defaultRows={[ { subscriptionPrice: 240, activeSubs: 2, duration: 12}, { subscriptionPrice: 30, activeSubs: 10, duration: 1}, { subscriptionPrice: 10, activeSubs: 20, duration: 0.23}, ]} /> Le MRR ne prend pas en compte les produits qui ne génèrent pas de revenu récurrent : - les achats uniques - les consommables - les abonnements non renouvelables Votre base d'utilisateurs peut générer un revenu stable via des produits à achat unique. Mais ce revenu n'est pas comptabilisé dans le MRR, car les achats eux-mêmes ne sont pas récurrents. ## Gestion des remboursements \{#refund-handling\} Lorsqu'un abonnement est remboursé, le MRR supprime sa contribution de chaque date du graphique où il avait été comptabilisé. Les valeurs passées du MRR peuvent diminuer après l'enregistrement d'un remboursement. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Devise \{#currency\} Adapty affiche tous les graphiques monétaires en **dollars américains**, quelle que soit la devise d'origine de la transaction. Cela inclut le chiffre d'affaires, le MRR, l'ARR, l'ARPU, l'ARPPU, la LTV, le chiffre d'affaires prédit, les remboursements, ainsi que les montants au sein des cohortes et des rapports de tests A/B. Il n'est pas possible d'afficher ces données dans une autre devise. Adapty convertit chaque transaction en USD en utilisant un taux de [currencylayer.com](https://currencylayer.com/) actualisé toutes les 8 heures, **fixé au moment de la transaction**. Les valeurs historiques en USD ne sont pas recalculées lorsque les taux de change évoluent. Les valeurs en devise locale sont disponibles par transaction dans : - Les champs `price_local` et `currency` dans les webhooks - Les colonnes `_local` (telles que `revenue_local` et `proceeds_local`) et `currency` dans les exports S3, GCS et BigQuery - La page de profil (vue par transaction) Pour les rapports financiers en devise locale, récupérez les valeurs en devise locale par transaction depuis un export et agrégez-les vous-même. ## Tarification au renouvellement \{#renewal-pricing\} Adapty calcule les revenus de renouvellement au prix actuel du produit, même pour les utilisateurs qui étaient sur un ancien tarif lors de leur première souscription. Après avoir modifié un prix dans App Store Connect ou Google Play, les chiffres Revenue, MRR et ARR du tableau de bord pour les abonnés existants peuvent diverger des revenus réellement encaissés — Adapty applique le nouveau prix, même si le store a maintenu ces utilisateurs à l'ancien tarif. Pour vérifier, comparez le champ `price` par transaction dans l'export S3, GCS ou BigQuery avec le tableau de bord pour les mêmes transactions. Le champ de l'export reflète ce que le store a communiqué (le prix effectivement payé par le client) ; le tableau de bord reflète le prix actuel du produit. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise d'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#revenue). - [Revenue](revenue) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: arr --- --- title: "ARR" description: "Suivez le chiffre d'affaires annuel récurrent (ARR) et optimisez votre stratégie d'abonnement." --- Le graphique du chiffre d'affaires annuel récurrent affiche les revenus de tous les abonnements auto-renouvelables actifs, normalisés sur un an. Le graphique considère comme actif tout abonnement payé et non expiré. L'ARR est une métrique clé pour suivre la croissance de votre activité par abonnement et prévoir les revenus futurs. ## Calcul \{#calculation\} :::warning La calculatrice ci-dessous **ne prend pas en compte** [la commission du store et la taxation](how-adapty-analytics-works#commissions-and-taxes). Comparez le résultat à vos calculs de **chiffre d'affaires brut**. ::: L'ARR est la version annualisée de votre chiffre d'affaires récurrent par abonnement. Il est particulièrement utile lorsque les abonnements annuels constituent votre produit principal — pour les activités majoritairement basées sur des abonnements mensuels ou hebdomadaires, le [MRR](mrr) est plus pertinent. L'ARR correspond à la somme de (prix × abonnés actifs ÷ période de facturation en années) pour tous vos types d'abonnement. Utilisez 1/12 pour le mensuel, 1/52 pour l'hebdomadaire. <SimpleCalculator client:load heading="ARR" formuLatex="\sum \frac{P_s \times U_s}{D_y}" variables={[ { nameInTheFormula: "P_s", variableName: "price", variableDescription: "Prix de l'abonnement", variableValue: 240 }, { nameInTheFormula: "U_s", variableName: "subs", variableDescription: "Abonnés payants actifs", variableValue: 2, isInteger: true }, { nameInTheFormula: "D_y", variableName: "periods", variableDescription: "Période d'abonnement", variableValue: 1, options: [ { label: "Hebdomadaire", value: "1/52" }, { label: "Mensuel", value: "1/12" }, { label: "2 mois", value: "2/12" }, { label: "3 mois", value: "3/12" }, { label: "6 mois", value: "6/12" }, { label: "Annuel", value: 1 } ] } ]} formulaCalculation="(price * subs ) / periods" isSum={true} defaultRows={[ { price: 240, subs: 2, periods: "1" }, { price: 30, subs: 10, periods: "1/12" }, { price: 10, subs: 20, periods: "1/52" } ]} /> ## Gestion des remboursements \{#refund-handling\} Lorsqu'un abonnement est remboursé, l'ARR supprime sa contribution de chaque date du graphique où il avait été comptabilisé. Les valeurs passées de l'ARR peuvent donc diminuer après un remboursement. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Devise \{#currency\} Adapty affiche tous les graphiques monétaires en **dollars américains**, quelle que soit la devise d'origine de la transaction. Cela inclut le chiffre d'affaires, le MRR, l'ARR, l'ARPU, l'ARPPU, la LTV, le chiffre d'affaires prédit, les remboursements, ainsi que les montants au sein des cohortes et des rapports de tests A/B. Il n'est pas possible d'afficher ces données dans une autre devise. Adapty convertit chaque transaction en USD en utilisant un taux de [currencylayer.com](https://currencylayer.com/) actualisé toutes les 8 heures, **fixé au moment de la transaction**. Les valeurs historiques en USD ne sont pas recalculées lorsque les taux de change évoluent. Les valeurs en devise locale sont disponibles par transaction dans : - Les champs `price_local` et `currency` dans les webhooks - Les colonnes `_local` (telles que `revenue_local` et `proceeds_local`) et `currency` dans les exports S3, GCS et BigQuery - La page de profil (vue par transaction) Pour les rapports financiers en devise locale, récupérez les valeurs en devise locale par transaction depuis un export et agrégez-les vous-même. ## Tarification au renouvellement \{#renewal-pricing\} Adapty calcule les revenus de renouvellement au prix actuel du produit, même pour les utilisateurs qui étaient sur un ancien tarif lors de leur première souscription. Après avoir modifié un prix dans App Store Connect ou Google Play, les chiffres Revenue, MRR et ARR du tableau de bord pour les abonnés existants peuvent diverger des revenus réellement encaissés — Adapty applique le nouveau prix, même si le store a maintenu ces utilisateurs à l'ancien tarif. Pour vérifier, comparez le champ `price` par transaction dans l'export S3, GCS ou BigQuery avec le tableau de bord pour les mêmes transactions. Le champ de l'export reflète ce que le store a communiqué (le prix effectivement payé par le client) ; le tableau de bord reflète le prix actuel du produit. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise d'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#revenue). - [Revenue](revenue) - [MRR](mrr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: arpu --- --- title: "ARPU" description: "Analysez le revenu moyen par utilisateur (ARPU) pour optimiser la génération de revenus." --- Le graphique ARPU (revenu moyen par utilisateur) affiche le revenu moyen généré par utilisateur sur une période donnée. Cette métrique est calculée en divisant le revenu total généré par une cohorte de clients par le nombre d'utilisateurs dans cette cohorte. Utilisez l'ARPU pour comparer les performances de revenus entre les segments d'utilisateurs — par source d'attribution, pays ou produit. ## Calcul \{#calculation\} :::warning La calculatrice ci-dessous **ne prend pas en compte** [la commission du store et la fiscalité](how-adapty-analytics-works#commissions-and-taxes). Comparez le résultat à vos calculs de **revenu brut**. ::: L'ARPU indique le revenu moyen que votre application génère par utilisateur — un indicateur courant de l'efficacité de la monétisation. L'ARPU correspond au revenu de la période (moins les remboursements) divisé par le nombre total d'utilisateurs de l'application sur cette période. <CompoundCalculator client:load heading="ARPU" formuLatex="\frac{\sum P_i \times Q_i - D}{U_p}" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "Prix du produit", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "Produits achetés", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "Montant remboursé", variableValue: 35, global: true }, { nameInTheFormula: "Up", variableName: "users", variableDescription: "Utilisateurs totaux", variableValue: 160, global: true, isInteger: true } ]} rowFormula="price * qty" resultFormula="(_sum - refunds) / users" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## Gestion des remboursements \{#refund-handling\} Les remboursements sont soustraits du numérateur de revenu à la date à laquelle le remboursement a été traité. Pour une comparaison complète entre les métriques, voir [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Devise \{#currency\} Adapty affiche tous les graphiques monétaires en **dollars américains**, quelle que soit la devise d'origine de la transaction. Cela inclut le chiffre d'affaires, le MRR, l'ARR, l'ARPU, l'ARPPU, la LTV, le chiffre d'affaires prédit, les remboursements, ainsi que les montants au sein des cohortes et des rapports de tests A/B. Il n'est pas possible d'afficher ces données dans une autre devise. Adapty convertit chaque transaction en USD en utilisant un taux de [currencylayer.com](https://currencylayer.com/) actualisé toutes les 8 heures, **fixé au moment de la transaction**. Les valeurs historiques en USD ne sont pas recalculées lorsque les taux de change évoluent. Les valeurs en devise locale sont disponibles par transaction dans : - Les champs `price_local` et `currency` dans les webhooks - Les colonnes `_local` (telles que `revenue_local` et `proceeds_local`) et `currency` dans les exports S3, GCS et BigQuery - La page de profil (vue par transaction) Pour les rapports financiers en devise locale, récupérez les valeurs en devise locale par transaction depuis un export et agrégez-les vous-même. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Pays, Tests A/B, Segment et Store. - ✅ Regrouper par : Pays, Store, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, voir le [Tableau de comparaison des métriques](metric-comparison-table#revenue). - [Revenu](revenue) - [MRR](mrr) - [ARPPU](arppu) - [ARR](arr) --- # File: arppu --- --- title: "ARPPU" description: "Comprendre l'ARPPU (Revenu Moyen Par Utilisateur Payant) et son impact sur la monétisation de votre application." --- Le graphique ARPPU (Average Revenue Per Paying User, soit le revenu moyen par utilisateur payant) affiche le revenu moyen généré par les utilisateurs ayant effectué un achat. Il représente le revenu réel produit par les clients payants, divisé par leur nombre, déduction faite des remboursements. Regroupez l'ARPPU par attribution pour identifier les canaux d'acquisition qui attirent les utilisateurs payants à plus forte valeur. ## Calcul \{#calculation\} :::warning La calculatrice ci-dessous **ne tient pas compte** de la [commission et de la fiscalité des stores](how-adapty-analytics-works#commissions-and-taxes). Comparez le résultat à vos calculs de **revenus bruts**. ::: L'ARPPU indique le revenu moyen par utilisateur payant — généralement bien supérieur à l'[ARPU](arpu), car les utilisateurs non payants sont exclus du dénominateur. L'ARPPU correspond au revenu de la période (déduction faite des remboursements) divisé par le nombre d'utilisateurs payants sur cette période. <CompoundCalculator client:load heading="ARPPU" formuLatex="\frac{\sum P_i \times Q_i - D}{U_p}" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "Product price", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "Products purchased", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "Amount refunded", variableValue: 35, global: true }, { nameInTheFormula: "Up", variableName: "users", variableDescription: "Paying users", variableValue: 16, global: true, isInteger: true } ]} rowFormula="price * qty" resultFormula="(_sum - refunds) / users" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## Gestion des remboursements \{#refund-handling\} Les remboursements sont soustraits du numérateur de revenus à la date à laquelle ils ont été traités. Un utilisateur dont l'achat a été remboursé ultérieurement est toujours comptabilisé dans le dénominateur des utilisateurs payants, ce qui fait baisser l'ARPPU plus rapidement que prévu en cas de remboursements importants. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Devise \{#currency\} Adapty affiche tous les graphiques monétaires en **dollars américains**, quelle que soit la devise d'origine de la transaction. Cela inclut le chiffre d'affaires, le MRR, l'ARR, l'ARPU, l'ARPPU, la LTV, le chiffre d'affaires prédit, les remboursements, ainsi que les montants au sein des cohortes et des rapports de tests A/B. Il n'est pas possible d'afficher ces données dans une autre devise. Adapty convertit chaque transaction en USD en utilisant un taux de [currencylayer.com](https://currencylayer.com/) actualisé toutes les 8 heures, **fixé au moment de la transaction**. Les valeurs historiques en USD ne sont pas recalculées lorsque les taux de change évoluent. Les valeurs en devise locale sont disponibles par transaction dans : - Les champs `price_local` et `currency` dans les webhooks - Les colonnes `_local` (telles que `revenue_local` et `proceeds_local`) et `currency` dans les exports S3, GCS et BigQuery - La page de profil (vue par transaction) Pour les rapports financiers en devise locale, récupérez les valeurs en devise locale par transaction depuis un export et agrégez-les vous-même. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#revenue). - [Revenue](revenue) - [MRR](mrr) - [ARPU](arpu) - [ARR](arr) --- # File: installs --- --- title: "Installs" description: "Suivez les installations de votre application et comprenez leur impact sur les abonnements avec Adapty." --- Le graphique Installs indique combien d'utilisateurs ont installé votre application sur la période sélectionnée. Ce qui compte comme une installation — et comment chaque installation est regroupée — dépend du paramètre de comptage des installations. Cet article explique comment choisir le bon mode de comptage, et comment [réconcilier les éventuelles divergences](#troubleshooting) entre les différentes sources d'analytics. ## Ce qui compte comme une installation \{#what-counts-as-an-install\} Le SDK Adapty enregistre une « installation » et l'envoie à Adapty lors du premier lancement de votre application par l'utilisateur. Cela a deux conséquences : - Une installation apparaît dans Adapty quand l'utilisateur ouvre l'application pour la première fois, ce qui peut survenir des heures ou des jours après le téléchargement. - Si un utilisateur télécharge l'application sans jamais l'ouvrir, Adapty ne le comptabilise pas. Votre **fuseau horaire de reporting** dans les paramètres de l'application détermine à quelle journée est attribuée chaque installation. Une installation à 23h30 UTC le 1er juin est comptée le 2 juin si votre fuseau horaire de reporting est +02:00, alors qu'App Store Connect ou Google Play peuvent l'afficher le 1er juin. ### Modes de comptage \{#counting-modes\} Le paramètre **Installs definition for analytics** détermine ce qui compte comme une nouvelle installation. Pour le modifier, ouvrez [App Settings → General → Installs definition for analytics](general#4-installs-definition-for-analytics). | Mode | Ce qui est comptabilisé | Exemple | Métrique tierce | Divergences potentielles | | --- | --- | --- | --- | --- | | **New device_ids** (recommandé) | **Chaque installation** — y compris les réinstallations. L'authentification, la création de profil et les mises à jour de version ne s'ajoutent pas au compteur. | Un utilisateur sur 5 appareils = 5 installations. <br /> <br /> Réinstallation sur le même appareil = 2 installations. | App Store : <br /> **Total Active Devices** <br /> <br /> Google Play : **Devices** | **Supérieur au nombre de téléchargements** si les réinstallations sont fréquentes. <br /> <br /> **Inférieur au nombre de téléchargements** si beaucoup d'utilisateurs téléchargent l'application sans l'ouvrir. | | **New customer_user_ids** | Uniquement **la première installation** par [utilisateur identifié](identifying-users). Les appareils supplémentaires et les utilisateurs anonymes ne sont pas comptabilisés. | Un utilisateur sur 5 appareils = 1 installation. <br /> <br /> Réinstallation, reconnexion = pas de nouvelle installation. <br /> <br /> Utilisation de l'application sans compte = pas de nouvelle installation. | Statistiques d'inscription de votre système d'authentification | **Reste vide** si vous n'identifiez pas du tout les utilisateurs. | | **New profiles in Adapty** (hérité) | Compte chaque installation et réinstallation, **ainsi que les profils anonymes créés lors d'une déconnexion**. | Un utilisateur, un appareil, 3 déconnexions = 4 installations. | Aucune | **Supérieur à toutes les métriques externes**. Compte chaque profil anonyme créé lors d'une déconnexion comme une installation. | Utilisez **New device_ids** sauf si vous avez une raison particulière de changer. ## Résolution des problèmes \{#troubleshooting\} ### Le compteur Adapty est supérieur à App Store Connect ou Google Play \{#adaptys-count-is-higher-than-app-store-connect-or-google-play\} Deux causes probables : - **Réinstallations.** Si votre [mode de comptage](#counting-modes) est défini sur **New device_ids**, Adapty comptabilise à la fois les premiers lancements et les réinstallations ultérieures. « Total Downloads » dans App Store Connect ne comptabilise que le téléchargement initial. - **Date du premier lancement ≠ date de téléchargement.** Les stores attribuent par date de téléchargement. Les utilisateurs qui ouvrent l'application tardivement sont rattachés à des jours différents. Pour comparer plus précisément, consultez **App Store Connect → Total Active Devices** ou **Google Play → Devices**. Ces métriques sont au niveau de l'appareil et se rapprochent davantage du mode **New device_ids** d'Adapty. ### Le compteur Adapty est à zéro \{#adaptys-count-is-zero\} Si votre mode de comptage est **New customer_user_ids**, mais que vous n'<InlineTooltip tooltip="authentifiez pas les utilisateurs">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Unity](unity-identifying-users), [Kotlin Multiplatform](kmp-quickstart-identify), [Capacitor](capacitor-quickstart-identify)</InlineTooltip>, Adapty n'enregistrera aucune installation. Dans ce mode, les installations anonymes sont exclues. Passez à **New device_ids** ou implémentez l'identification des utilisateurs. ### Le compteur Adapty diffère d'AppsFlyer ou d'Adjust \{#adaptys-count-differs-from-appsflyer-or-adjust\} Les MMP attribuent les installations selon leur propre initialisation de SDK ou premier événement de contact. Ceux-ci se déclenchent selon un calendrier différent de celui du premier lancement du SDK Adapty — un certain écart est normal. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Pays, Tests A/B, Segment et Store. - ✅ Regrouper par : Pays, Store, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#subscribers-and-conversion). - [Nouveaux abonnements](reactivated-subscriptions) - [Abonnements actifs](active-subscriptions) - [Nouveaux essais](new-trials) --- # File: active-subscriptions --- --- title: "Abonnements actifs" description: "Surveillez et gérez les abonnements actifs grâce aux analyses robustes d'Adapty." --- Le graphique Abonnements actifs affiche le nombre d'abonnements payants uniques qui n'ont pas encore expiré à la fin de chaque période sélectionnée. Il inclut les abonnements intégrés réguliers (non expirés) qui ont démarré et sont actuellement actifs, et exclut les essais gratuits ainsi que les abonnements dont le renouvellement a été annulé. C'est un indicateur de la taille et de la croissance de votre base d'abonnés. ## Calcul \{#calculation\} La métrique des abonnements actifs comptabilise les abonnements payants non expirés à la fin de chaque période. Pour les abonnements sans délai de grâce, l'expiration survient lorsque la date de renouvellement suivante est dépassée sans renouvellement réussi. Par exemple : 500 abonnements actifs à la fin du mois dernier, plus 50 nouveaux ce mois-ci, moins 25 expirés ce mois-ci = 525 abonnements actifs à la fin de ce mois. ## Gestion des remboursements \{#refund-handling\} Lorsqu'un abonnement est remboursé, Adapty le retire du décompte actif — aussi bien pour la période en cours que rétroactivement pour les dates passées. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles des analyses](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise d'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#subscribers-and-conversion). - [Abonnements résiliés (expirés)](churned-expired-subscriptions) - [Abonnements annulés](cancelled-subscriptions) - [Achats hors abonnement](non-subscriptions) --- # File: reactivated-subscriptions --- --- title: "Nouveaux abonnements" description: "Suivez les nouveaux abonnements dans Adapty pour surveiller les premières conversions et les conversions d'essais gratuits en abonnements payants." --- Le graphique Nouveaux abonnements affiche le nombre de nouveaux abonnements (activés pour la première fois) dans votre application. Cette métrique indique le nombre de nouveaux abonnements démarrés sur une période donnée, incluant à la fois les abonnements qui partent de zéro et les essais gratuits qui se convertissent en abonnements payants. Elle n'inclut pas les renouvellements d'abonnements ni les abonnements réactivés. ## Calcul \{#calculation\} La métrique Nouveaux abonnements comptabilise les activations d'abonnements pour la première fois au cours de la période — aussi bien les abonnements qui partent de zéro que les essais gratuits qui se convertissent en abonnements payants. ## Gestion des remboursements \{#refund-handling\} Les nouveaux abonnements ne **déduisent pas** les remboursements — le comptage inclut les abonnements qui ont été remboursés ultérieurement. Pour évaluer l'impact net, comparez avec les [Événements de remboursement](refund-events). Pour une comparaison complète des métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise de l'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise de l'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#subscribers-and-conversion). - [Abonnements actifs](active-subscriptions) - [Abonnements résiliés (expirés)](churned-expired-subscriptions) - [Abonnements annulés](cancelled-subscriptions) - [Achats uniques](non-subscriptions) --- # File: non-subscriptions --- --- title: "Achats non-abonnement" description: "Découvrez comment gérer les produits hors abonnement dans Adapty et suivre efficacement les achats des utilisateurs." --- Le graphique Achats non-abonnement comptabilise les achats intégrés qui ne sont pas des abonnements auto-renouvelables : consommables, non-consommables et abonnements non renouvelables. Les renouvellements sont exclus. :::note « Achats non-abonnement » est plus large qu'« achats uniques » — les consommables et les abonnements non renouvelables peuvent chacun être achetés plusieurs fois. ::: ## Calcul \{#calculation\} Chaque achat intégré non-abonnement appartient à l'un des trois types suivants : - **Consommables** : articles que les utilisateurs peuvent acheter plusieurs fois, comme de la nourriture pour poissons dans une application de pêche ou de la monnaie virtuelle supplémentaire. - **Non-consommables** : articles achetés une seule fois et utilisés indéfiniment, comme un circuit de course dans un jeu ou une version sans publicité. - **Abonnements non renouvelables** : abonnements qui expirent après une période définie et ne se renouvellent pas automatiquement, comme un accès d'un an à un catalogue de contenus. Le contenu peut être statique, mais l'abonnement ne se renouvelle pas à son expiration. :::note Ce graphique comptabilise uniquement les événements d'achat et ne soustrait pas les achats remboursés. Si vous avez des produits hors abonnement fréquemment remboursés, le nombre affiché sera supérieur au nombre réel d'achats ayant généré des revenus. ::: ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Segment, Store et Produit. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#revenue). - [Abonnements actifs](active-subscriptions) - [Nouveaux abonnements](reactivated-subscriptions) - [Abonnements résiliés (expirés)](churned-expired-subscriptions) - [Abonnements annulés](cancelled-subscriptions) --- # File: cancelled-subscriptions --- --- title: "Renouvellements d'abonnements annulés" description: "Gérez efficacement les abonnements annulés grâce aux outils de gestion d'Adapty." --- Le graphique Subscriptions renewal canceled affiche le nombre d'abonnements dont le renouvellement automatique a été désactivé (annulé par l'utilisateur). Lorsque le renouvellement automatique d'un abonnement est désactivé, cela signifie que l'abonnement ne se renouvellera pas automatiquement pour la période suivante. L'utilisateur conserve toutefois l'accès aux fonctionnalités premium de l'application jusqu'à la fin de la période en cours. :::tip **Fidélisez vos abonnés avant qu'ils ne se désabonnent.** [Retention Messaging](retention-messaging) affiche un message personnalisé dans l'écran Annuler l'abonnement d'Apple — une raison de rester, juste au moment où l'abonné appuie sur Annuler. ::: ## Calcul \{#calculation\} La métrique des renouvellements d'abonnements annulés comptabilise les abonnements dont le renouvellement automatique a été désactivé pendant la période. L'utilisateur conserve l'accès premium jusqu'à la fin de la période de facturation en cours, mais l'abonnement ne se renouvellera pas automatiquement après cela. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#churn). - [Abonnements actifs](active-subscriptions) - [Abonnements résiliés (expirés)](churned-expired-subscriptions) - [Nouveaux abonnements](reactivated-subscriptions) - [Achats uniques](non-subscriptions) --- # File: churned-expired-subscriptions --- --- title: "Abonnements résiliés (expirés)" description: "Gérez les abonnements résiliés et expirés pour améliorer la rétention des utilisateurs." --- Le graphique des abonnements résiliés (expirés) affiche le nombre d'abonnements arrivés à expiration, c'est-à-dire que l'utilisateur n'a plus accès aux fonctionnalités premium de l'application. Cela se produit généralement lorsque l'utilisateur décide de ne pas renouveler son abonnement à la fin de la période ou rencontre un problème de facturation. Regroupez par motif d'expiration pour distinguer la résiliation volontaire de celle liée à un problème de paiement. :::tip **Fidélisez vos abonnés avant qu'ils ne se désabonnent.** [Retention Messaging](retention-messaging) affiche un message personnalisé dans l'écran Annuler l'abonnement d'Apple — une raison de rester, juste au moment où l'abonné appuie sur Annuler. ::: ## Calcul \{#calculation\} La métrique des abonnements résiliés (expirés) comptabilise les abonnements qui ont expiré au cours de la période — l'utilisateur a perdu l'accès aux fonctionnalités premium. Cela inclut à la fois les utilisateurs qui ont choisi de ne pas renouveler et ceux qui ont perdu leur abonnement en raison d'un problème de facturation. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Motif d'expiration, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#churn). - [Abonnements actifs](active-subscriptions) - [Nouveaux abonnements](reactivated-subscriptions) - [Abonnements annulés](cancelled-subscriptions) - [Achats non liés à un abonnement](non-subscriptions) --- # File: active-trials --- --- title: "Essais actifs" description: "Suivez et gérez les essais d'abonnement actifs avec les analyses Adapty." --- Le graphique des essais actifs dans Adapty affiche le nombre d'essais gratuits non expirés qui sont actuellement actifs à la fin d'une période donnée. « Actif » signifie que les abonnements n'ont pas encore expiré ; les utilisateurs ont donc toujours accès aux fonctionnalités payantes de l'application. ## Calcul \{#calculation\} La métrique des essais actifs comptabilise les essais gratuits non expirés à la fin de chaque période. L'annulation du renouvellement automatique ne retire pas un essai du comptage — seule l'expiration le fait. Par exemple : 100 essais actifs hier, plus 10 nouveaux aujourd'hui, moins 5 expirés aujourd'hui = 105 essais actifs aujourd'hui. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles des analyses](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Période, Statut de renouvellement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise d'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#subscribers-and-conversion). - [Nouveaux essais](new-trials) - [Renouvellement d'essai annulé](trials-renewal-cancelled) - [Essais expirés](expired-churned-trials) --- # File: new-trials --- --- title: "Nouveaux essais" description: "Gérez les nouveaux essais d'abonnement et optimisez les taux de conversion essai-vers-payant." --- Le graphique des nouveaux essais affiche le nombre d'essais activés durant la période sélectionnée. Utilisez-le pour suivre le volume d'essais issus des campagnes publicitaires et autres actions d'acquisition. ## Calcul \{#calculation\} La métrique des nouveaux essais comptabilise les essais démarrés durant la période, qu'ils soient encore actifs ou non à la fin de celle-ci. Par exemple, si 50 utilisateurs démarrent un essai en mai, le point de données de mai affiche 50 — même si certains ont déjà expiré ou converti vers un abonnement payant au moment où vous consultez le graphique. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise d'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#subscribers-and-conversion). - [Essais actifs](active-trials) - [Renouvellement d'essai annulé](trials-renewal-cancelled) - [Essais expirés](expired-churned-trials) --- # File: trials-renewal-cancelled --- --- title: "Renouvellements d'essais annulés" description: "Comprenez les renouvellements d'essais, les annulations et les flows d'abonnement grâce aux insights d'Adapty." --- Le graphique Renouvellements d'essais annulés affiche le nombre d'essais dont le renouvellement a été annulé (annulé par l'utilisateur). Lorsque le renouvellement d'un essai est désactivé, cela signifie que cet essai ne sera pas automatiquement converti en abonnement payant, mais l'utilisateur conserve quand même les fonctionnalités premium de l'application jusqu'à la fin de la période en cours. ## Calcul \{#calculation\} La métrique Renouvellements d'essais annulés comptabilise les essais dont le renouvellement automatique a été désactivé par l'utilisateur durant la période. L'utilisateur conserve l'accès à l'essai jusqu'à son expiration, mais l'essai ne se convertira pas automatiquement en abonnement payant. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#churn). - [Nouveaux essais](new-trials) - [Essais actifs](active-trials) - [Essais expirés](expired-churned-trials) --- # File: expired-churned-trials --- --- title: "Essais expirés (résiliés)" description: "Gérez efficacement les essais expirés et résiliés grâce à l'analytique Adapty." --- Le graphique des essais expirés (résiliés) affiche le nombre d'essais qui ont expiré, privant les utilisateurs de l'accès aux fonctionnalités premium de l'application. Dans la plupart des cas, cela se produit lorsque les utilisateurs décident de ne pas payer pour l'application ou rencontrent des problèmes de facturation. ## Calcul \{#calculation\} La métrique des essais expirés comptabilise les essais qui ont pris fin durant la période — l'utilisateur a perdu l'accès aux fonctionnalités premium. Cela inclut aussi bien les utilisateurs qui ont choisi de ne pas convertir que ceux dont la conversion a échoué en raison d'un problème de facturation. Regroupez par **Expiration reason** pour distinguer la résiliation volontaire de la résiliation due à la facturation. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Raison d'expiration, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#churn). - [Nouveaux essais](new-trials) - [Essais actifs](active-trials) - [Renouvellement des essais annulé](trials-renewal-cancelled) --- # File: refund-events --- --- title: "Événements de remboursement" description: "Gérez les événements de remboursement dans Adapty pour réduire le churn et optimiser vos revenus." --- Le graphique des événements de remboursement indique combien d'achats et d'abonnements ont été remboursés. Adapty associe chaque événement de remboursement à la date à laquelle le remboursement a été émis, et non à la date de début de l'abonnement. ## Calcul \{#calculation\} Adapty comptabilise chaque achat ou abonnement remboursé au cours de la période sélectionnée. Chaque remboursement est attribué à la date à laquelle il a eu lieu, et non à la date de début de l'abonnement. Les remboursements liés aux périodes d'essai sont exclus, car celles-ci ne génèrent aucun revenu. ## Traitement des remboursements par métrique \{#how-metrics-handle-refunds\} Les différentes métriques traitent les remboursements de manière distincte. Un même événement de remboursement peut faire baisser un graphique immédiatement, en modifier un autre de façon rétroactive (en changeant les valeurs des périodes passées), ou n'en affecter un troisième d'aucune façon. Le tableau ci-dessous présente les règles par métrique. | Métrique | Remboursements pris en compte ? | Date d'attribution | Peut être négatif ? | Remarques | | --- | --- | --- | --- | --- | | [Revenus](revenue) | Oui | Date du remboursement — et non la date d'achat initiale | Oui — les jours où les remboursements dépassent les nouveaux revenus | Revenus = total des transactions − remboursements. | | [MRR](mrr) | Oui, de façon rétroactive | L'abonnement est retiré de toutes les périodes où il était actif | Non | Les valeurs des périodes passées peuvent diminuer après un remboursement. | | [ARR](arr) | Oui, de façon rétroactive | Identique au MRR | Non | Les valeurs des périodes passées peuvent diminuer après un remboursement. | | [ARPU](arpu) | Oui | Date du remboursement | Oui (dans les périodes avec beaucoup de remboursements) | Les remboursements sont soustraits du numérateur des revenus. | | [ARPPU](arppu) | Oui, numérateur uniquement | Date du remboursement | Oui (dans les périodes avec beaucoup de remboursements) | Les remboursements sont soustraits du numérateur des revenus. Un utilisateur remboursé est toujours comptabilisé dans le dénominateur des utilisateurs payants, ce qui peut faire baisser l'ARPPU plus vite que prévu en cas de nombreux remboursements. | | [Abonnements actifs](active-subscriptions) | Oui, de façon rétroactive | L'abonnement est retiré du comptage | Non | | | [Nouveaux abonnements](reactivated-subscriptions) | **Non** | — | Non | Le comptage inclut les abonnements ultérieurement remboursés. Comparez avec [Événements de remboursement](refund-events) pour mesurer l'impact net. | | [Montant remboursé](refund-money) / [Événements de remboursement](refund-events) | Les remboursements **sont** la donnée | Date du remboursement | Non (toujours ≥ 0) | | | [Rétention](analytics-retention) | **Non** | — | Non | Les utilisateurs remboursés restent comptabilisés dans la courbe de rétention. Cela peut donner l'impression que la rétention est plus élevée que les [Abonnements actifs](active-subscriptions) ou les [Revenus](revenue) pour la même cohorte. | | [Revenus par cohorte](analytics-cohorts) | Oui, de façon cumulative | Date du remboursement | Non (les soustractions cumulatives ne font pas passer les revenus de cohorte en négatif) | Les remboursements sont déduits des revenus de la cohorte au fur et à mesure. Pour les autres métriques de cohorte, voir [Cohortes > Gestion des remboursements](analytics-cohorts#refund-handling). | | [Métriques de paywall](paywall-metrics) / [Métriques de test A/B](results-and-metrics) (comptages) | **Non** | — | Non | Les comptages d'abonnés, d'abonnés payants et d'ARPPU sur ces pages ne déduisent pas les remboursements. | | Exports GCS / S3 | Remboursement sous forme de ligne d'événement distincte | `event_datetime` = horodatage du remboursement | Les colonnes nettes peuvent être négatives lors de l'agrégation | La ligne de remboursement porte `is_refund = true` (S3/GCS) ou le type d'événement `subscription_refunded` (webhooks). | ### Valeurs négatives \{#negative-values\} Dans les vues agrégées (graphique des revenus, analyses personnalisées sur les exports), une métrique peut afficher une valeur négative pour une période ou un regroupement donné lorsque les remboursements de ce segment dépassent les nouveaux revenus de la même période. Ce n'est pas un bug — c'est l'arithmétique qui fonctionne normalement. Par exemple : un pays n'a enregistré aucun nouvel achat un mardi, mais un remboursement de 100 $ correspondant à un achat antérieur a été traité ce jour-là. Les revenus du pays pour ce mardi afficheront donc −100 $. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Motif du remboursement, Pays, Type d'offre, ID d'offre, Type de remise de l'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Motif du remboursement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de remise de l'offre, ID d'offre, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#revenue). - [Montant remboursé](refund-money) - [Problème de facturation](billing-issue) - [Délai de grâce](grace-period) --- # File: refund-money --- --- title: "Remboursements" description: "Découvrez comment traiter les remboursements pour les abonnements dans Adapty sans perte de revenus." --- Le graphique Remboursements affiche le montant remboursé au cours de la période sélectionnée. Adapty associe chaque événement de remboursement à sa date d'émission, ce qui entraîne une baisse des revenus sur cette même période. ## Calcul \{#calculation\} Adapty ne comptabilise que les transactions génératrices de revenus — nouveaux abonnements payants, renouvellements et achats uniques. Les essais gratuits, qui ne génèrent aucun revenu et ne peuvent pas être remboursés, sont exclus. Chaque montant remboursé est rattaché à la date à laquelle il a été traité, ce qui fait apparaître la baisse de revenus sur cette même période. :::info Le montant remboursé est calculé avant déduction des frais du store. ::: ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Raison du remboursement, Pays, Type d'offre, ID d'offre, Type de réduction d'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Raison du remboursement, Produit, Pays, Store, Paywall, Audience, Placement, Durée, Type d'offre, Type de réduction d'offre, ID d'offre, Segment et Attribution. ## Gestion des demandes de remboursement \{#refund-request-management\} Le Refund saver aide les utilisateurs d'Adapty à gérer plus efficacement les demandes de remboursement de l'App Store d'Apple grâce à l'automatisation. Il fait gagner du temps et réduit les pertes de revenus en simplifiant le processus. Grâce aux notifications en temps réel et aux informations exploitables, cet outil facilite le traitement des demandes de remboursement tout en restant conforme aux directives d'Apple. En savoir plus sur le [Refund saver](refund-saver). ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#revenue). - [Événements de remboursement](refund-events) - [Problème de facturation](billing-issue) - [Délai de grâce](grace-period) --- # File: grace-period --- --- title: "Délai de grâce" description: "Comprenez le fonctionnement des délais de grâce des abonnements et améliorez la rétention des utilisateurs." --- Le graphique Délai de grâce affiche le nombre d'abonnements ayant été placés en délai de grâce en raison d'un [problème de facturation](billing-issue). Pendant cette période, l'abonnement reste actif pendant que le store tente d'obtenir le paiement de l'abonné. Si le paiement n'est pas reçu avant la fin du délai de grâce, l'abonnement passe à l'état de problème de facturation. ## Calcul \{#calculation\} La métrique Délai de grâce comptabilise les abonnements qui sont entrés en délai de grâce durant la période sélectionnée. Le délai de grâce commence lorsque le renouvellement d'un abonnement échoue et dure jusqu'à 6 jours pour les abonnements hebdomadaires ou 16 jours pour les autres périodes de facturation. Si le paiement aboutit pendant cette fenêtre, l'abonnement se poursuit normalement ; dans le cas contraire, l'abonnement passe à l'état de [problème de facturation](billing-issue). ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [Tableau de comparaison des métriques](metric-comparison-table#billing-issues-and-revenue-recovery). - [Remboursements (montant)](refund-money) - [Événements de remboursement](refund-events) - [Problème de facturation](billing-issue) --- # File: grace-period-converted --- --- title: "Délai de grâce converti" description: "Suivez le nombre d'abonnements entrés en délai de grâce et renouvelés avant son expiration." --- Le graphique **Grace period converted** affiche le nombre d'abonnements qui sont entrés dans l'état de [délai de grâce](grace-period) et ont été renouvelés avec succès avant l'expiration de ce délai. ### Calcul \{#calculation\} Le graphique Grace period converted affiche le nombre quotidien de renouvellements d'abonnements pour les utilisateurs en délai de grâce. Le délai de grâce commence lorsque l'abonnement entre dans l'état de problème de facturation suite à un échec de paiement, et se termine après une durée définie (6 jours pour les abonnements hebdomadaires, 16 jours pour tous les autres) ou lorsque le paiement est reçu avec succès. Ce graphique donne des indications sur l'efficacité de la fonctionnalité de délai de grâce et peut aider à identifier d'éventuels problèmes de traitement des paiements ou de gestion des abonnements. ### Filtres disponibles \{#available-filters\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Motif de remboursement, Pays, Type d'offre, ID d'offre, Type de remise d'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Grouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ### Utilisation du graphique Grace period converted \{#grace-period-converted-chart-usage\} Utilisez ce graphique pour suivre l'efficacité du délai de grâce dans la récupération des abonnements ayant des problèmes de paiement. En surveillant les tendances de conversion dans le temps, vous pouvez identifier des schémas de résolution des paiements et évaluer l'impact des modifications apportées à vos processus de mise à jour des paiements ou à vos stratégies de communication durant les délais de grâce. ### Métriques similaires \{#similar-metrics\} - [Problème de facturation](billing-issue) - [Problème de facturation converti](billing-issue-converted) - [Revenus issus des problèmes de facturation convertis](billing-issue-converted-revenue) - [Délai de grâce](grace-period) - [Revenus issus des délais de grâce convertis](grace-period-converted-revenue) - [Montant remboursé](refund-money) - [Événements de remboursement](refund-events) --- # File: grace-period-converted-revenue --- --- title: "Revenus convertis pendant le délai de grâce" description: "Suivez le chiffre d'affaires total généré par les conversions en délai de grâce." --- Le graphique **Grace period converted revenue** affiche les revenus générés par les [conversions en délai de grâce](grace-period-converted) : les abonnements qui sont entrés dans l'état de [délai de grâce](grace-period) et ont été renouvelés avec succès avant l'expiration de la période. ### Calcul \{#calculation\} Le graphique Grace period converted revenue affiche les revenus quotidiens générés par les renouvellements d'abonnements des utilisateurs en délai de grâce. Le délai de grâce commence lorsque l'abonnement entre dans l'état de problème de facturation en raison d'un échec de paiement, et se termine après un délai défini (6 jours pour les abonnements hebdomadaires, 16 jours pour tous les autres abonnements) ou lorsque le paiement est reçu avec succès. Le graphique fournit des informations sur l'efficacité de la fonctionnalité de délai de grâce et peut aider à identifier des problèmes potentiels de traitement des paiements ou de gestion des abonnements. ### Filtres disponibles \{#available-filters\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Raison de remboursement, Pays, Type d'offre, ID d'offre, Type de remise de l'offre, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Grouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ### Utilisation du graphique Grace period converted revenue \{#grace-period-converted-revenue-chart-usage\} Utilisez ce graphique pour mesurer l'impact financier de la fonctionnalité de délai de grâce en suivant les revenus récupérés sur les abonnements ayant rencontré des problèmes de paiement. Cela vous permet de quantifier l'efficacité de votre stratégie de délai de grâce et d'évaluer le retour sur investissement de la mise en œuvre de fonctionnalités ou de communications liées au délai de grâce. ### Métriques similaires \{#similar-metrics\} - [Problème de facturation](billing-issue) - [Problème de facturation converti](billing-issue-converted) - [Revenus convertis liés au problème de facturation](billing-issue-converted-revenue) - [Délai de grâce](grace-period) - [Délai de grâce converti](grace-period-converted) - [Remboursements](refund-money) - [Événements de remboursement](refund-events) --- # File: billing-issue --- --- title: "Problème de facturation" description: "Résolvez les problèmes de facturation d'abonnement grâce aux outils de support d'Adapty." --- Le graphique Problème de facturation affiche le nombre d'abonnements ayant basculé dans l'état Problème de facturation. Cet état est généralement déclenché lorsque le store (Apple ou Google, par exemple) ne parvient pas à encaisser le paiement de l'abonné pour une raison quelconque, comme une carte de crédit expirée ou un solde insuffisant. ## Calcul \{#calculation\} La métrique Problème de facturation comptabilise les abonnements qui sont entrés dans cet état au cours de la période. Un abonnement entre dans cet état lorsque le store (Apple ou Google) ne peut pas traiter le paiement de renouvellement — généralement en raison d'une carte de crédit expirée ou d'un solde insuffisant. Pendant cet état, l'abonnement n'est pas actif. Si la fonctionnalité [délai de grâce](grace-period) est activée, l'abonnement ne bascule en état Problème de facturation qu'après l'expiration du délai de grâce sans paiement. ## Filtres et regroupements disponibles \{#available-filters-and-grouping\} :::link Article principal : [Contrôles des analyses](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Période, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Paywall, Audience, Placement, Durée, Segment et Attribution. ## Métriques similaires \{#similar-metrics\} Pour une comparaison côte à côte de ces métriques, consultez le [tableau de comparaison des métriques](metric-comparison-table#billing-issues-and-revenue-recovery). - [Problème de facturation converti](billing-issue-converted) - [Revenus des problèmes de facturation convertis](billing-issue-converted-revenue) - [Remboursements](refund-money) - [Événements de remboursement](refund-events) - [Délai de grâce](grace-period) - [Délai de grâce converti](grace-period-converted) - [Revenus du délai de grâce convertis](grace-period-converted-revenue) --- # File: billing-issue-converted --- --- title: "Problème de facturation résolu" description: "Suivez le nombre de problèmes de facturation résolus avant la fin du cycle de facturation." --- Le graphique Billing issue converted affiche le nombre quotidien d'abonnements qui sont entrés dans l'état [Billing Issue](billing-issue) et ont été renouvelés avant la fin du cycle de facturation. ### Calcul \{#calculation\} Le graphique Billing issue converted affiche le nombre d'abonnements qui sont entrés dans l'état [Billing Issue](billing-issue) au cours du cycle de facturation en cours et ont été renouvelés ce jour-là. Un abonnement entre dans l'état Billing Issue lorsque le store (par ex. Apple, Google) est dans l'impossibilité de traiter le paiement de l'abonné pour une raison quelconque, comme une carte de crédit expirée ou des fonds insuffisants. Pendant l'état Billing Issue, l'abonnement n'est pas considéré comme actif. Si la fonctionnalité de délai de grâce est activée dans les paramètres du store, l'abonnement ne passera à l'état Billing Issue qu'une fois le délai de grâce expiré. ### Filtres disponibles \{#available-filters\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Refund Reason, Country, Offer Type, Offer ID, Offer Discount Type, Paywall, A/B tests, Placement, Period, Segment, Store, Product et Duration. - ✅ Grouper par : Product, Country, Store, Paywall, Audience, Placement, Duration, Segment et Attribution. ### Utilisation du graphique Billing issue converted \{#billing-issue-converted-chart-usage\} Utilisez ce graphique pour suivre l'efficacité de la résolution des problèmes de facturation au cours du cycle de facturation, après expiration du délai de grâce. En surveillant les tendances de résolution dans le temps, vous pouvez identifier des patterns dans le recouvrement des paiements et évaluer l'impact des modifications apportées à votre logique de relance de paiement ou à vos stratégies de communication lors de problèmes de facturation. ### Métriques similaires \{#similar-metrics\} - [Billing issue](billing-issue) - [Billing issue converted revenue](billing-issue-converted-revenue) - [Refund money](refund-money) - [Refund events](refund-events) - [Grace period](grace-period) - [Grace period converted](grace-period-converted) - [Grace period converted revenue](grace-period-converted-revenue) --- # File: billing-issue-converted-revenue --- --- title: "Revenus convertis suite à un problème de facturation" description: "Résolvez les problèmes de facturation des abonnements grâce aux outils de support d'Adapty." --- Le graphique **Billing issue converted revenue** affiche les revenus issus des [conversions après un problème de facturation](billing-issue-converted) : les abonnements qui sont entrés dans l'état [Billing Issue](billing-issue) et ont été renouvelés avant la fin du cycle de facturation. ### Calcul \{#calculation\} Le graphique **Billing issue converted revenue** affiche les revenus quotidiens des abonnements qui sont entrés dans l'état [Billing Issue](billing-issue) lors du cycle de facturation en cours et ont été renouvelés ce jour-là. Un abonnement entre dans l'état Billing Issue lorsque le store (par exemple Apple ou Google) ne parvient pas à traiter le paiement de l'abonné pour une raison quelconque, comme une carte de crédit expirée ou des fonds insuffisants. Durant cet état, l'abonnement n'est pas considéré comme actif. Si la fonctionnalité délai de grâce est activée dans les paramètres du store, l'abonnement ne passera à l'état Billing Issue qu'après l'expiration de ce délai. ### Filtres disponibles \{#available-filters\} :::link Article principal : [Contrôles Analytics](controls-filters-grouping-compare-proceeds) ::: - ✅ Filtrer par : Attribution, Audience, Refund Reason, Country, Offer Type, Offer ID, Offer Discount Type, Paywall, A/B tests, Placement, Period, Segment, Store, Product et Duration. - ✅ Regrouper par : Product, Country, Store, Paywall, Audience, Placement, Duration, Segment et Attribution. ### Utilisation du graphique Billing issue converted revenue \{#billing-issue-converted-revenue-chart-usage\} Utilisez ce graphique pour mesurer l'impact financier des problèmes de facturation résolus en suivant les revenus récupérés après l'expiration du délai de grâce. Cela vous permet de quantifier l'efficacité de votre stratégie de récupération après incident de facturation et d'évaluer le retour sur investissement des mécanismes de nouvelle tentative de paiement ou des communications ciblées auprès des utilisateurs. ### Métriques similaires \{#similar-metrics\} - [Billing issue](billing-issue) - [Billing issue converted](billing-issue-converted) - [Refund money](refund-money) - [Refund events](refund-events) - [Grace period](grace-period) - [Grace period converted](grace-period-converted) - [Grace period converted revenue](grace-period-converted-revenue) --- # File: ltv --- --- title: "Lifetime Value (LTV)" description: "Découvrez comment calculer et optimiser la Lifetime Value (LTV) dans Adapty." --- Le LTV réalisé (Lifetime Value) par client payant affiche le revenu qu'une cohorte de clients payants a réellement généré après déduction des remboursements, divisé par le nombre de clients payants dans cette cohorte. Ce graphique vous indique donc le revenu moyen que vous générez par client payant. Adapty conçoit le graphique LTV pour répondre à plusieurs questions importantes sur les revenus de votre application et le comportement de vos clients : 1. Combien d'argent chaque cohorte génère-t-elle sur toute sa durée de vie avec votre application ? 2. À quel moment une cohorte devient-elle rentable ? 3. Comment optimiser vos dépenses marketing et d'acquisition pour attirer des clients à forte valeur LTV ? 4. Combien de temps faut-il pour rentabiliser votre investissement dans l'acquisition de nouveaux clients ? Le graphique LTV fonctionne avec les données de l'application que nous collectons via notre SDK et les événements intégrés. Grâce à ces informations, vous pourrez comprendre les performances de vos abonnements et les revenus générés par vos abonnés sur une période donnée. Vous pouvez utiliser ces données pour prendre des décisions éclairées concernant vos offres d'abonnement, vos dépenses publicitaires et vos stratégies d'acquisition clients. Les filtres vous permettront également de segmenter les données par pays, attribution et d'autres variables, pour une compréhension plus fine de votre base clients. ### LTV par renouvellements \{#ltv-by-renewals\} La vue **LTV by renewals** présente les données relatives à la période d'abonnement (P), en capturant spécifiquement la première fois qu'un client effectue un paiement. Dans le cas d'un abonnement hebdomadaire, cela correspond à la période d'abonnement hebdomadaire suivante. ### LTV par jours \{#ltv-by-days\} La vue **LTV by days** organise et filtre les données selon des intervalles quotidiens, hebdomadaires ou mensuels. Elle fournit des informations sur le revenu total généré par tous les utilisateurs ayant installé l'application un jour, une semaine ou un mois donné, divisé par le nombre d'utilisateurs payants sur cette même période. Cette vue offre des insights précieux sur le suivi des revenus et permet une compréhension globale du comportement des utilisateurs dans le temps. ### Durée de cohorte et période \{#cohort-length-and-time-frame\} Deux paramètres de temps contrôlent ce qu'affiche le tableau : - **Time frame** — la plage de dates. Configurez-la dans le calendrier au-dessus du tableau. - **Cohort length** — la taille de chaque ligne : jour, semaine, mois, trimestre ou année. Avec une longueur mensuelle, chaque ligne couvre un mois d'installations. Les deux fonctionnent indépendamment. Par exemple : une période de 6 mois avec une longueur de cohorte mensuelle vous donne un tableau avec 6 lignes. Une période d'1 an avec une longueur de cohorte hebdomadaire vous donne 52 lignes. ### Calcul \{#calculation\} Le LTV réalisé est calculé à partir du revenu total généré par chaque cohorte de clients, après déduction des remboursements. _LTV pour le jour/la semaine/le mois = Revenu généré par tous les utilisateurs payants ayant installé l'application ce jour/cette semaine/ce mois / le nombre d'utilisateurs payants ayant installé l'application ce jour/cette semaine/ce mois_ Le calcul du LTV inclut les montées en gamme, les baisses de gamme et les réactivations, comme lorsqu'un utilisateur modifie son plan d'abonnement ou sa tarification. Il prend en compte le revenu généré par l'abonnement initial et les renouvellements suivants basés sur le plan mis à jour. ### Regroupement et filtrage disponibles \{#available-grouping-and-filtering\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: Les filtres et les regroupements peuvent être appliqués aux deux vues du graphique LTV (renouvellements et jours), ce qui vous permet d'explorer des cohortes spécifiques et de comprendre leur comportement dans le temps. - ✅ Filtrer par : Attribution, Audience, Pays, Paywall, Tests A/B, Placement, Segment, Store, Produit et Durée. - ✅ Regrouper par : Produit, Pays, Store, Durée, Segment et Cohorte (Jour, Semaine, Mois ou Année). Le graphique LTV réalisé dans Adapty aide à obtenir des insights précieux sur le comportement des clients, à optimiser les stratégies marketing, à suivre les performances des revenus et à prendre des décisions basées sur les données pour maximiser la valeur à long terme de leurs clients. --- # File: analytics-cohorts --- --- title: "Analyse par cohortes" description: "Utilisez les cohortes analytiques d'Adapty pour suivre l'engagement des utilisateurs et les tendances d'abonnement." --- Les cohortes Adapty sont conçues pour répondre à plusieurs questions importantes : 1. À quel jour une cohorte est-elle rentabilisée ? 2. Combien d'argent l'application génère-t-elle pour une cohorte donnée ? 3. Combien puis-je dépenser pour attirer un client payant ? 4. Combien de temps faut-il pour amortir les dépenses publicitaires ? Les cohortes s'appuient sur les données de l'application collectées via le SDK et les notifications du store, sans nécessiter de configuration supplémentaire de votre part. ## Cohortes par renouvellements ou par jours \{#cohorts-by-renewals-or-by-days\} Vous pouvez analyser les cohortes par renouvellements ou par jours. Ce paramètre modifie les intitulés des colonnes et, par conséquent, l'approche d'analyse. Le suivi **par jours** fournit des informations précieuses pour la budgétisation et la compréhension des délais de paiement. C'est particulièrement utile pour suivre les produits non basés sur un abonnement, comme les consommables ou les achats uniques. Dans ce mode, la couleur bleue dans les cellules du tableau tend à se concentrer au milieu des lignes pour deux raisons principales. D'une part, la vue par jours permet de voir rapidement les paiements associés aux produits de courte durée, alors que dans la vue par renouvellements, ils sont regroupés avec les renouvellements mensuels et annuels. D'autre part, les paiements différés contribuent à ce schéma de distribution, certains utilisateurs payant plus tard que prévu. Le suivi **par renouvellements** montre quant à lui la rétention et le churn des cohortes d'un paiement à l'autre, sans tenir compte de la date. Les utilisateurs tardifs qui ont payé avec un délai quelconque (qui peut se compter en mois) sont ajoutés au nombre de leur période d'abonnement. Cette approche ne reflète pas la situation des revenus calendaires, mais elle est nettement plus pratique pour analyser la rétention et le churn des cohortes et en tirer des enseignements comportementaux. Choisissez le mode qui vous convient ou utilisez les deux pour multiplier les conclusions et les idées. ## Comment Adapty construit les cohortes \{#how-adapty-builds-cohorts\} Voyons, à travers l'exemple des cohortes par renouvellements, comment le tableau est construit. Pour constituer les cohortes, nous utilisons deux mesures : les installations de l'application et les transactions (achats). Chaque ligne d'une cohorte représente un intervalle de temps spécifique, allant d'un jour à un an. Chaque ligne commence par le nombre d'utilisateurs qui ont installé l'application durant cet intervalle et ont activé un abonnement ou effectué un achat de produit à vie ou hors abonnement. Chaque colonne suivante de la ligne indique le nombre d'utilisateurs ayant renouvelé leur abonnement jusqu'à cette période. M3 correspond au mois 3 et signifie que les abonnés ont effectué 3 renouvellements consécutifs jusqu'à ce point ; W7 correspond à la semaine 7, et Y2 à l'année 2. Vous pouvez parfois voir P2 dans les cohortes. P désigne la période d'abonnement. Adapty l'affiche à la place de W/M/Y lorsque plusieurs produits avec des périodes de renouvellement différentes sont présents dans la même cohorte. Nous utilisons des dégradés de couleur pour mettre en évidence les différences de valeurs entre cohortes. Les valeurs les plus élevées ont des couleurs plus saturées. L'image ci-dessous montre une cohorte typique. 1. Cette cohorte affiche les données uniquement pour les produits hebdomadaires (repère n°1). 2. Elle n'exclut pas les produits et affiche les revenus en valeurs absolues (repère n°2). 3. La période de temps est les 6 derniers mois, et la durée de cohorte est de 1 mois (repère n°3). 4. La ligne **Total** (repère n°4) affiche la valeur cumulée pour chaque période. Le montant de 442 K$ dans la première cellule de la ligne **Total** cumule les revenus de la première période (activation de l'abonnement) de tous les mois (nov., déc., etc.) jusqu'à la fin de la période. La cellule Total indique le nombre de clients ayant installé l'application durant toute la période. 5. La première colonne de la ligne Nov 2023 (repère n°5) affiche les revenus de la première période (activation de l'abonnement) de 37,7 K$ pour les clients ayant installé l'application en novembre 2023. Le nombre de ces clients, soit 95 129, est affiché dans la colonne d'en-tête. La deuxième colonne de la ligne Nov 2023 affiche les revenus de la semaine 2 (abonnements renouvelés jusqu'à la 2e semaine) de 8 770 $ pour les clients ayant installé l'application en novembre 2023. 6. Dans le tableau, vous pouvez voir le chiffre d'affaires total, l'ARPU, l'ARPPU et l'ARPAS (repère n°6). Vous pouvez en savoir plus sur ces métriques un peu plus loin dans cet article. 7. Vous pouvez configurer les colonnes dans la partie droite du tableau via le menu déroulant **Columns** (repère n°7). 8. Au-dessus du tableau, à droite (repère n°8), se trouve également un menu déroulant pour calculer les commissions des stores et les taxes pour des analyses de cohortes spécifiques. Vous pouvez découvrir comment Adapty calcule les commissions des stores et les taxes dans [cet article](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). Après avoir choisi l'option correspondante dans le menu déroulant, les données de revenus seront recalculées en conséquence. 9. Sur le côté droit du tableau, vous pouvez voir les revenus prédits (Predicted Revenue) et la valeur vie prédite (Predicted LTV) (repère n°9). Le champ **Predicted Revenue** estime le revenu total généré par une cohorte d'abonnés dans un délai donné, tandis que le champ **Predicted LTV** représente la valeur anticipée de chaque utilisateur de la cohorte. Vous pouvez survoler n'importe quelle cellule de la cohorte pour afficher les métriques détaillées de cette période. Les cellules avec des lignes obliques en arrière-plan correspondent aux périodes non encore terminées ; les valeurs qu'elles contiennent sont donc susceptibles d'augmenter. ## Durée de cohorte et période \{#cohort-length-and-time-frame\} Deux paramètres de temps contrôlent ce qu'affiche le tableau : - **Time frame** — la plage de dates. Configurez-la dans le calendrier au-dessus du tableau. - **Cohort length** — la taille de chaque ligne : jour, semaine, mois, trimestre ou année. Avec une longueur mensuelle, chaque ligne couvre un mois d'installations. Les deux fonctionnent indépendamment. Par exemple : une période de 6 mois avec une longueur de cohorte mensuelle vous donne un tableau avec 6 lignes. Une période d'1 an avec une longueur de cohorte hebdomadaire vous donne 52 lignes. ## Filtres, métriques, segments de cohortes et export CSV \{#filters-metrics-cohort-segments-and-export-in-csv\} :::link Article principal : [Contrôles analytiques](controls-filters-grouping-compare-proceeds) ::: Par défaut, Adapty construit les cohortes à partir des données de tous les achats. Vous pouvez filtrer par durée de produit, produits spécifiques, pays, store, paywall, segment et données d'attribution. À droite du panneau de contrôle, un bouton permet d'exporter les données de cohortes au format CSV. Vous pouvez ensuite l'ouvrir dans Excel ou Google Sheets, ou l'importer dans votre propre système analytique. Il existe 6 métriques pouvant être affichées dans les cohortes : Subscriptions, Payers, Revenue, ARPU, ARPPU et ARPAS. Vous pouvez les afficher en valeurs absolues ou en variation relative par rapport au début de la cohorte. ## Abonnements, payeurs, revenu total, ARPU, ARPPU et ARPAS \{#subscriptions-payers-total-revenue-arpu-arppu-and-arpas\} **Subscriptions** correspond au nombre total d'abonnements actifs, d'achats à vie et d'achats hors abonnement effectués par une cohorte dans la période sélectionnée. Suivre cette métrique vous aide à comprendre le comportement des clients et l'efficacité de vos offres. Ces informations vous permettent d'affiner votre stratégie produit, d'adapter vos actions marketing et d'optimiser vos sources de revenus. **Payers** correspond au nombre total d'utilisateurs ayant effectué un achat au sein d'une cohorte. Cette métrique vous permet de comprendre combien d'utilisateurs uniques contribuent à vos revenus. Pour les applications comportant une part significative d'achats hors abonnement, elle peut mettre en évidence la portée réelle de vos offres : elle indique si une large base d'utilisateurs effectue des achats ou si les revenus sont générés par un groupe restreint d'acheteurs récurrents. Comprendre le nombre de payeurs aide à évaluer l'engagement des clients, à planifier des actions marketing ciblées et à optimiser les stratégies de revenus. **Total revenue** correspond aux revenus cumulés d'une cohorte dans la période sélectionnée (par ex. du 25 nov. 2022 au 24 mai 2023). Cette métrique vous permet de savoir combien d'argent vous avez collecté auprès des utilisateurs d'une cohorte donnée et de calculer le ROAS. Par exemple, si les dépenses publicitaires de septembre 2022 s'élevaient à 10 000 $, et que les revenus totaux de la cohorte de septembre 2022 sont de 30 000 $, le ROAS est de 3:1. **ARPU** est le revenu moyen par utilisateur. Il est calculé comme suit : revenu total / nombre d'utilisateurs uniques. 60 000 $ de revenus / 5 000 utilisateurs = 12 $ d'ARPU. Il est utile de comparer cette valeur au coût par installation (CPI) pour évaluer l'efficacité de vos campagnes marketing. **ARPPU** est le revenu moyen par utilisateur payant. Il est calculé comme suit : revenu total / nombre d'utilisateurs payants uniques. 60 000 $ de revenus / 1 000 utilisateurs payants = 60 $ d'ARPPU. Il vous permet de comprendre combien vous rapporte en moyenne un client payant. **ARPAS** est le revenu moyen par abonné actif. Il est calculé comme suit : revenu total / nombre d'abonnés actifs. Par abonnés, nous entendons ceux qui ont activé une période d'essai ou un abonnement. 60 000 $ de revenus / 1 500 abonnés = 40 $ d'ARPAS. ## Commissions et taxes \{#commission-fees-and-taxes\} Un aspect important du calcul des revenus dans les cohortes est la prise en compte des commissions des stores et des taxes (qui peuvent varier selon le pays du compte store de l'utilisateur). Adapty prend actuellement en charge le calcul des commissions et des taxes pour l'App Store et le Play Store dans l'analyse par cohortes. Pour plus de détails sur la façon dont Adapty calcule les taxes et les commissions dans ses analyses, veuillez consulter notre [documentation](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). ## Revenue vs Proceeds \{#revenue-vs-proceeds\} Revenue et Proceeds sont tous deux des métriques financières. Vous pouvez considérer Revenue comme le chiffre d'affaires brut et Proceeds comme le chiffre d'affaires net. Revenue ne tient pas compte des frais de l'App Store / Play Store, contrairement à Proceeds. Par conséquent, Proceeds est toujours inférieur à Revenue. La commission effectivement déduite varie en fonction de plusieurs facteurs, notamment l'éligibilité à des programmes comme le [Small Business Program](app-store-small-business-program) (15 %), les taux réduits pour les abonnements de longue durée (15 % après un an de renouvellement), les taux spécifiques à certains pays et les taux standard (jusqu'à 30 %). Adapty détermine automatiquement le taux de commission applicable pour chaque transaction de vos clients et calcule les Proceeds en conséquence. Pour plus d'informations sur la façon dont les taux de commission sont déterminés, consultez la documentation [Commissions et taxes du store](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). ## Gestion des remboursements \{#refund-handling\} Deux règles s'appliquent universellement à toutes les métriques de cohortes : - Un remboursement est daté du jour où il a été émis, et non de la date d'achat d'origine. Un remboursement n'affecte une cohorte que lorsque sa date tombe dans la période sélectionnée. - Un remboursement ne retire jamais un utilisateur de sa cohorte et ne modifie jamais le nombre d'installations. L'appartenance à une cohorte est fixée au moment de l'installation de l'application. Au-delà de ces règles, l'effet d'un remboursement dépend de la métrique et du [mode d'affichage](#cohorts-by-renewals-or-by-days). Lisez la colonne correspondant au mode que vous utilisez. | Métrique | Par renouvellements | Par jours | | --- | --- | --- | | Installations (taille de la cohorte) | Non affecté. L'utilisateur reste dans sa cohorte. | Identique à « Par renouvellements ». | | Abonnements | Les abonnements remboursés sont toujours comptabilisés. | Un remboursement retire l'abonnement du décompte. | | Payeurs | Les utilisateurs payants remboursés sont toujours comptabilisés. | Un remboursement retire l'utilisateur du décompte, même s'il a effectué d'autres paiements réussis. | | Revenue | Le montant remboursé est soustrait de la colonne de la période de renouvellement où le paiement avait été initialement comptabilisé. | Le montant remboursé est soustrait à partir du jour du remboursement. | | ARPU | Revenue / installations. Un remboursement réduit le revenu ; le nombre d'installations ne change jamais. | Identique à « Par renouvellements ». | | ARPPU | Revenue / utilisateurs payants. Un remboursement peut réduire à la fois le revenu et le nombre d'utilisateurs payants, de sorte que l'ARPPU peut évoluer plus fortement que le revenu seul. | Identique à « Par renouvellements ». | | ARPAS | Revenue / abonnés actifs. Un remboursement réduit le revenu ; le nombre d'abonnés ne change pas. | Identique à « Par renouvellements ». | | Rétention | Non affecté. Comptabilise les événements d'essai et d'achat, pas les remboursements. | Identique à « Par renouvellements ». | Un remboursement soustrait le montant remboursé du revenu, quel que soit le mode de comptabilisation des revenus actif. ### Taux de conversion et ARPPU \{#conversion-rate-and-arppu\} Les remboursements n'affectent pas un taux de conversion basé sur les installations, car le nombre d'installations ne change jamais. Un taux de conversion basé sur les utilisateurs payants est différent. Les remboursements le réduisent dans la vue **par jours**, mais pas dans la vue **par renouvellements**. Dans la vue **par renouvellements**, les colonnes Revenue et Payers affichent chacune une période individuellement. La colonne ARPPU, en revanche, ne le fait pas. Chaque cellule ARPPU cumule tout, de la première période de la cohorte jusqu'à la période de la colonne. Elle couvre donc toujours plusieurs périodes à la fois, en excluant les utilisateurs remboursés. Pour cette raison, diviser le Revenue d'une seule période par ses utilisateurs payants ne reproduira pas l'ARPPU affiché. **Exemple.** Un utilisateur installe l'application en février et souscrit un abonnement, puis reçoit un remboursement intégral en avril. En consultant la cohorte de février **par jours** : - Période février–mars, avant que le remboursement n'entre dans la fenêtre : l'utilisateur compte pour 1 utilisateur payant, et son revenu est inclus en totalité. - Période février–juin, après que le remboursement est entré dans la fenêtre : l'utilisateur compte pour 0 utilisateur payant, et son revenu tombe à 0. Dans les deux périodes, le nombre d'installations de février et la rétention restent identiques. [La gestion des remboursements par les métriques](refund-events#how-metrics-handle-refunds) compare ces mêmes règles entre le MRR, les graphiques de revenus et les exports de données. ## Prédiction : Revenue et LTV \{#prediction-revenue-and-ltv\} Le **revenu prédit** est une estimation du revenu total qu'une cohorte d'abonnés payants devrait générer dans la période sélectionnée après la création de la cohorte. Il est calculé en multipliant la LTV prédite de la cohorte par le nombre prédit d'utilisateurs payants au sein de la cohorte. Par exemple, si la LTV prédite est de 50 $ et qu'il y a 100 utilisateurs payants dans une cohorte, le revenu prédit sera de 5 000 $. La **LTV prédite** est la valeur vie estimée par abonné payant, représentant le revenu moyen que chaque abonné payant devrait générer dans la période sélectionnée après la création de la cohorte. Ces prédictions sont basées sur les schémas historiques de rétention des cohortes, en utilisant les données propres à l'application lorsqu'un historique suffisant est disponible, et des moyennes inter-applications dans le cas contraire. Pour une documentation détaillée sur le modèle de prédiction d'Adapty, veuillez consulter notre [documentation sur les prédictions](predicted-ltv-and-revenue). Les cohortes Adapty fournissent des informations détaillées sur le comportement des utilisateurs et les performances financières de votre application. En analysant les cohortes par renouvellements ou par jours, vous pouvez déterminer à quel moment les cohortes deviennent rentables, suivre les revenus, calculer le revenu moyen par utilisateur et comprendre le temps nécessaire pour amortir les dépenses publicitaires. Grâce à des filtres, des métriques et des options d'export personnalisables, Adapty vous donne les moyens de prendre des décisions basées sur les données et d'optimiser vos stratégies d'acquisition d'utilisateurs et de monétisation pour maximiser le succès de votre application. --- # File: analytics-funnels --- --- title: "Analyse des entonnoirs" description: "Comprenez les entonnoirs d'analyse dans Adapty pour surveiller le comportement des utilisateurs et améliorer les conversions." --- Les entonnoirs Adapty sont conçus pour vous aider à répondre à ce type de questions : 1. Quel pourcentage des installations se convertit en clients payants ? 2. Quelle part de ceux qui ont essayé le produit est devenue fidèle ? 3. Quelles étapes affichent un fort taux de chute et méritent plus d'attention ? 4. Pourquoi les clients arrêtent-ils de payer ? Grâce à un graphique en entonnoir, vous pouvez également obtenir davantage d'informations sur le comportement des utilisateurs en appliquant des filtres et des regroupements. Les entonnoirs fonctionnent avec les données collectées via le SDK et les notifications du store, sans aucune configuration supplémentaire de votre part. :::note Les entonnoirs reflètent les données d'installation selon votre définition de l'installation dans les [App Settings](general#4-installs-definition-for-analytics). ::: <img src="/assets/shared/img/funnels-tab.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Lire le graphique en entonnoir étape par étape \{#funnel-chart-step-by-step\} Parcourons les éléments d'un entonnoir pour comprendre comment lire le parcours utilisateur sur le graphique. <img src="/assets/shared/img/ed5bf5d-CleanShot_2022-06-23_at_09.36.49.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Installations \{#installs\} La 1ère colonne (1) correspond au nombre d'installations. Elle est affichée en valeur absolue (2) du total des installations (et non des utilisateurs uniques), ainsi qu'à 100 % — la valeur d'entrée la plus élevée servant de base au calcul des conversions relatives. Si un utilisateur supprime l'application puis la réinstalle, deux installations distinctes sont comptabilisées. La zone grise adjacente représente les paramètres de transition entre les étapes. Le pourcentage de conversion vers l'étape suivante (Paywall affiché) est indiqué sur un drapeau (3). Le pourcentage de chute et la valeur absolue du désabonnement sont affichés en dessous (4). <img src="/assets/shared/img/00416f9-CleanShot_2022-06-23_at_14.02.06.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Paywall affiché \{#paywall-displayed\} La 2ème colonne (5) indique le nombre d'utilisateurs de l'application ayant vu un paywall au moins une fois (6). Seuls les utilisateurs dont l'installation s'est produite durant la période sélectionnée sont pris en compte. Si un utilisateur voit un paywall durant la période sélectionnée mais que sa date d'installation est hors plage, sa vue n'est pas comptabilisée. Un pourcentage de ces vues rapporté à la 1ère étape est également affiché (7). Vous remarquerez que ce pourcentage est égal au drapeau gris (3) de la 1ère étape. Cette égalité ne s'applique qu'à ces deux premières étapes. Nous collectons les données pour cette étape à partir de tous vos paywalls utilisant la méthode `logShowFlow()` (iOS SDK v4+) / `logShowPaywall()`. Assurez-vous donc d'envoyer chaque vue de paywall à Adapty via cette méthode, comme décrit dans la [documentation](present-remote-config-paywalls#track-paywall-view-events). La zone grise à côté de la 2ème colonne représente la transition. Le pourcentage de conversion vers l'étape suivante (Période d'essai) est affiché sur un drapeau (8). Le pourcentage de chute et la valeur absolue des clients perdus après le paywall sont indiqués en dessous (9). <img src="/assets/shared/img/fb11650-CleanShot_2022-06-23_at_15.54.32.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Périodes d'essai \{#trials\} La 3ème colonne (10) affiche le nombre de périodes d'essai activées sur les paywalls par les clients ayant installé l'application durant la période sélectionnée (11). Si un filtre est appliqué sur un ou des produits sans période d'essai, cette valeur est nulle et la colonne est vide. Un pourcentage d'essais rapporté à la 1ère étape est également visible, indiquant la conversion des installations vers les essais (12). Vous remarquerez que ce pourcentage n'est plus égal au drapeau gris (8) de la conversion de l'étape précédente. C'est parce que nous comparons la valeur actuelle avec la 1ère étape en haut du graphique et avec l'étape précédente sur les drapeaux gris. La zone grise à côté de la 3ème colonne affiche donc le pourcentage de conversion vers l'étape suivante (Payant), indiqué sur un drapeau (13). Le pourcentage de chute et la valeur absolue des clients perdus durant la période d'essai sont affichés en dessous (14). <img src="/assets/shared/img/7b88909-CleanShot_2022-06-23_at_15.54.32_-_2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Abonnements et renouvellements \{#subscriptions-and-renewals\} La 4ème colonne affiche le nombre d'abonnements activés (15). Pour les produits sans période d'essai, ce nombre inclut les abonnements directs depuis un paywall. Pour les produits avec période d'essai, il contient le nombre d'essais convertis en abonnements payants. Si vous avez les deux types de produits, avec et sans essai, il s'agit de la somme des deux. Le pourcentage en haut indique la conversion depuis les installations (16). Le pourcentage sur le drapeau gris indique la conversion vers l'étape suivante (renouvellement pour la 2ème période) (17). Le pourcentage de chute avant le renouvellement vers la 2ème période et sa valeur absolue sont affichés sous la conversion (18). <img src="/assets/shared/img/d13bf9b-CleanShot_2022-06-23_at_15.54.32-3.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Cette étape marque le début d'une série d'étapes de structure similaire. Après le 2ème renouvellement vient le 3ème, puis le 4ème, etc. Si votre historique d'application contient suffisamment de données, vous pouvez visualiser des dizaines de périodes via le défilement horizontal. La logique de ces étapes reste la même : - le pourcentage par rapport aux installations en haut, - le pourcentage par rapport à l'étape précédente en bas, - le nombre absolu de renouvellements en haut, - le nombre absolu de désabonnements en bas, - une info-bulle au survol pour les raisons de désabonnement. ### Raisons de désabonnement \{#churn-reasons\} Adapty détaille les statistiques de *désabonnement* à partir de l'étape Période d'essai et au-delà. Chaque utilisateur ayant atteint une étape sans passer à la suivante est comptabilisé comme un désabonnement. * Si un événement spécifique (par exemple, l'expiration d'un essai ou un problème de facturation) a causé l'absence de conversion, Adapty en affiche la raison. * Le statut **unknown** est un état temporaire. Il indique que l'utilisateur n'a pas encore rencontré l'événement lui permettant de passer à l'étape suivante. À l'étape Période d'essai, cela signifie généralement que l'essai n'a pas encore pris fin. C'est fréquent lorsque vous consultez les entonnoirs sur de courtes plages de dates ou sur une seule journée, car les essais prennent du temps à se conclure. Adapty mettra à jour les informations une fois que l'utilisateur aura converti ou annulé l'essai. <img src="/assets/shared/img/churn-reasons.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Vue tableau, filtres et export CSV \{#table-view-filters-and-csv-export\} Le graphique en entonnoir est enrichi d'un tableau pour vous fournir un support pratique dans votre travail avec les chiffres. <img src="/assets/shared/img/4787aff-CleanShot_2022-06-23_at_21.01.44.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Ce tableau reprend l'approche de l'entonnoir avec quelques ajustements. Il comporte des colonnes affichant les données de toutes les étapes, à l'exception de l'étape du 1er abonnement payant. À la place, deux colonnes distinctes sont présentes : Installation → Payant et Essai → Payant. Elles mettent en évidence le point clé de conversion où un utilisateur gratuit devient payant. On pourrait penser qu'il s'agit d'une division par type de produit : la colonne Installation → Payant n'afficherait que les produits sans période d'essai, tandis que la colonne Essai → Payant ne contiendrait que les produits avec période d'essai. Mais ce n'est pas tout à fait ainsi que cela fonctionne. Car nous prenons également en compte les utilisateurs dont la période d'essai a expiré et qui achètent un produit avec essai comme s'il n'en avait pas. <img src="/assets/shared/img/a9bcbc7-CleanShot_2022-06-23_at_21.29.12.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En approfondissant les chiffres, vous découvrirez de puissants outils de filtrage pour formuler de nouvelles hypothèses. N'hésitez pas à définir des conditions selon différentes dimensions. Collectez de véritables insights basés sur les données. Faites varier : 1. Le type de produit — économie, durée, etc. 2. La plage de dates. 3. La segmentation par pays. 4. L'attribution du trafic. 5. Le store. Sélectionnez Valeur absolue #, Pourcentage relatif % ou les deux pour n'afficher que les données nécessaires. <img src="/assets/shared/img/1475e42-CleanShot_2022-06-23_at_21.50.33_-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Enfin, à droite du panneau de contrôle, un bouton permet d'exporter les données de l'entonnoir au format CSV. Vous pouvez ensuite l'ouvrir dans Excel ou Google Sheets, ou l'importer dans votre propre système d'analyse. :::important Informez Adapty si votre application est inscrite à un programme de commission réduite. Pour garantir l'exactitude des calculs, précisez votre statut dans les programmes [Small Business Program](app-store-small-business-program) et [Reduced Service Fee program](google-reduced-service-fee) dans vos [paramètres d'application](general). ::: <img src="/assets/shared/img/ff23846-CleanShot_2022-06-23_at_22.15.49.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: analytics-retention --- --- title: "Analyse de la rétention" description: "Comprenez les analyses de rétention des utilisateurs et optimisez votre stratégie d'abonnement." --- Les graphiques de rétention peuvent vous aider à répondre aux questions suivantes : 1. Comment votre application fidélise-t-elle ses clients d'une période à l'autre ? 2. Quels produits sont les plus attractifs et retiennent le mieux les utilisateurs ? 3. Quels groupes d'utilisateurs sont les plus fidèles ? 4. Quel niveau de rétention peut servir de référence pour la croissance ? 5. Et bien sûr, comment économiser de l'argent en investissant dans l'audience déjà acquise plutôt qu'en cherchant de nouveaux utilisateurs. Vous trouverez des informations précieuses sur le comportement des utilisateurs en définissant des filtres et des groupes. La rétention est calculée à partir des données que nous collectons via le SDK et les notifications du store — aucune configuration supplémentaire n'est requise de votre côté. :::tip **Fidélisez vos abonnés avant qu'ils ne se désabonnent.** [Retention Messaging](retention-messaging) affiche un message personnalisé dans l'écran Annuler l'abonnement d'Apple — une raison de rester, juste au moment où l'abonné appuie sur Annuler. ::: ### Comment calculons-nous la rétention ? \{#how-do-we-calculate-retention\} En observant le graphique de rétention, vous voyez comment le nombre d'utilisateurs évolue selon l'étape franchie : l'essai (si la case « show trials » est cochée), le 1er paiement, le 2e paiement, etc. Voici ce qui est comptabilisé lorsque vous choisissez une plage de dates pour le graphique de rétention. Par exemple, vous avez sélectionné les 3 derniers mois dans le calendrier et la case « show trials » est décochée. Cela signifie que seuls les utilisateurs ayant effectué leur 1er abonnement au cours des 3 derniers mois sont comptés. Si la case « show trials » est cochée et que les 3 derniers mois sont sélectionnés, nous comptons tous les utilisateurs ayant démarré un essai au cours de ces 3 derniers mois. Pour ces abonnés, la rétention absolue à l'étape N correspond au nombre de ceux ayant effectué le Nième paiement. La valeur relative de rétention à l'étape N est calculée comme le ratio entre le nombre absolu de Nièmes paiements et le nombre total d'abonnements (ou d'essais) sur la période sélectionnée. :::info La rétention évolue rétrospectivement Quel que soit le moment où vous consultez le graphique, le nombre de référence (100 %) reste identique pour la période sélectionnée. En revanche, la rétention vers la période suivante peut augmenter avec le temps. Par exemple, pour un abonnement mensuel, si 20 premiers achats ont été effectués entre le 1er et le 31 décembre, la rétention vers la deuxième période devrait augmenter tout au long du mois de janvier (et peut-être même après), au fur et à mesure que les utilisateurs entrent dans la période d'abonnement suivante, parfois avec un léger décalage pour diverses raisons (par exemple, un délai de grâce). ::: ### Gestion des remboursements \{#refund-handling\} Les remboursements ne sont **pas** exclus de la rétention. Un utilisateur remboursé reste comptabilisé sur la courbe de rétention, ce qui peut faire paraître la Rétention plus élevée que les [Abonnements actifs](active-subscriptions) ou les [Revenus](revenue) pour la même cohorte. Pour une comparaison complète entre les métriques, consultez [Comment les métriques gèrent les remboursements](refund-events#how-metrics-handle-refunds). ### Opportunités de rétention \{#retention-opportunities\} Voyons comment tirer le meilleur parti de la fonctionnalité de rétention d'Adapty. Plutôt que de se limiter à une passion pour les chiffres, il est plus utile d'envisager la valeur business concrète que peuvent apporter les résultats analytiques. Avant de plonger dans les détails du graphique, il vaut mieux clarifier l'impact que ces données peuvent avoir. Gardons donc en tête le POURQUOI et le COMMENT. 1 - travailler avec son audience. Avant tout, la rétention concerne l'audience cible, ses préférences, et la question de savoir si votre produit répond à ses attentes tout au long de sa durée de vie en tant que client. Si vous vous êtes demandé comment mesurer la relation fondamentale de votre activité qui génère des revenus, la rétention est là pour vous. Cette mesure est utile car il est généralement moins coûteux de vendre à un client existant qu'à un inconnu. Et ce coût est faible pour deux raisons : moins d'efforts pour conclure la vente et un panier moyen plus élevé. Il peut donc être judicieux d'investir dans la fidélité de vos abonnés lorsque la rétention baisse. 2 - travailler avec le produit. La deuxième raison du POURQUOI, c'est que les graphiques de rétention montrent la durée de vie réelle de consommation de votre produit et permettent des prévisions à long terme. Et si vous souhaitez vous améliorer, corrigez le travail qui délivre le produit pour modifier sa durée de vie, puis refaites vos prévisions pour vous rapprocher de vos objectifs commerciaux. Ces ajustements peuvent s'inscrire dans une vision stratégique, en tandem avec une routine de prévision. Et oui, ce processus ne s'arrête jamais, car nous courons tous vite pour rester à la même place dans un environnement en constante évolution. 3 - travailler avec le marché. Aller plus vite que les principaux concurrents, c'est bien, mais parfois sortir de la course ordinaire peut apporter davantage de bénéfices. Lorsque vous analysez le comportement des utilisateurs dans différents pays et stores, certaines particularités locales peuvent ouvrir des insights remarquables et de nouvelles opportunités pour l'activité. Le contexte culturel et de marché peut être analysé sous l'angle de la rétention pour être ensuite utilisé dans la segmentation et le développement futur. Par exemple, vous pourrez trouver de l'eau bleue dans certaines régions et y croître plus rapidement. L'utilisation des données de rétention ne se limite bien sûr pas à cette interprétation de base, mais c'est un bon point de départ si vous souhaitez obtenir rapidement de la valeur concrète. ### Courbes, vue tableau, filtres et export CSV \{#curves-table-view-filters-and-csv-export\} Maintenant que nous avons établi les bases concernant les objectifs de rétention et les principaux modes d'interprétation, passons en revue les outils qui facilitent tout cela. Le cœur de la fonctionnalité de rétention dans Adapty est le graphique. Il montre comment le niveau de rétention évolue en fonction des étapes du cycle de vie d'un utilisateur. Ces étapes sont affichées sur l'axe horizontal : Trial, Paid (le 1er abonnement), P2 (le 2e abonnement), P3, P4, etc. Notez que l'axe commence par l'étape Trial uniquement lorsque la case « Show trials » est cochée. Pour le calcul des données, cette case fonctionne de la façon suivante. Lorsque « Show trials » est sélectionné et que l'axe commence par l'étape Trial, seuls les scénarios incluant des essais sont affichés — les transactions provenant directement des installations ne sont pas prises en compte, et l'étape Paid ne contient que les transactions issues des essais. Lorsque « Show trials » n'est pas sélectionné et que l'axe commence par l'étape Paid, cette première étape regroupe toutes les premières transactions, qu'elles proviennent d'essais ou directement d'installations. Lorsque vous survolez le graphique, une fenêtre contextuelle affichant un résumé des données apparaît. De même, si vous survolez une colonne du tableau ci-dessous, une fenêtre contextuelle récapitulative s'affiche avec les données correspondantes sur le graphique. Le tableau contient les mêmes regroupements et filtres que ceux choisis pour le graphique. Combinez librement filtres et regroupements pour une analyse avancée. Collectez de vraies informations à partir des données. Variez : 1. Type de produit. 2. Durée. 3. Plage de temps. 4. Pays. 5. Attribution. 6. Store. Utilisez les contrôles #Absolu et %Relatif pour afficher les données souhaitées. Enfin, à droite du panneau de contrôle, un bouton permet d'exporter les données du funnel en CSV. Vous pouvez ensuite l'ouvrir dans Excel ou Google Sheets, ou l'importer dans votre propre système analytique pour continuer l'analyse et les prévisions dans l'environnement de votre choix. :::warning Veillez à indiquer que votre application est incluse dans le Small Business Program dans les [Paramètres généraux Adapty](https://app.adapty.io/settings/general). ::: --- # File: analytics-conversion --- --- title: "Analyse des conversions" description: "Mesurez les taux de conversion des abonnements avec les outils d'analytique d'Adapty." --- Là où les entonnoirs offrent une vue d'ensemble et la rétention se concentre sur la fidélité des utilisateurs, l'analyse des conversions est conçue pour vous aider à évaluer l'efficacité à chaque étape clé du parcours utilisateur — dans le temps. Les conversions répondent aux questions suivantes : 1. Comment les conversions de l'application évoluent-elles dans le temps ? Y a-t-il des tendances saisonnières ? 2. Comment les conversions évoluent-elles lors d'activités marketing ou d'autres nouveaux événements ? 3. Comment les utilisateurs de différentes régions réagissent-ils à vos mises à jour d'application ? 4. Quels types de produits convertissent mieux dans le temps ? La conversion est calculée à partir des données collectées via le SDK Adapty et les notifications du store, sans aucune configuration supplémentaire de votre part. ## Contrôles principaux et graphiques \{#main-controls-and-charts\} Bien que le chiffre d'affaires soit souvent la métrique de référence pour mesurer le succès, ce n'est qu'une partie du tableau d'ensemble. Comprendre comment votre activité évolue dans le temps — à travers différents comportements utilisateurs et étapes du cycle de vie — est tout aussi important. C'est là qu'intervient l'analyse des conversions. Vous pouvez obtenir des informations plus précieuses sur le comportement des utilisateurs en appliquant des filtres et des regroupements. Pour identifier et analyser les tendances, surveillez l'évolution de vos conversions quotidiennement, mensuellement ou annuellement. Sur le côté gauche du graphique, vous trouverez le contrôle des étapes de conversion. Il vous permet de choisir quelles conversions suivre spécifiquement — par exemple Installation → Essai, Essai → Payant, ou Payant → Renouvellement. Chaque métrique de conversion suit cette logique : - Soit **X** le nombre d'utilisateurs ayant atteint l'état de départ à une date donnée (ex. : installations). - Soit **Y** le nombre de ces utilisateurs ayant finalement atteint l'état cible (ex. : démarrages d'essai). - Le taux de conversion est calculé ainsi : **Conversion = (Y / X) × 100 %** :::note La date affichée sur le graphique correspond au moment où les utilisateurs ont atteint l'état initial (X) — le moment où ils sont devenus éligibles à la conversion. ::: Vous trouverez ci-dessous l'explication de chaque conversion, accompagnée d'un exemple pour illustration. ### Installation -> Payant \{#install---paid\} Cette métrique indique le pourcentage d'utilisateurs ayant installé l'application à une date donnée et ayant finalement acheté leur premier abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'installations à une date sélectionnée (identique pour tous les produits, car aucun produit n'est choisi au moment de l'installation). - **Y** = nombre de ces utilisateurs ayant finalement acheté leur premier abonnement (avec ou sans essai). **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 installations. - Au 8 janvier, 20 de ces utilisateurs s'étaient abonnés. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires du groupe du 1er janvier avaient souscrit un abonnement. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs ayant installé l'application le 1er janvier ont finalement converti vers un abonnement payant, jusqu'au moment présent. </details> ### Installation -> Essai \{#install---trial\} Cette métrique indique le pourcentage d'utilisateurs ayant installé l'application à une date donnée et ayant finalement démarré un essai. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'installations à une date sélectionnée (identique pour tous les produits, car aucun produit n'est choisi au moment de l'installation). - **Y** = nombre de ces utilisateurs ayant activé un essai, à n'importe quel moment. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 installations. - Au 8 janvier, 20 de ces utilisateurs avaient démarré un essai. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires du groupe du 1er janvier avaient démarré un essai. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs ayant installé l'application le 1er janvier ont finalement démarré un essai, jusqu'au moment présent. </details> ### Vue paywall -> Essai \{#paywall-view---trial\} Cette métrique mesure combien d'utilisateurs ont démarré l'essai après avoir vu un paywall. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'utilisateurs ayant vu un paywall à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant démarré l'essai à n'importe quel moment ultérieur. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 vues de paywall. - Au 8 janvier, 20 de ces utilisateurs avaient démarré l'essai. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires avaient démarré l'essai. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela montre que 50 % des utilisateurs ayant vu un paywall le 1er janvier ont démarré l'essai, jusqu'au moment présent. </details> ### Vue paywall -> Payant \{#paywall-view---paid\} Cette métrique mesure combien d'utilisateurs ont effectué un achat après avoir vu un paywall. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'utilisateurs ayant vu un paywall à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant effectué un achat à n'importe quel moment ultérieur. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 vues de paywall. - Au 8 janvier, 20 de ces utilisateurs avaient effectué un achat. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires avaient effectué un achat. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela montre que 50 % des utilisateurs ayant vu un paywall le 1er janvier ont effectué un achat, jusqu'au moment présent. </details> ### Essai -> Payant \{#trial---paid\} Cette métrique indique le pourcentage d'utilisateurs ayant démarré un essai à une date donnée et ayant ensuite acheté leur premier abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'essais démarrés à une date sélectionnée. - **Y** = nombre de ces utilisateurs ayant finalement souscrit un abonnement après leur essai. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, 100 essais ont été démarrés. - Au 8 janvier, 20 de ces utilisateurs s'étaient abonnés. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires du groupe d'essai du 1er janvier s'étaient abonnés. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs ayant démarré un essai le 1er janvier ont finalement converti vers un abonnement payant, jusqu'au moment présent. </details> ### Payant -> 2e période \{#paid---2nd-period\} Cette métrique indique le pourcentage d'utilisateurs ayant renouvelé leur abonnement après le premier paiement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre de premiers abonnements à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant renouvelé pour une deuxième période, à n'importe quel moment ultérieur (généralement après un cycle d'abonnement ; inclut les renouvellements en délai de grâce). - **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 premiers abonnements. - Au 8 janvier, 20 d'entre eux avaient renouvelé. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires de ce groupe avaient renouvelé. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela montre que 50 % des utilisateurs ayant effectué leur premier paiement d'abonnement le 1er janvier ont renouvelé pour une deuxième période, jusqu'au moment présent. </details> ### 2e période -> 3e période \{#2nd-period---3rd-period\} Cette métrique mesure combien d'utilisateurs ont renouvelé à nouveau après leur deuxième période d'abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'abonnements en deuxième période à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant renouvelé pour une troisième période, à n'importe quel moment ultérieur (généralement après un cycle de facturation supplémentaire ; inclut les renouvellements en délai de grâce). **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 abonnements en deuxième période. - Au 8 janvier, 20 de ces utilisateurs avaient renouvelé. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires avaient renouvelé. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela montre que 50 % des utilisateurs entrés dans leur deuxième période d'abonnement le 1er janvier ont renouvelé pour une troisième, jusqu'au moment présent. </details> ### 3e période -> 4e période \{#3rd-period---4th-period\} Cette métrique indique le pourcentage d'utilisateurs ayant renouvelé après leur troisième période d'abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'abonnements en troisième période à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant renouvelé pour une quatrième période, à n'importe quel moment ultérieur (généralement après un cycle de facturation ; inclut les renouvellements en délai de grâce). **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 abonnements en troisième période. - Au 8 janvier, 20 utilisateurs avaient renouvelé. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires avaient renouvelé. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs entrés dans leur troisième période d'abonnement le 1er janvier ont renouvelé pour une quatrième, jusqu'au moment présent. </details> ### 4e période -> 5e période \{#4th-period---5th-period\} Cette métrique indique le pourcentage d'utilisateurs ayant renouvelé après leur quatrième période d'abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre d'abonnements en quatrième période à une date sélectionnée. - **Y** = nombre d'utilisateurs ayant renouvelé pour une cinquième période, à n'importe quel moment ultérieur (généralement après un cycle de facturation ; inclut les renouvellements en délai de grâce). **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 abonnements en quatrième période. - Au 8 janvier, 20 utilisateurs avaient renouvelé. - Le 8 janvier, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er février, 30 utilisateurs supplémentaires avaient renouvelé. - Le 1er février, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs entrés dans leur quatrième période d'abonnement le 1er janvier ont renouvelé pour une cinquième, jusqu'au moment présent. </details> ### 6 mois + \{#6-months-\} Cette métrique indique le pourcentage d'utilisateurs restés abonnés plus de 6 mois à partir de leur premier abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre de premiers abonnements à une date sélectionnée. - **Y** = nombre de ces utilisateurs ayant renouvelé au moins une fois après 6 mois à partir de la date d'abonnement initiale. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, il y a eu 100 premiers abonnements. - Durant la première semaine de juillet, 20 d'entre eux avaient renouvelé (ex. : lors de leur 25e renouvellement hebdomadaire). - Le 8 juillet, la conversion pour le 1er janvier = (20 / 100) × 100 % = 20 % - Au 1er août, 30 autres avaient renouvelé après 6 mois. - Le 1er août, la conversion pour le 1er janvier = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs abonnés le 1er janvier sont restés abonnés au-delà de 6 mois au 1er août. </details> ### 1 an + \{#1-year-\} Cette métrique indique le pourcentage d'utilisateurs restés abonnés plus de 12 mois à partir de leur premier abonnement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - **X** = nombre de premiers abonnements à une date sélectionnée. - **Y** = nombre de ces utilisateurs ayant renouvelé au moins une fois après 12 mois à partir de la date d'abonnement initiale. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier 2021, il y a eu 100 premiers abonnements. - Durant la première semaine de janvier 2022, 20 avaient renouvelé. - Le 8 janvier 2022, la conversion = (20 / 100) × 100 % = 20 % - Au 1er février 2022, 30 autres avaient renouvelé après 12 mois. - Le 1er février 2022, la conversion = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs abonnés le 1er janvier 2021 sont restés actifs plus d'un an. </details> ### 2 ans + \{#2-years-\} Cette métrique indique le pourcentage d'utilisateurs restés abonnés plus de 24 mois à partir de leur date de premier paiement. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - X = nombre de premiers abonnements à une date sélectionnée. - Y = nombre de ces utilisateurs ayant renouvelé au moins une fois après 24 mois à partir de la date d'abonnement initiale. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier 2020, il y a eu 100 premiers abonnements. - Durant la première semaine de janvier 2022, 20 d'entre eux avaient renouvelé. - Le 8 janvier 2022, la conversion = (20 / 100) × 100 % = 20 % - Au 1er février 2022, 30 autres avaient renouvelé après 2 ans. - Le 1er février 2022, la conversion = ((20 + 30) / 100) × 100 % = 50 % Cela signifie que 50 % des utilisateurs abonnés le 1er janvier 2020 étaient encore actifs après 2 ans, au 1er février 2022. </details> ### Délai de grâce -> Payant \{#grace-period---paid\} Cette métrique indique le pourcentage d'utilisateurs entrés dans un [délai de grâce d'abonnement](grace-period) ayant résolu le problème *avant* la fin du délai de grâce. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - X = nombre d'abonnés entrés dans le délai de grâce. - Y = nombre de ces utilisateurs ayant renouvelé l'abonnement avant la fin du délai de grâce. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier 2025, l'abonnement de 100 personnes n'a pas pu être renouvelé automatiquement. Elles sont entrées dans un délai de grâce de 16 jours, devant se terminer le 17 janvier. - 50 personnes ont mis à jour leurs informations de paiement entre le 1er et le 17 janvier, et leur abonnement a été renouvelé avec succès. - Le 17 janvier 2025, la conversion = (50 / 100) × 100 % = 50 % </details> ### Problème de facturation -> Payant \{#billing-issue---paid\} Cette métrique indique le pourcentage d'utilisateurs ayant rencontré un [problème de facturation](/billing-issue) et ayant repris leurs paiements avant la fin du cycle de facturation. <details> <summary>Comment ça fonctionne</summary> **Définitions** : - X = nombre d'abonnés ayant rencontré un problème de facturation. - Y = nombre de ces utilisateurs ayant renouvelé leur abonnement entre le problème de facturation et la fin du cycle de facturation. **Formule** : Conversion = (Y / X) × 100 % **Exemple** : - Le 1er janvier, 100 abonnés ont rencontré un problème de facturation lorsque leur abonnement n'a pas pu être renouvelé automatiquement. - Remarque : si un délai de grâce est activé, l'état de problème de facturation ne commence qu'après la fin du délai de grâce. Dans cet exemple, on suppose que le délai de grâce s'est terminé le 1er janvier. - Au 8 janvier, 10 de ces utilisateurs avaient résolu le problème de paiement et renouvelé. - Le 8 janvier, la conversion pour le 1er janvier = (10 / 100) × 100 % = 10 % - Au 31 janvier (fin du cycle de facturation), 10 utilisateurs supplémentaires avaient renouvelé. - Le 31 janvier, la conversion pour le 1er janvier = ((10 + 10) / 100) × 100 % = 20 % Cela montre que 20 % des utilisateurs entrés dans un état de problème de facturation le 1er janvier ont résolu le problème et renouvelé avant la fin de leur cycle de facturation. </details> ## Regroupements et plages de dates \{#grouping-and-time-ranges\} L'objet d'analyse lorsque la conversion est sélectionnée est le graphique. Il montre comment le pourcentage de conversion évolue dans le temps. Utilisez le sélecteur de dates pour choisir des options rapides pour la période. Le graphique contient généralement plusieurs courbes. Jusqu'à cinq d'entre elles sont sélectionnées par défaut dans la liste de regroupement, et vous pouvez modifier la sélection en cochant les cases dans la zone à droite du graphique. Lorsque vous ouvrez la page pour la première fois, la durée du produit est sélectionnée comme regroupement par défaut. Vos paramètres sont ensuite enregistrés en cache et, la prochaine fois, vous verrez le groupe que vous avez sélectionné récemment. Les regroupements disponibles sont les suivants : - Produit - Pays - Store - Paywall - Durée - Attribution marketing Si la plage de dates sélectionnée est insuffisante pour afficher des résultats, une notification peut apparaître, proposant une date pertinente et une option pour ajuster automatiquement la plage de dates en un seul clic. ## Vue tableau, filtres et export CSV \{#table-view-filters-and-csv-export\} La comparaison des courbes offre une image claire ; pour aller plus loin, utilisez le tableau situé sous le graphique. Le tableau est synchronisé avec le graphique : en survolant une colonne, vous voyez la fenêtre contextuelle associée sur les courbes. Le regroupement mentionné ci-dessus modifie à la fois les graphiques et le tableau. Appliquez un filtre rapide par produit ou utilisez d'autres filtres avancés, notamment Produit, Pays, Store, Durée, Attribution. Nous savons qu'il est important de pouvoir travailler avec les données comme vous le souhaitez. C'est pourquoi, à droite du panneau de contrôle, un bouton permet d'exporter les données de l'entonnoir au format CSV. Vous pouvez ensuite l'ouvrir dans Excel ou Google Sheets, ou l'importer dans votre propre système d'analyse pour continuer l'analyse et les prévisions dans l'environnement que vous préférez. :::important Informez Adapty si votre application est inscrite à un programme de commission réduite. Pour garantir des calculs corrects, indiquez votre statut dans le [Programme Small Business](app-store-small-business-program) et le [Programme de frais de service réduits](google-reduced-service-fee) dans vos [paramètres d'application](general). ::: --- # File: reports --- --- title: "Rapports" description: "Générez des rapports d'abonnement détaillés dans Adapty pour analyser les revenus de l'application et le comportement des utilisateurs." --- Recevez des informations pertinentes et actualisées directement dans votre boîte mail : revenus, taux de désabonnement, abonnés actifs, essais actifs, et bien plus encore – les mêmes métriques que celles disponibles dans [Charts](charts). Ces rapports peuvent être envoyés quotidiennement, hebdomadairement ou mensuellement, et présentent l'évolution en comparant la période la plus récente à la précédente. Les données envoyées dans les rapports sont basées sur ce que vous avez configuré sur votre page [**Overview**](https://app.adapty.io/overview), à savoir les métriques, leur ordre, le fuseau horaire de reporting et le type de revenus. Vous avez la possibilité de choisir le niveau de détail souhaité pour vos rapports : récapitulatif ou par application. Un rapport récapitulatif est un e-mail unique contenant des informations agrégées sur toutes vos applications (ou le sous-ensemble que vous avez sélectionné). Un rapport par application, en revanche, ne contiendra que les données d'une seule application choisie. Nous recommandons d'activer les rapports récapitulatifs pour toutes les applications et les rapports par application pour celles récemment lancées ou à haute priorité, ainsi que celles dont vous êtes personnellement responsable. Quel que soit le niveau de détail choisi, les rapports par e-mail sont livrés dans votre boîte mail à 9h dans votre fuseau horaire local : les rapports quotidiens arrivent chaque jour, les rapports hebdomadaires arrivent le lundi, et les rapports mensuels arrivent le premier jour du mois. Chaque rapport inclut les données actuelles ainsi que des comparaisons avec la période précédente (par exemple, pour le rapport quotidien du jour, il compare les données d'hier et d'avant-hier ; pour le rapport hebdomadaire du jour, il compare les données de la semaine dernière et de celle d'avant, etc.). Soyez assuré que, quels que soient les rapports sélectionnés, vous recevrez les informations les plus récentes et les plus précises directement dans votre boîte mail. ## Activer les rapports \{#enable-reports\} 1. Ouvrez la section [**Account**](https://app.adapty.io/account) dans le menu supérieur d'Adapty. 2. Dans la section **Email reports**, choisissez les types de rapports que vous souhaitez recevoir – quotidien, hebdomadaire et/ou mensuel. 2. Personnalisez chaque type de rapport en sélectionnant les applications concernées. Pour ce faire, cliquez sur le bouton **Edit**. 3. Dans la fenêtre du rapport, choisissez les applications à inclure. 4. Enfin, cliquez sur le bouton **Save changes** pour appliquer vos sélections. ## Définir votre fuseau horaire \{#set-your-time-zone\} 1. Ouvrez la section [**Overview**](https://app.adapty.io/overview) dans le menu principal d'Adapty. 2. Cliquez sur le bouton **Edit** et choisissez votre fuseau horaire. 3. Cliquez sur le bouton **Done** pour enregistrer. --- # File: discrepancies-and-troubleshooting --- --- title: "Résoudre les divergences de données" description: "Identifier les causes des divergences de données" --- Les utilisateurs d'Adapty peuvent rencontrer des **divergences** lorsqu'ils comparent des ensembles de données similaires provenant de sources différentes. Cela peut notamment se produire lorsque vous comparez : * des graphiques Adapty aux rapports des stores * des graphiques Adapty à des graphiques tiers * différents graphiques au sein d'Adapty ## Algorithme de dépannage \{#troubleshooting-algorithm\} La plupart des divergences entre Adapty et d'autres plateformes sont attendues et normales. Elles surviennent parce que **des sources différentes traitent les mêmes données différemment**. Parfois, elles indiquent un **problème dans votre configuration Adapty**. Si vous pensez que vos données varient d'une plateforme à l'autre, la meilleure démarche est d'[exporter les données brutes](export-analytics-api-requests) et de **comparer les fichiers**. * Même les stores peuvent rencontrer des problèmes liés au traitement et à la présentation des données. Accédez aux **données de transaction brutes** des stores pour une comparaison plus précise. * Lorsque vous comparez Adapty à une autre plateforme d'analytics, utilisez les rapports de transactions des stores comme source de vérité et base de comparaison. * Il est plus facile d'identifier les incohérences avec un jeu de données limité. Comparez de petits volumes de données — concentrez-vous sur un produit spécifique et une seule journée. * Déterminez si votre divergence provient d'une différence de **tarification** ou de **nombre d'événements**. Les problèmes de tarification peuvent être résolus par une [mise à jour du produit](#product-pricing). Les problèmes d'événements peuvent indiquer des [problèmes côté serveur](#issues-with-server-notifications-and-rtdn). * Consultez le [flux d'événements](event-feed) pour surveiller les événements entrants — vous pourrez y remarquer un comportement inattendu. Après avoir identifié où les données divergent, vous pouvez examiner les causes courantes suivantes : ## Problèmes avec les notifications serveur et RTDN \{#issues-with-server-notifications-and-rtdn\} Adapty ne reçoit pas les données d'événements nécessaires si vous n'avez pas correctement configuré les connexions aux stores. Cela affecte particulièrement les événements qui surviennent sans intervention directe de l'utilisateur — renouvellements d'abonnement, problèmes de facturation, etc. Effectuez la configuration serveur-à-serveur dès que possible ([App Store](enable-app-store-server-notifications) | [Play Store](enable-real-time-developer-notifications-rtdn)) et [attendez](#data-delays) que les stores établissent la connexion. Vous pouvez [importer manuellement](importing-historical-data-to-adapty) les données App Store Connect manquantes dans Adapty. ## Données manquantes \{#missing-data\} ### Utilisateurs avec des versions d'application obsolètes \{#users-with-out-of-date-app-versions\} Si certains de vos utilisateurs utilisent une version plus ancienne de votre application sans le SDK Adapty, Adapty ne reçoit pas leurs données. Les chiffres d'Adapty et des autres sources divergeront donc. ### Problèmes d'intégration \{#integration-issues\} Certaines intégrations Adapty (par exemple, Adjust ou AppsFlyer) nécessitent du code applicatif supplémentaire pour fonctionner. Si vous configurez le tableau de bord Adapty sans mettre à jour votre application, les données nécessaires n'apparaîtront pas dans Adapty. ### Données historiques manquantes \{#missing-historical-data\} Adapty n'a pas accès aux données historiques de votre application, sauf si vous les [importez manuellement](importing-historical-data-to-adapty). Si la [plage de dates](controls-filters-grouping-compare-proceeds#set-the-date-range) d'un graphique commence avant votre intégration d'Adapty et que vous n'avez pas importé les données historiques, ses valeurs différeront des autres sources. ## Délais de données \{#data-delays\} Adapty vise à fournir une analyse quasi en temps réel de l'économie de votre application. Les limitations et exceptions suivantes s'appliquent : * Lors de votre première intégration d'Adapty, les données peuvent ne pas apparaître immédiatement. * Lors de l'activation d'une intégration avec une plateforme tierce, il peut y avoir un délai avant que les données soient entièrement synchronisées. * Une fois qu'Adapty reçoit les données du store, il faut encore **15 à 30 minutes** pour qu'elles soient traitées et affichées sur la page Analytics. * Les échanges de données entre Adapty et des tiers ne sont **pas toujours instantanés** en raison du nombre de variables en jeu. * Les calculs de certaines métriques avancées (comme les [prédictions de cohorte](predicted-ltv-and-revenue)) nécessitent une certaine quantité de données. Adapty n'effectue ces calculs que lorsqu'il dispose de suffisamment de données. ## Heure et calendrier \{#time-and-calendar\} #### Dates et fuseaux horaires \{#dates-and-timezones\} L'une des raisons les plus courantes des divergences de données perçues est une différence de paramètres de fuseau horaire. Adapty comptabilise les jours selon le fuseau horaire `UTC`. Si une autre plateforme utilise un fuseau horaire différent, les calculs divergeront. La différence diminuera à mesure que vous augmentez l'échelle. Vous pouvez [modifier le paramètre de fuseau horaire](general#3-reporting-timezone) pour chaque application. #### Le calendrier fiscal Apple \{#the-apple-fiscal-calendar\} Apple utilise son propre [calendrier comptable](https://adapty.io/apple-fiscal-calendar/) pour déterminer les périodes de vente et les dates de paiement. Chaque « mois » du calendrier est composé de **4 ou 5 semaines**, et **peut inclure des jours des mois calendaires voisins**. Les paiements sont généralement émis 30 à 45 jours après la fin de la période de vente. Par exemple, la période de vente « janvier 2026 » commence le 28 décembre 2025 — 4 jours avant le début du mois calendaire. La date de paiement estimée pour cette période est le 5 mars. Ne comparez pas les données des rapports de paiement Apple avec les mois calendaires. Sélectionnez plutôt une [plage de dates personnalisée](controls-filters-grouping-compare-proceeds#set-the-date-range) correspondant à la période de vente concernée. #### Dates de transaction \{#transaction-dates\} Certains services (par exemple, AppsFlyer) peuvent appliquer des règles de [cohorte](analytics-cohorts) lors de l'affichage des transactions, et les attribuer à la date d'installation de l'application plutôt qu'à la date à laquelle la transaction elle-même a eu lieu. ## Calcul des revenus \{#revenue-calculation\} ### Frais et taxes \{#fees-and-taxes\} Selon le [paramètre](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue), les graphiques Adapty peuvent afficher vos **revenus bruts**, vos **revenus après commission du store** ou vos **revenus après commission du store et taxes**. Certains stores et plateformes tierces peuvent ne pas être en mesure d'afficher les revenus bruts, ou déduire automatiquement les taxes. Si vous constatez une divergence entre deux graphiques de revenus différents, assurez-vous que la comparaison est valide. ### Annulations et remboursements \{#cancellations-and-refunds\} Les différentes plateformes affichent les données de remboursement différemment. Adapty traite les remboursements comme des revenus négatifs. Si un utilisateur s'abonne et demande un remboursement le lendemain, les deux événements seront reflétés dans les graphiques Adapty — chacun à sa propre date. D'autres plateformes peuvent soustraire la valeur du remboursement de la transaction d'origine. ## Achats sandbox \{#sandbox-purchases\} Le [flux d'événements](event-feed) affiche les achats effectués par des comptes sandbox. Les graphiques d'analytics ne le font pas. Cependant, si vos données d'import historique contiennent des achats sandbox, Adapty ne pourra pas les distinguer, et ses graphiques refléteront les achats sandbox historiques. ## Installations et téléchargements \{#installs-and-downloads\} Les stores (en particulier l'Apple App Store) peuvent suivre directement les téléchargements des utilisateurs. Leurs statistiques peuvent inclure les cas où l'application a été installée, mais jamais lancée. Adapty ne peut enregistrer une installation que lorsqu'un utilisateur lance l'application, quelle que soit votre [définition des installations](general#4-installs-definition-for-analytics). ## Pays et store \{#country-and-store\} Pour garantir des rapports précis, Adapty [peut déduire](controls-filters-grouping-compare-proceeds#filter-and-group-data) le pays de l'utilisateur à partir de son adresse IP. Les stores attribuent toujours les téléchargements et les achats à un app store spécifique. Si vous avez besoin de distinguer clairement les deux, vous pouvez [créer un nouveau segment d'utilisateurs](segments) avec l'attribut `Country by store account`, et [filtrer les analytics par segment](controls-filters-grouping-compare-proceeds#filter-and-group-data). ## Tarification des produits \{#product-pricing\} Si une tarification incorrecte d'un produit provoque une divergence de revenus, changer le prix ne corrige pas les transactions passées. Pour modifier le prix des transactions existantes, vous devez les remplacer de force en important des données correctes. Lorsqu'un utilisateur restaure un ancien achat après un changement de prix, Apple peut signaler incorrectement la valeur de l'achat. Vous devez importer les données historiques pour qu'Adapty reflète la valeur correcte. ## Conflits d'attribution \{#attribution-conflicts\} Adapty ne peut utiliser [qu'une seule source d'attribution](attribution-integration#prevent-data-issues) par transaction. Vous ne pouvez pas remplacer ces données ultérieurement. Si votre configuration inclut plusieurs fournisseurs d'attribution qui ne sont pas d'accord entre eux, la même transaction sur deux plateformes différentes peut sembler avoir deux sources de trafic différentes. ## Différences de terminologie \{#differences-in-terminology\} Différentes plateformes peuvent avoir des noms différents pour le même concept. Les métriques liées aux [revenus](#fees-and-taxes) varient d'une plateforme à l'autre : | Adapty | App Store Connect | Google Play Console | |--------|-------------------|----------------------| | **Revenus bruts** | Sales | Gross Revenue | | **Revenus après commission du store** | N/A | N/A | | **Revenus après commission du store et taxes** | Proceeds | Earnings | | **ARPPU** | Proceeds per paying user | ARPPU | D'autres métriques peuvent également différer dans leur définition : - **Abonnements** : - Adapty ne comptabilise pas les nouveaux essais comme des abonnements. Un [nouvel abonnement](reactivated-subscriptions) commence toujours par une transaction financière. - D'autres plateformes, comme Google Play Console, peuvent **comptabiliser chaque essai comme un nouvel abonnement**, même avant que le premier paiement ait été effectué. - **Rétention** : - Adapty mesure la rétention sur la base du nombre de renouvellements d'abonnements. - App Store Connect considère qu'un utilisateur est retenu s'il ouvre l'application le jour spécifié. Un utilisateur sans abonnement sera comptabilisé, mais l'utilisateur abonné qui n'a pas ouvert l'application ce jour-là ne le sera pas. - La métrique « Retained Installers » de Google Play Console mesure la rétention en fonction du nombre de jours pendant lesquels l'application reste installée sur l'appareil de l'utilisateur. Les utilisateurs qui n'ouvrent pas l'application sont pris en compte dans cette métrique. ## Métrique Nouveaux abonnements vs l'événement `subscription_started` \{#new-subscriptions-metric-vs-the-subscription_started-event\} La métrique [Nouveaux abonnements](reactivated-subscriptions) et l'[événement d'intégration](events) `subscription_started` comptabilisent des choses différentes, leurs totaux ne correspondent donc pas. La métrique comptabilise à la fois les premiers achats effectués sans essai et les conversions d'essai en abonnement payant. L'événement `subscription_started` ne se déclenche que pour les premiers achats effectués sans essai — lorsqu'un essai est converti en abonnement payant, Adapty envoie `trial_converted` à la place. En conséquence, le nombre de Nouveaux abonnements est supérieur au nombre d'événements `subscription_started` dès lors que votre application comporte des conversions d'essai. --- # File: push-notifications --- --- title: "Recevoir des notifications push pour les nouveaux événements" description: "Recevoir des notifications push pour les nouveaux événements" --- Les notifications push dans l'application mobile Adapty pour [iOS](https://apps.apple.com/us/app/adapty/id6739359219) et [Android](https://play.google.com/store/apps/details?id=io.adapty.dashboard) vous permettent de rester informé en temps réel de ce qui se passe avec vos applications. Que vous suiviez de nouveaux essais, des renouvellements d'abonnements ou des installations, vous recevrez des mises à jour instantanées sans avoir à consulter le tableau de bord. Vous pouvez définir des paramètres de notification par défaut qui s'appliquent à toutes vos applications, puis les ajuster pour des applications spécifiques si vous avez besoin de plus de contrôle. C'est particulièrement utile lorsque vous lancez une nouvelle application et souhaitez surveiller de près l'activité initiale. Le nombre total de notifications pour l'ensemble de vos applications est limité à 1 000/jour. ## Configurer les notifications push \{#configure-push-notifications\} Pour configurer les notifications push dans l'application mobile Adapty : 1. Ouvrez l'application Adapty. 2. Allez dans **Settings → Notifications**. 3. Appuyez sur **Enable notifications** pour autoriser l'application à vous envoyer des notifications. 4. Choisissez d'utiliser les paramètres par défaut ou de configurer les notifications par application. Notez que les paramètres individuels par application remplacent les paramètres par défaut. 5. Sélectionnez les événements pour lesquels vous souhaitez recevoir des notifications. ## Événements pris en charge \{#supported-events\} Vous pouvez recevoir des notifications push pour les types d'événements suivants : * Niveau d'accès mis à jour * Renouvellement automatique désactivé * Renouvellement automatique activé * Problème de facturation détecté * Délai de grâce entamé * Achat unique * Achat unique remboursé * Abonnement annulé * Abonnement différé * Premier achat d'abonnement * Abonnement mis en pause * Abonnement remboursé * Abonnement renouvelé * Essai annulé * Essai converti * Essai démarré --- # File: predicted-ltv-and-revenue --- --- title: "Prédictions dans les cohortes" description: "Utilisez les analyses prédictives d'Adapty pour prévoir la LTV et les revenus." --- Les prédictions Adapty sont conçues pour vous aider à répondre aux questions suivantes : 1. Quelle est la valeur vie (LTV) prédite de vos cohortes d'utilisateurs ? 2. Quelles cohortes sont susceptibles de générer les revenus les plus élevés à l'avenir ? 3. Combien pouvez-vous investir en fonction du retour sur investissement prédit ? Avec les prédictions Adapty, vous pouvez prendre des décisions basées sur les données concernant les revenus et la croissance. Le modèle de prédiction d'Adapty estime le potentiel de revenus à long terme des cohortes d'utilisateurs de votre application. Pour chaque cohorte, il projette comment les revenus, le nombre d'abonnés payants et la LTV moyenne évolueront dans le temps. Cela vous aide à prendre des décisions éclairées sur l'acquisition d'utilisateurs, les stratégies marketing et le développement produit. Adapty propose une valeur vie (LTV) prédite et des revenus prédits pour les cohortes d'abonnés payants. Les prédictions sont affichées sur la page d'analyse des cohortes pour 3, 6, 9, 12, 18 et 24 mois après la création de la cohorte. Pour les applications avec très peu d'historique, le modèle se rabat sur des moyennes inter-applications, de sorte que les prédictions pour les applications plus récentes peuvent ne pas refléter pleinement leur comportement utilisateur spécifique. ## Fonctionnement du modèle \{#how-the-model-works\} Le modèle de prédiction d'Adapty utilise les tendances de rétention issues des données historiques de cohortes pour projeter les revenus futurs et la LTV. Pour chaque combinaison d'application et de type d'abonnement, le modèle mesure comment les abonnés payants et les revenus totaux évoluent d'une période de renouvellement à l'autre. Il calcule deux taux de rétention — un pour les abonnés, un pour les revenus — en se basant sur les cohortes passées de l'application. Ces taux sont ensuite appliqués aux nouvelles cohortes pour projeter leur évolution sur 3, 6, 9, 12, 18 et 24 mois après la création de la cohorte. Les données utilisées sont entièrement anonymisées. Le modèle produit deux valeurs pour chaque cohorte : - **Revenus prédits** : le revenu total qu'une cohorte est censée générer dans l'horizon sélectionné. - **LTV prédite** : les revenus prédits divisés par le nombre prédit d'abonnés payants dans la cohorte. ### Pondérations spécifiques à l'application et inter-applications \{#app-specific-and-cross-app-weights\} Par défaut, les prédictions pour une cohorte utilisent des pondérations de rétention apprises à partir des cohortes historiques de cette application, reflétant le comportement spécifique de ses utilisateurs. Lorsqu'une application ne dispose pas de suffisamment d'historique pour un horizon de prédiction particulier, Adapty se rabat sur des pondérations de rétention moyennées sur l'ensemble des applications du même type d'abonnement. Par exemple, une projection à 12 mois pour une application qui n'a que six mois d'existence utilise le repli inter-applications. Ce repli est appliqué indépendamment par horizon, de sorte que la même cohorte peut utiliser les pondérations propres à l'application pour la prédiction à 3 mois et les pondérations inter-applications pour la prédiction à 12 mois. ### Disponibilité et mises à jour \{#availability-and-updates\} Les prédictions deviennent disponibles après qu'une cohorte a terminé sa première période de renouvellement — généralement une semaine après la création pour les abonnements hebdomadaires et environ quatre semaines pour les abonnements mensuels. Ensuite, les prédictions sont mises à jour quotidiennement en utilisant les dernières données transactionnelles, afin de rester en phase avec le comportement de la cohorte. ### Limitations \{#limitations\} - **Qualité des données** : un comportement de cohorte inhabituel ou des cohortes avec très peu d'abonnés payants réduisent la précision. Les cohortes de moins de 30 abonnés payants sont exclues des données d'entraînement du modèle. - **Nouvelles applications** : les applications sans historique suffisant utilisent les pondérations de repli inter-applications, qui peuvent ne pas refléter le comportement spécifique de l'application. - **Âge de la cohorte** : les prédictions pour un horizon donné sont masquées une fois que la cohorte dépasse cet horizon. Par exemple, les prédictions à 3 mois cessent d'apparaître après trois mois, et aucune prédiction n'est affichée pour les cohortes de plus de 24 mois. ## Dans le tableau de bord \{#in-the-dashboard\} Pour voir les prédictions, accédez à la page d'analyse des cohortes dans votre Adapty Dashboard. Pour plus de détails sur les cohortes, consultez [Analyse des cohortes](analytics-cohorts). <img src="/assets/shared/img/4d808b4-Export-1691486610612.gif" alt="Page d'analyse des cohortes affichant les colonnes Revenus prédits et LTV prédite" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> La colonne **Predicted revenue** affiche le revenu total estimé qu'une cohorte d'abonnés devrait générer pendant la période sélectionnée après la création de la cohorte. Cette valeur est calculée à l'aide du modèle de prédiction d'Adapty, en se basant sur les tendances de rétention des cohortes historiques de l'application. La colonne **Predicted LTV** affiche la valeur vie estimée de chaque utilisateur dans la cohorte sélectionnée. Cette valeur est calculée en divisant les revenus prédits par le nombre prédit d'utilisateurs payants dans la cohorte. ### Sélectionner l'horizon \{#select-the-horizon\} Pour modifier l'horizon de prédiction, sélectionnez une valeur dans le menu déroulant **Predictions**. Les options disponibles sont 3, 6, 9, 12, 18 et 24 mois après la création de la cohorte. ### Filtrer par produit \{#filter-by-product\} Vous pouvez filtrer les revenus prédits et la LTV par produit. Par défaut, les prédictions sont construites à partir de toutes les données d'achat — filtrer par produit montre la contribution de chaque produit. <img src="/assets/shared/img/66a9c61-Export-1691486288948.gif" alt="Analyses de cohortes filtrées par produit" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Quand les prédictions ne sont pas disponibles \{#when-predictions-are-unavailable\} Quand une prédiction ne peut pas être produite pour une cohorte, les colonnes Revenus prédits et LTV prédite affichent des tirets cadratins (—) à la place des valeurs. Cela peut se produire pour plusieurs raisons : - **Délai insuffisant depuis la création de la cohorte** : les prédictions ne deviennent disponibles qu'après que la cohorte a terminé sa première période de renouvellement — environ une semaine pour les abonnements hebdomadaires et environ quatre semaines pour les abonnements mensuels. - **Taille de cohorte trop petite** : trop peu d'abonnés payants pour produire une projection fiable. - **Comportement de cohorte inhabituel** : la cohorte s'écarte significativement des tendances attendues par le modèle. Attendre quelques semaines peut résoudre ce problème à mesure que davantage de données s'accumulent. - **Horizon dépassé** : la cohorte est plus ancienne que l'horizon de prédiction sélectionné. Par exemple, la prédiction à 3 mois est masquée après trois mois, la prédiction à 12 mois après douze mois, et aucune prédiction n'est affichée pour les cohortes de plus de 24 mois. :::warning Lors de l'activation des prédictions, il est important de noter qu'il peut y avoir un délai maximum de 24 heures avant que les données de prédiction pour les Revenus et la LTV ne soient disponibles sur votre Adapty Dashboard. ::: --- # File: predictions-in-ab-tests --- --- title: "Prédictions dans les tests A/B" description: "Découvrez comment les prédictions dans les tests A/B aident à affiner les stratégies de tarification des abonnements." --- Bienvenue dans la documentation d'Adapty sur les analyses prédictives pour notre fonctionnalité de test A/B. Cet outil vous donnera un aperçu des résultats futurs de vos tests A/B en cours et vous aidera à prendre des décisions basées sur les données plus rapidement 🚀 grâce aux prédictions alimentées par l'IA d'Adapty. ### Qu'est-ce que les prédictions de test A/B ? \{#what-are-ab-test-predictions\} Les prédictions de test A/B d'Adapty utilisent des techniques avancées de machine learning (notamment des modèles de gradient boosting) pour anticiper le potentiel de revenus à long terme des paywalls comparés dans un test A/B. Ce modèle prédictif vous permet de sélectionner le paywall le plus efficace en fonction des revenus projetés sur un an, au lieu de vous appuyer uniquement sur les métriques observées pendant l'exécution du test. Cela vous permet de déterminer le gagnant de manière plus fiable et plus rapide, sans avoir à attendre des semaines que les données s'accumulent. ### Comment fonctionne le modèle ? \{#how-does-the-model-work\} Le modèle est entraîné sur un vaste ensemble de données historiques de tests A/B provenant d'une grande variété d'applications dans différentes catégories. Il intègre un large éventail de caractéristiques pour prédire les revenus qu'un paywall est susceptible de générer dans l'année suivant le début de l'expérience. Ces caractéristiques comprennent : - Les transactions des utilisateurs et les taux de conversion sur différentes périodes - La répartition géographique des utilisateurs - L'utilisation de la plateforme (iOS ou Android) - Les taux de désabonnement et de remboursement - Les produits d'abonnement et la durée de leurs périodes (quotidienne, mensuelle, annuelle, etc.) - D'autres données liées aux transactions Le modèle tient également compte des périodes d'essai dans les paywalls, en utilisant les taux de conversion historiques pour prédire les revenus comme si les utilisateurs étaient déjà convertis. Cela garantit une comparaison équitable entre les paywalls avec et sans offres d'essai, car nous prenons également en compte les essais actifs susceptibles de générer des revenus à l'avenir. ### En quoi le P2BB prédit diffère-t-il du P2BB classique ? \{#how-is-predicted-p2bb-different-from-just-the-p2bb\} Nos tests A/B utilisent l'approche bayésienne : nous modélisons essentiellement la distribution des revenus par utilisateur (ou plus précisément « Revenus pour 1 000 utilisateurs »), puis nous calculons la probabilité qu'une distribution soit « vraiment » meilleure que l'autre et non par hasard — c'est ce que nous appelons la Probabilité d'être le meilleur ou P2BB (vous pouvez en savoir plus sur notre approche [ici](maths-behind-it)). Il est important de noter que ce faisant, nous nous appuyons uniquement sur les revenus accumulés pendant la durée d'exécution du test. Ainsi, si vous deviez exécuter un test comparant un abonnement annuel à un abonnement hebdomadaire, vous devriez attendre très longtemps pour vraiment comprendre lequel est le plus performant. Une situation similaire se produit lorsque vous comparez des abonnements avec essai à des abonnements sans essai dans un test A/B — car les essais actifs susceptibles de faire pencher la balance vers un gagnant ne sont jamais pris en compte dans les revenus. C'est là qu'intervient notre modèle prédictif. En s'appuyant sur la distribution actuelle des revenus dans un test A/B et entraîné sur un large jeu de données, il est capable de prédire la version future de la distribution des revenus (c'est-à-dire après 1 an). Ensuite, il produit un P2BB prédit — celui auquel vous aboutiriez si vous exécutiez le test pendant toute une année. Notez que le P2BB prédit peut parfois contredire le P2BB actuel. Dans ce cas, nous mettons en évidence les lignes de variation en jaune, comme ceci : <img src="/assets/shared/img/74577c6-CleanShot_2024-02-15_at_13.08.452x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous considérons cela comme un signal indiquant que vous devriez accumuler davantage de données pour confirmer le gagnant ou approfondir l'analyse du test A/B pour en comprendre la raison. En général, nous recommandons de faire confiance au P2BB prédit plutôt qu'au P2BB actuel, car il prend simplement en compte davantage de données, mais la décision finale vous appartient bien sûr. ### Précision et certitude du modèle \{#model-accuracy-and-certainty\} Le modèle atteint un niveau de précision élevé, avec une erreur absolue moyenne en pourcentage (MAPE) légèrement inférieure à 10 %. Ce niveau de précision permet aux entreprises de se fier en toute confiance aux prédictions du modèle pour prendre des décisions basées sur les données. Pour garantir davantage de stabilité, le modèle utilise un critère de « certitude » basé sur trois facteurs : - Un intervalle de prédiction étroit — le modèle est confiant dans son résultat - Un nombre suffisant d'abonnements et de revenus dans le test - Au moins 2 semaines se sont écoulées depuis le début du test Une prédiction est considérée comme fiable lorsqu'au moins deux de ces trois critères sont remplis. Lorsqu'un nouveau test A/B commence, le modèle fournit une prédiction de revenus par 1 000 utilisateurs sur un an (notre principale métrique de test A/B) pour chaque paywall. Les prédictions ne sont affichées que lorsqu'elles satisfont aux critères de certitude. Si les données sont insuffisantes, le modèle indiquera « données insuffisantes pour la prédiction ». ### Limites et considérations \{#limitations-and-considerations\} Bien que notre modèle prédictif soit un outil puissant, il est important d'en tenir compte ses limites. Les performances du modèle dépendent de la qualité et de la représentativité des données disponibles. Un comportement de cohorte inhabituel ou de nouvelles applications non incluses dans l'ensemble d'entraînement peuvent affecter la précision des prédictions. Néanmoins, les prédictions sont mises à jour quotidiennement pour refléter les dernières données et comportements des utilisateurs. Cela garantit que les informations que vous recevez sont toujours basées sur les données les plus récentes. 🚧 Remarque : Cet outil est un complément, et non un substitut, à votre expertise et à votre compréhension des dynamiques propres à votre application. Utilisez ces prédictions comme guide, en les combinant avec d'autres métriques et vos connaissances du marché, pour prendre des décisions éclairées. --- # File: adapty-ads-manager --- --- title: "Adapty Ads Manager" description: "Obtenez des analyses en temps réel depuis Apple Ads et gérez et optimisez vos campagnes" --- **Adapty Ads Manager** est une plateforme tout-en-un conçue pour vous aider à gérer, optimiser et faire évoluer vos campagnes Apple Ads plus efficacement. Elle connecte les performances de vos Apple Search Ads aux métriques de revenus clés — installations, essais, abonnements et valeur à vie — sans nécessiter de MMP. Grâce à des analyses en temps réel, des prévisions pilotées par l'IA et une automatisation intelligente, Adapty Ads Manager élimine les ajustements manuels d'enchères fastidieux, les tableurs et les approximations, et les remplace par des insights clairs et des outils qui vous permettent d'agir plus vite. Avec Adapty Ads Manager, vous bénéficiez de : - **[Vue d'ensemble](ads-manager-overview)** : Toutes les métriques clés en un coup d'œil — dépenses, revenus, ROAS, CPA et plus encore — chacune avec un graphique de tendance quotidien - **[Agent IA](ads-manager-ai-agent)** : Posez des questions en langage naturel et obtenez des réponses et recommandations sur l'ensemble du funnel - **Données de performance en temps réel** : Pour les campagnes, groupes d'annonces et mots-clés - **Suivi des revenus de bout en bout** : De la recherche → installation → essai → abonnement → LTV - **Prédictions et recommandations IA** : Pour une mise à l'échelle rentable - **Gestion en masse** : Des enchères, budgets, statuts et structures - **[Automatisations basées sur des règles](ads-manager-automations)** : Gérez le cycle de vie complet des mots-clés - **[Market Intelligence](ads-manager-market-intelligence)** : Stratégies de mots-clés concurrentiels dans plus de 50 pays - **[Tests A/B CPP](ads-manager-cpp-ab-tests)** : Comparez les pages produit personnalisées en face à face et trouvez la meilleure <CustomDocCardList ids={['adapty-ads-manager-get-started', 'ads-manager-overview', 'ads-manager-ai-agent', 'adapty-ads-manager-analytics', 'ads-manager-create-campaign', 'ads-manager-create-ad-group', 'ads-manager-manage-keywords', 'ads-manager-automations', 'ads-manager-market-intelligence', 'ads-manager-cpp-ab-tests']} /> ## Pourquoi choisir Adapty Ads Manager ? \{#why-choose-adapty-ads-manager\} Parce que nous vous offrons les **données les plus précises du marché.** Contrairement à la console Apple Ads native ou aux MMP, nos données sont **en temps réel, sans perte et entièrement connectées** aux essais, abonnements et LTV — sans délais ni lacunes d'attribution. Grâce à une implémentation simple et une expérience utilisateur fluide, vous pouvez tout gérer en un seul endroit sans avoir à jongler entre plusieurs outils. ## Démarrer \{#get-started\} Pour commencer avec Adapty Ads Manager, suivez le [guide](adapty-ads-manager-get-started) et vous serez prêt à explorer --- # File: adapty-ads-manager-get-started --- --- title: "Démarrer avec Adapty Ads Manager" description: "Importez vos données historiques depuis Apple Ads et commencez à recevoir des mises à jour en temps réel sur le tableau de bord" --- [Adapty Ads Manager](adapty-ads-manager) est votre plateforme d'optimisation et d'analyse pour Apple Ads. Dans ce guide, vous apprendrez à démarrer avec Adapty Ads Manager en deux étapes : 1. Installez le SDK Adapty et laissez-le suivre vos données d'achat. 2. Connectez Adapty Ads Manager à votre compte Apple Ads pour importer vos données historiques et commencer à suivre les mises à jour en temps réel. :::note Adapty Ads Manager n'utilise pas l'[intégration Apple Ads](apple-search-ads) disponible dans **App settings**. Pour utiliser Adapty Ads Manager, il vous suffit de terminer la configuration décrite dans ce guide. ::: ## 1. Installer le SDK Adapty \{#1-install-the-adapty-sdk\} :::important Adapty Ads Manager est un **produit autonome**. Vous pouvez l'utiliser même si vos paywalls, abonnements ou analyses ne sont pas gérés par Adapty — il n'est pas nécessaire de migrer toute votre stack vers Adapty. Pour obtenir des données de revenus précises, la configuration minimale consiste à installer le SDK Adapty en mode observateur et à activer les notifications serveur de l'App Store dans Adapty. ::: Pour connecter vos données de revenus aux performances de vos campagnes, laissez Adapty suivre vos achats : 1. La première étape dépend de si vous avez déjà implémenté des achats intégrés : - Si vous **avez déjà implémenté des achats intégrés avec Adapty**, vous n'avez rien d'autre à faire à cette étape. - Si vous **avez déjà implémenté des achats intégrés sans Adapty** et ne prévoyez pas de migrer vers Adapty, installez le SDK Adapty pour votre plateforme en mode observateur. À cette étape, vous devez uniquement ajouter le SDK à votre projet, l'activer avec le mode observateur activé et signaler les transactions : - [iOS](implement-observer-mode) - [Android](implement-observer-mode-android) - [React Native](implement-observer-mode-react-native) - [Flutter](implement-observer-mode-flutter) - [Unity](implement-observer-mode-unity) - [Kotlin Multiplatform](implement-observer-mode-kmp) - [Capacitor](implement-observer-mode-capacitor) - Si vous **n'avez pas encore implémenté d'achats intégrés et souhaitez utiliser Adapty**, suivez les étapes du [guide de démarrage rapide](quickstart) pour déléguer la gestion des achats à Adapty. 2. Pour recevoir les mises à jour liées aux revenus directement depuis l'App Store, [activez les notifications serveur de l'App Store dans Adapty](enable-app-store-server-notifications). ## 2. Connecter Apple Ads \{#2-connect-apple-ads\} :::important Vous devez avoir le rôle **Account Admin** dans Apple Ads pour connecter Apple Ads à Adapty. ::: Vous devez maintenant connecter votre compte Adapty Ads Manager à votre compte Apple Ads : 1. Cliquez sur le logo Adapty dans l'en-tête et choisissez **Search Ads**. 2. Cliquez sur **Continue with Apple**. 3. Connectez-vous à votre compte Apple. 4. Sélectionnez le niveau d'accès que vous souhaitez accorder à Adapty Ads Manager : - **Read and Write** : accorde l'accès à tous les groupes de campagnes. - **Limited access** : choisissez des groupes de campagnes spécifiques et attribuez le rôle **Read & Write** pour n'accorder l'accès qu'à ces groupes. 5. Cliquez sur **Grant access**. Adapty commencera alors à synchroniser vos données historiques depuis Apple Ads. Vous pouvez déjà commencer à explorer Adapty Ads Manager, mais l'importation de toutes les données historiques prendra un certain temps. ## Prochaines étapes \{#whats-next\} Une fois vos données de transaction synchronisées avec succès, apprenez comment : - [Gérer vos campagnes, groupes d'annonces et mots-clés](ads-manager) - [Configurer des règles d'automatisation pour ajuster les enchères selon les performances de vos campagnes](ads-manager-automations) --- # File: ads-manager-overview --- --- title: "Vue d'ensemble dans Adapty Ads Manager" description: "Retrouvez toutes vos métriques clés Apple Ads au même endroit, chacune avec un graphique de tendance." --- La page **Overview** regroupe toutes les métriques clés Apple Ads au même endroit, chacune accompagnée d'un graphique de tendance. Par défaut, elle affiche les données de toutes vos applications connectées. Pour n'afficher qu'une seule application, sélectionnez-la dans le menu déroulant des applications dans l'en-tête. Pour y accéder, rendez-vous dans **Overview** dans la barre latérale gauche d'Adapty Ads Manager. :::tip Pour obtenir un résumé de ce qui nécessite votre attention plutôt que de parcourir les métriques, consultez l'[Agent IA](ads-manager-ai-agent). ::: ## Métriques \{#metrics\} Chaque métrique s'affiche sous forme de carte avec un graphique de tendance pour la période sélectionnée. Pour les définitions et formules des métriques, consultez [Métriques dans Adapty Ads Manager](adapty-ads-manager-metrics). ## Configurer les métriques affichées \{#configure-displayed-metrics\} Pour modifier les métriques affichées sur la page **Overview**, cliquez sur **Edit metrics**. Vous pouvez alors : - **Ajouter une métrique** : cliquez sur **Add metric** et cochez les métriques souhaitées. - **Supprimer une métrique** : décochez-la dans le panneau **Add metric**, ou cliquez sur **×** à côté d'elle. ## Contrôles \{#controls\} Utilisez les contrôles en haut de page pour ajuster ce qu'affiche la page **Overview** : - **Date range** : choisissez une période prédéfinie (**Last 7 days**, **Last 30 days**, **Last 90 days**) ou saisissez une plage personnalisée. Tous les graphiques et valeurs récapitulatives se mettent à jour en fonction de la période sélectionnée. - **Chart type** : basculez entre les vues histogramme empilé, courbe et graphique en secteurs. - **Revenue display** : choisissez comment les métriques de revenus sont calculées : - **Gross revenue** : revenu total avant toute déduction. - **Proceeds after store commission** : revenu après déduction de la commission d'Apple. - **Proceeds after store commissions and taxes** : revenu net après déduction de la commission d'Apple et des taxes applicables. --- # File: ads-manager-ai-agent --- --- title: "Agent IA dans Adapty Ads Manager" description: "Posez des questions en langage naturel sur votre compte Apple Ads et obtenez des réponses et recommandations couvrant l'ensemble du funnel." --- L'agent IA est un assistant de chat dans Adapty Ads Manager qui répond à vos questions sur votre compte Apple Ads en langage naturel. Il s'appuie sur l'ensemble de votre funnel — impression, installation, essai, abonnement et revenu — pour raisonner sur le revenu et le ROAS, et pas seulement sur les clics. L'attribution intégrée d'Adapty met ces données de funnel à la disposition de l'agent en quasi temps réel. L'agent est consultatif : il analyse votre compte et recommande des actions, mais ne modifie pas les campagnes, enchères ou budgets à votre place. ## Ce que vous pouvez demander \{#what-you-can-ask\} Interrogez l'agent sur n'importe quelle partie de votre compte Apple Ads. Il peut : - **Vue d'ensemble du compte** : résumer ce qui se passe sur l'ensemble de votre compte et identifier les priorités. - **Objets sous-performants** : repérer les campagnes qui ne rentabilisent pas et les mots-clés sans conversions. - **Budget** : identifier les campagnes qui atteignent leur plafond budgétaire journalier et conseiller s'il faut l'augmenter. - **Décisions d'enchères et de pause** : recommander s'il faut augmenter une enchère ou attendre, et s'il faut mettre une campagne en pause ou la maintenir active. - **Performance géographique** : montrer quels pays sur- ou sous-performent et où réallouer le budget. ## Exemples de questions \{#example-questions\} L'agent fournit les réponses les plus utiles quand vous précisez une métrique, une fenêtre temporelle et la décision que vous évaluez. Par exemple : - Quels mots-clés ont le ROAS le plus élevé, et comment réallouer le budget vers eux ? - Quels mots-clés ont un spend élevé mais aucun essai ni abonnement sur les 30 derniers jours, et lesquels devrais-je mettre en pause ? - Quelles campagnes atteignent leur plafond budgétaire journalier tout en restant rentables, et de combien devrais-je augmenter chacune ? - Comparez mes pays par ROAS et coût par abonnement — où devrais-je déplacer le budget ? - Devrais-je baisser l'enchère sur ce mot-clé, le mettre en pause ou lui laisser plus de temps ? Montre-moi les données du funnel qui justifient ta réponse. - Quels mots-clés génèrent des installations peu coûteuses qui se convertissent rarement en abonnements payants ? ## Ouvrir l'agent IA \{#open-the-ai-agent\} Pour ouvrir l'agent, cliquez sur **Ask AI Agent** dans l'en-tête du compte. Avant de poser une question, sélectionnez une application pour définir le périmètre de l'agent. Saisissez ensuite votre question et envoyez-la. L'agent exécute les tâches en arrière-plan, vous pouvez donc continuer à travailler dans Adapty Ads Manager pendant qu'il prépare sa réponse. Pour changer le modèle qui répond à vos questions, utilisez le sélecteur situé à côté du champ de saisie du message. ## Accéder aux conversations précédentes \{#access-previous-chats\} Le panneau compact n'affiche que votre conversation en cours. Pour consulter des conversations antérieures, cliquez sur le bouton d'agrandissement en haut du panneau pour passer en mode plein écran. Une liste **Chats** s'ouvre sur la gauche, où vous pouvez rechercher des conversations passées ou en démarrer une nouvelle avec **New chat**. ## Limitations \{#limitations\} L'agent IA est consultatif. Il recommande des actions mais ne les applique pas à votre place. Passez en revue ses recommandations, puis appliquez les modifications vous-même [lors de la gestion des campagnes](ads-manager-create-campaign) et des [mots-clés](ads-manager-manage-keywords). --- # File: ads-manager --- --- title: "Suivre et gérer vos campagnes dans Adapty Ads Manager" description: "Obtenez des analyses en temps réel depuis Apple Ads et optimisez vos campagnes" --- :::important Avant de commencer à utiliser l'Ads Manager, assurez-vous d'avoir suivi les étapes de [ce guide](adapty-ads-manager-get-started). ::: Adapty Ads Manager vous permet de faire trois choses essentielles au même endroit : - **Voir ce qui génère vraiment des revenus** – explorez les performances de vos campagnes, groupes d'annonces et mots-clés directement liés aux installations, essais, abonnements et revenus. - **Lancer et restructurer rapidement** – créez et modifiez des campagnes, groupes d'annonces, mots-clés et exclusions sans passer par la console native. - **Automatiser les tâches répétitives** – configurez des règles qui ajustent automatiquement les enchères et les budgets pour atteindre votre CPA/ROAS cible, sans intervention manuelle. <CustomDocCardList /> --- # File: adapty-ads-manager-analytics --- --- title: "Analytics dans Adapty Ads Manager" description: "Consultez les analytics de l'application dans Adapty Ads Manager." --- [Ads Manager](https://app.adapty.io/asa/campaigns) est une section du tableau de bord Adapty Ads Manager qui vous permet de voir toutes les métriques clés en un seul endroit et de les organiser par applications, campagnes, groupes d'annonces, mots-clés et termes de recherche. Vous pouvez personnaliser les métriques affichées et consulter les données de toutes vos campagnes en même temps. ## Vue d'ensemble de la structure \{#structure-overview\} Dans Adapty Ads Manager, vous pouvez évaluer les performances de vos annonces à plusieurs niveaux. ### Campagnes \{#campaigns\} Dans l'onglet **Campaigns**, vous pouvez voir toutes les métriques regroupées par campagnes. Cliquez sur le nom d'une campagne pour accéder à ses détails. ### Applications \{#apps\} Dans l'onglet **Apps**, vous pouvez voir la liste de vos applications. Cliquez sur le nom d'une application pour voir les métriques de campagne associées. ### Groupes d'annonces \{#ad-groups\} Dans l'onglet **Ad groups**, vous pouvez voir toutes les métriques regroupées par groupes d'annonces. Cliquez sur le nom d'un groupe d'annonces pour accéder à ses détails. ### Mots-clés \{#keywords\} Dans l'onglet **Keywords**, vous pouvez voir toutes les métriques regroupées par mots-clés. Cliquez sur un mot-clé pour voir les termes de recherche associés. ### Termes de recherche \{#search-terms\} Dans l'onglet **Search terms**, vous pouvez voir toutes les métriques regroupées par termes de recherche et leurs mots-clés associés. ### Mots-clés à exclure \{#negative-keywords\} Dans l'onglet **Negative keywords**, vous pouvez voir la liste des mots-clés à exclure et leurs métriques. ### Annonces \{#ads\} Dans l'onglet **Ads**, vous pouvez voir la liste des annonces et leurs métriques, afin de savoir quelle configuration d'annonce génère des résultats. ## Métriques \{#metrics\} Les colonnes disponibles sont regroupées en plusieurs grandes catégories : - **General** : Propriétés générales des annonces et campagnes. - **Performance** : Informations sur la façon dont les utilisateurs réagissent à vos annonces. - **Insights** (pour les mots-clés et les termes de recherche uniquement) : Part d'impressions et popularité des recherches. - **Advanced downloads** : Nouveaux téléchargements et re-téléchargements, avec les valeurs Total, View-Through et Tap-Through. - **Conversions** : Métriques liées aux revenus, associées aux annonces et aux campagnes. - **Cohort** : Analytics temporelle des groupes d'utilisateurs. Pour la liste complète des métriques et leur description, consultez l'[article](adapty-ads-manager-metrics). ## Graphiques \{#charts\} Dans chaque onglet, vous pouvez voir des graphiques montrant l'évolution des différentes métriques sur la période sélectionnée. Ajustez la période à l'aide du sélecteur **Date range** en haut à droite. Vous pouvez afficher plusieurs métriques simultanément pour repérer les corrélations et les évolutions dans le temps. Cliquez sur **+** pour ajouter une nouvelle métrique. Cliquez sur **Reset** pour repartir de zéro, ou décochez simplement les métriques pour les masquer. :::tip Dans l'onglet **Keywords**, vous pouvez également [explorer les graphiques au niveau des mots-clés](ads-manager-manage-keywords#explore-keyword-level-charts). ::: ## Personnaliser les métriques affichées \{#customize-which-metrics-to-show\} Dans chaque onglet, vous pouvez personnaliser les colonnes affichées et leur ordre. Vous pouvez également enregistrer des vues pour y revenir rapidement à tout moment. Pour personnaliser les colonnes affichées et leur ordre, cliquez sur **Columns > Edit columns** en haut à droite. Sélectionnez ensuite les colonnes dans la liste et réorganisez-les par glisser-déposer. Cliquez sur **Save** pour appliquer les modifications. Pour enregistrer un préréglage de vue, cliquez à nouveau sur le menu déroulant **Columns**, puis sur l'icône **Save** à côté de **Unsaved**. Saisissez le nom du préréglage et cliquez sur **Save**. Vous pouvez ensuite basculer entre différentes vues via le menu déroulant **Columns**. ## Contrôles \{#controls\} Sur la page **Analytics**, vous disposez de cinq contrôles principaux : 1. **Pinned metrics** : Sélectionnez les métriques à épingler dans la barre au-dessus du tableau. 2. **Date ranges** : En savoir [plus](controls-filters-grouping-compare-proceeds#set-the-date-range). 3. **Filters** : Filtrez par valeurs de métriques ou propriétés de campagne. 4. **Store commission and taxes** : En savoir [plus](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). 5. **Search** : Recherchez par noms de campagnes. --- # File: adapty-ads-manager-metrics --- --- title: "Métriques dans Adapty Ads Manager" description: "Consultez les analytics d'application dans Adapty Ads Manager." --- Adapty Ads Manager fournit des métriques complètes pour mesurer les performances des campagnes et le comportement des utilisateurs. ## Performance \{#performance\} | Métrique | Description | |--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Spend | La somme du coût de chaque clic d'un client sur votre annonce. | | Impressions | Le nombre de fois où votre annonce sponsorisée est apparue dans les résultats de recherche de l'App Store pendant la période de reporting. | | CPM | Le montant moyen que vous payez pour mille impressions d'annonce. CPM moy. = Dépenses / (Impressions / 1 000) Remarque : pour les campagnes de résultats de recherche App Store avec le modèle de tarification CPT, il affiche le CPM effectif. | | Taps | Le nombre de fois où l'annonce a été tapée par les utilisateurs pendant la période de reporting. | | CPT | Le montant moyen que vous payez par tap sur votre annonce. CPT moy. = Dépenses / Taps | | TTR | Le nombre de fois où votre annonce a été tapée par des clients divisé par le total des impressions reçues. TTR = Taps / Impressions × 100 % | | Downloads (Total) | Le nombre total de nouveaux téléchargements et re-téléchargements via tap ou vue à partir d'une annonce pendant la période de reporting. | | Downloads (View-Through) | Le nombre de téléchargements et re-téléchargements d'utilisateurs ayant vu votre annonce dans une fenêtre de 24 heures sans l'avoir tapée. | | Downloads (Tap-Through) | Le nombre total de nouveaux téléchargements et re-téléchargements d'utilisateurs ayant tapé sur votre annonce dans une fenêtre de 30 jours. | | Avg CPA (Total) | Le CPA (coût par acquisition) total moyen est la dépense totale de la campagne divisée par le total des téléchargements résultant d'une vue ou d'un tap sur votre annonce pendant la période de reporting. | | Avg CPA (Tap-Through) | Le CPA (coût par acquisition) via tap moyen est la dépense totale de la campagne divisée par le nombre de téléchargements via tap pendant la période de reporting. | | Download Rate (Total) | Le total des téléchargements résultant d'une vue ou d'un tap sur votre annonce divisé par le nombre total de taps pendant la période de reporting. Formule : (Total Downloads / Taps) × 100 % si Taps > 0, sinon 0 % | | Download Rate (Tap-Through) | Le total des téléchargements résultant de taps sur votre annonce divisé par le nombre total de taps pendant la période de reporting. Formule : (Tap-Through Downloads / Taps) × 100 % si Taps > 0, sinon 0 % | | DPM (Total) | Downloads per Mille (DPM) est le nombre de téléchargements pour mille impressions. Formule : (Total Downloads / Impressions) × 1 000 si Impressions > 0, sinon 0 | ## Conversions \{#conversions\} :::note Revenue, ARPU, ARPPU, ARPAS, ROAS et ROI sont également disponibles comme métriques de cohorte pour l'analyse temporelle de groupes d'utilisateurs. ::: | Métrique | Description | |--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Conversions | Conversions est le nombre total d'événements de conversion pendant la période de reporting. Formule : Essais démarrés + Abonnements démarrés + Achats uniques | | Conversion CR | Conversion CR (taux de conversion) est le pourcentage du total des téléchargements ayant abouti à une conversion. Formule : (Conversions / Total Downloads) × 100 % si Total Downloads > 0, sinon 0 % | | Cost per Conversion | Cost per Conversion est votre dépense totale divisée par le nombre de conversions. Formule : Spend / Conversions si Conversions > 0, sinon 0 | | Revenue | Revenue est le montant total d'argent généré par les achats, renouvellements ou autres conversions monétisées dans votre application pendant la période sélectionnée (avant commission du store). | | ROAS | ROAS (Return on Ad Spend) est le revenu généré par vos annonces divisé par les dépenses publicitaires, exprimé en pourcentage. Formule : (Revenue / Spend) × 100 % si Spend > 0, sinon 0 % | | ROI | ROI (Return on Investment) mesure le bénéfice net par rapport aux dépenses. Formule : ((Revenue − Spend) / Spend) × 100 % si Spend > 0, sinon 0 % | | ARPU | ARPU (Average Revenue per User) est le revenu moyen par utilisateur. Il est calculé comme le revenu total divisé par le nombre d'utilisateurs uniques. 60 000 $ de revenu / 5 000 utilisateurs = 12 $ d'ARPU. Il est utile de comparer cette valeur au coût par installation (CPI) pour comprendre l'efficacité de vos campagnes marketing. | | ARPPU | ARPPU (Average Revenue per Paying User) est le revenu moyen par utilisateur payant. Il est calculé comme le revenu total divisé par le nombre d'utilisateurs payants uniques. 60 000 $ de revenu / 1 000 utilisateurs payants = 60 $ d'ARPPU. Il vous aide à comprendre combien d'argent génère en moyenne un client payant. | | ARPAS | ARPAS est le revenu moyen par abonné actif. Il est calculé comme revenu total / nombre d'abonnés actifs. Par abonnés, nous entendons ceux qui ont activé une période d'essai ou un abonnement. 60 000 $ de revenu / 1 500 abonnés = 40 $ d'ARPAS. | | Installs | Installs est le nombre total d'utilisateurs ayant installé l'application pour la première fois, ainsi que toute réinstallation par des utilisateurs existants. Cela inclut plusieurs installations par le même utilisateur sur des appareils différents. Notez que les téléchargements incomplets ou les installations annulées avant leur fin ne sont pas comptabilisés. | | Installs CR | Installs CR (taux de conversion) est le pourcentage d'utilisateurs parmi le total des téléchargements ayant installé l'application. Formule : (Installs / Total Downloads) × 100 % si Total Downloads > 0, sinon 0 % | | CPI | CPI (Cost per Install) est le coût par installation capturé par Adapty. Formule : Spend / Installs si Installs > 0, sinon 0 | | Trials | Trials est le nombre de nouveaux essais d'abonnement initiés pendant la période de reporting. | | Trial CR | Trial CR (taux de conversion) est le pourcentage du total des téléchargements ayant démarré un essai. Formule : (Trials / Total Downloads) × 100 % si Total Downloads > 0, sinon 0 % | | Cost per Trial | Cost per Trial est votre dépense totale divisée par le nombre de nouveaux démarrages d'essai. Formule : Spend / Trials si Trials > 0, sinon 0 | | Trials converted | Trials converted est le nombre d'essais d'abonnement ayant été convertis avec succès en abonnements payants pendant la période de reporting. | | Trial converted CR | Trial converted CR (taux de conversion) est le pourcentage d'essais d'abonnement convertis en abonnements payants. Formule : (Trials converted / Trials) × 100 % si Trials > 0, sinon 0 % | | Cost per Trial converted | Cost per Trial converted est votre dépense totale divisée par le nombre d'essais convertis sur la même période. Formule : Spend / Trials converted si Trials converted > 0, sinon 0 | | Subscriptions | Subscriptions est le nombre total de nouveaux abonnements souscrits (hors essai) pendant la période de reporting. | | Subscription CR | Subscription CR (taux de conversion) est le pourcentage du total des téléchargements ayant souscrit un abonnement payant (sans essai gratuit). Formule : (Subscriptions / Total Downloads) × 100 % si Total Downloads > 0, sinon 0 % | | Cost per Subscription | Cost per Subscription est votre dépense totale divisée par le nombre de nouveaux abonnements démarrés. Formule : Spend / Subscriptions si Subscriptions > 0, sinon 0 | | Non-subscriptions started | Non-subscriptions started est le nombre total d'achats intégrés uniques non basés sur un abonnement. | | Non-subscription CR | Non-subscription CR (taux de conversion) est le pourcentage du total des téléchargements ayant effectué un achat hors abonnement dans votre application. Formule : (Non-subscriptions started / Total Downloads) × 100 % si Total Downloads > 0, sinon 0 % | | Cost per Non-subscription | Cost per Non-subscription est votre dépense totale divisée par le nombre d'achats hors abonnement. Formule : Spend / Non-subscriptions started si Non-subscriptions started > 0, sinon 0 | ## Téléchargements avancés \{#advanced-downloads\} | Métrique | Description | |--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | New Downloads (Total) | Le nombre total de nouveaux téléchargements via tap ou vue pendant la période de reporting. | | New Downloads (View-Through) | Les nouveaux téléchargements d'utilisateurs ayant vu votre annonce sans la taper et n'ayant pas précédemment téléchargé votre application sont comptabilisés dans une fenêtre de 24 heures. | | New Downloads (Tap-Through) | Les nouveaux téléchargements d'utilisateurs ayant tapé sur votre annonce et n'ayant pas précédemment téléchargé votre application. Ils sont comptabilisés dans une fenêtre d'attribution de 30 jours. | | New Download Share (Tap-Through) | Indique le pourcentage du total des téléchargements via tap qui sont de nouveaux téléchargements (d'utilisateurs ayant tapé sur votre annonce dans une fenêtre d'attribution de 30 jours). | | Redownloads (Total) | Le nombre total de re-téléchargements via tap ou vue pendant la période de reporting. | | Redownloads (View-Through) | Les re-téléchargements d'utilisateurs ayant vu votre annonce sans la taper dans une fenêtre de 24 heures. Ils sont comptabilisés lorsqu'un utilisateur télécharge votre application, la supprime, puis la télécharge à nouveau sur le même appareil ou un autre après avoir vu une annonce. | | Redownloads (Tap-Through) | Les re-téléchargements d'utilisateurs ayant tapé sur votre annonce dans une fenêtre d'attribution de 30 jours. Ils sont comptabilisés lorsqu'un utilisateur télécharge votre application, la supprime, puis la télécharge à nouveau sur le même appareil ou un autre après avoir tapé sur une annonce. | | Redownloads Share (Tap-Through) | Indique le pourcentage du total des téléchargements via tap qui sont des re-téléchargements. | ## Insights \{#insights\} | Métrique | Description | |--------|------------------------------------------------------------------------------------------------------------------------------------------| | Impression Share | Impression Share est le pourcentage d'impressions reçues par votre annonce par rapport au total des impressions pour le même terme de recherche. | | Rank | Rank (actuel) est la position actuelle de votre application en termes de part d'impressions pour le terme de recherche sélectionné dans un pays ou une région donnée. | | Search Popularity | Search Popularity (actuel) est la popularité des termes de recherche en fonction du pays ou de la région. Le classement va de 1 à 5, 5 correspondant au volume de recherche le plus élevé. | --- # File: ads-manager-create-campaign --- --- title: "Gérer les campagnes dans Adapty Ads Manager" description: "Créez et modifiez des campagnes Apple Ads dans Adapty Ads Manager." --- Adapty Ads Manager dispose d'une intégration bidirectionnelle avec Apple Ads : vous obtenez des données de performance en quasi temps réel et vous pouvez créer et modifier des campagnes directement depuis Adapty Dashboard, de façon bien plus pratique qu'avec l'interface native. Si vous créez une campagne dans le tableau de bord natif Apple Ads, elle apparaîtra automatiquement dans Adapty Ads Manager dans les 24 heures. En plus d'[explorer les métriques complètes des campagnes](adapty-ads-manager-analytics), vous pouvez gérer tous les paramètres de campagne : - Créer des campagnes - Modifier des campagnes existantes - Lancer et mettre en pause des campagnes :::tip Pour trouver les campagnes qui nécessitent une attention particulière — par exemple celles qui ont atteint leur plafond budgétaire quotidien ou qui ne sont pas rentables — interrogez l'[Agent IA](ads-manager-ai-agent). ::: ## Qu'est-ce qu'une campagne \{#what-is-a-campaign\} Une campagne se concentre sur une seule application et diffuse des publicités dans un seul placement sur l'App Store. Chaque campagne comprend un budget quotidien et des [groupes d'annonces](ads-manager-create-ad-group) qui suivent une stratégie spécifique pour promouvoir votre application. Une campagne continue à dépenser selon les paramètres de son budget. :::important Notez qu'une campagne ne peut pas fonctionner seule ; les groupes d'annonces sont le niveau où vous définissez l'enchère par défaut, l'audience et les mots-clés. Sans groupe d'annonces, une campagne n'a ni ciblage ni enchère et ne diffusera pas. Créez la campagne, puis [ajoutez au moins un groupe d'annonces](ads-manager-create-ad-group) pour l'activer. ::: ## Créer des campagnes \{#create-campaigns\} Pour créer une campagne : 1. Ouvrez la page **Ads Manager** et cliquez sur **+**. Sélectionnez **Create campaign** pour lancer l'assistant de création de campagne. 2. Choisissez un **placement** pour votre annonce, puis cliquez sur **Start** : | Placement | Où votre annonce apparaît | | --- | --- | | **Search Results** | En haut des résultats de recherche dans l'App Store. | | **Search Tab** | Dans la liste des applications suggérées dans l'onglet Recherche, avant que l'utilisateur effectue une recherche. | | **Today Tab** | Sur la page Aujourd'hui de l'App Store. | | **Product Pages** | Dans la liste **You Might Also Like** sur les pages d'autres produits. Apple sélectionne les pages pertinentes pour vous. | | **Duplicate a Campaign** | Réutilisez le placement, les groupes d'annonces et les mots-clés d'une campagne existante. | 3. Pour les campagnes **Search Result**, choisissez le **type de campagne**. Regrouper les campagnes par type organise les données de vos rapports et permet à Adapty de suggérer une stratégie de mots-clés adaptée. :::note Choisissez **Max Conversions** pour ignorer la sélection manuelle de mots-clés et laisser les enchères automatisées d'Apple optimiser les conversions. ::: | Type de campagne | Description | | --- | --- | | **Generic** | Termes génériques décrivant ce que fait votre application, sans lien avec une marque. | | **Competitor** | Mots-clés de marque appartenant à vos concurrents. | | **Discovery** | Search Match identifie automatiquement de nouveaux mots-clés, ce qui vous permet de récupérer les plus performants. | | **Max Conversions** | Enchères automatisées par Apple, optimisées pour les conversions. Définissez le **Target CPA** à l'étape Settings. | | **Brand** | Mots-clés associés à la marque de votre application. | | **Custom** | Aucune stratégie prédéfinie. Créez la campagne entièrement de zéro. | 4. Sélectionnez l'**application** (ce que vous souhaitez promouvoir) et le **groupe de campagne** (le compte Apple Ads qui gère et finance la campagne). 5. Sélectionnez les **pays ou régions** à cibler. Pour faciliter l'optimisation, utilisez une campagne par pays. 6. Configurez les **paramètres de base** de la campagne. Le ciblage d'audience et les mots-clés se trouvent dans les [groupes d'annonces](ads-manager-create-ad-group) de la campagne, que vous ajoutez après avoir créé la campagne. | Paramètre | Description | | --- | --- | | **Campaign name** | Rempli automatiquement à partir de l'application, du placement et du pays. Modifiable à tout moment. | | **Daily budget** | Le montant que la campagne peut dépenser par jour. | | **Target CPA** | L'objectif de coût par acquisition pour l'enchérisseur automatisé. Apparaît uniquement pour les campagnes Max Conversions. | | **Ad scheduling** | Facultatif. La campagne démarre immédiatement, sauf si vous définissez une date de début ultérieure ; ajoutez une date de fin pour l'arrêter à un moment précis. | Les comptes à crédit complètent également les informations de facturation à cette étape. 7. Vérifiez le récapitulatif, confirmez les informations, puis cliquez sur **Create campaign**. 8. Passez à la [configuration du groupe d'annonces](ads-manager-create-ad-group). Les campagnes ne peuvent pas être diffusées sans groupes d'annonces — ce sont eux qui définissent l'audience et/ou les mots-clés. ## Modifier des campagnes \{#edit-campaigns\} Pour modifier une campagne existante : 1. Ouvrez les paramètres de la campagne par l'une des méthodes suivantes : - Cliquez sur le nom de la campagne dans **Ads Manager > Campaigns**. Puis cliquez sur **Edit campaign** en haut à droite. - Ou cochez la case à côté du nom de la campagne et cliquez sur **Actions > Edit campaign settings**. 2. Ajustez les paramètres de la campagne. Vous pouvez modifier le nom de la campagne, le type de campagne (pour les campagnes Search Results), les pays et le budget quotidien. Pour modifier le placement des annonces, la stratégie d'enchères ou la planification, créez plutôt une nouvelle campagne. 3. Cliquez sur **Save changes**. Vous pouvez également modifier le type d'une campagne directement dans la colonne **Campaign type** du tableau des campagnes. :::note Les modifications effectuées directement dans Apple Ads se synchronisent automatiquement avec Adapty Ads Manager, mais peuvent prendre un certain temps avant d'apparaître. ::: ## Exporter les campagnes \{#export-campaigns\} Pour exporter le tableau des campagnes au format CSV, cliquez sur l'icône de téléchargement au-dessus du tableau et sélectionnez **Export current page** ou **Export all pages**. **Export all pages** télécharge toutes les campagnes de toutes les pages dans un seul fichier. Une fenêtre de progression suit le téléchargement ; vous pouvez l'annuler à tout moment. Deux filtres optionnels sont disponibles : - **Enabled only** : inclure uniquement les campagnes actives. - **With spend ≥** : inclure uniquement les campagnes dont les dépenses dépassent un seuil défini. - **Group by country** : décomposer chaque ligne de campagne par pays. Le tableau est exporté tel qu'il apparaît dans votre tableau de bord, avec les colonnes que vous avez sélectionné d'afficher. ## Lancer et mettre en pause des campagnes \{#launch--pause-campaigns\} Pour lancer ou mettre en pause une campagne depuis Adapty Ads Manager : 1. Accédez à **Ads Manager > Campaigns**. 2. Activez ou désactivez le bouton à côté du nom de la campagne dans la colonne **Status**. ## Supprimer des campagnes \{#delete-campaigns\} Adapty Ads Manager ne peut pas supprimer des campagnes. Vous pouvez [mettre en pause](#launch--pause-campaigns) la campagne pour arrêter les dépenses, tout en conservant ses paramètres et ses données analytiques. --- # File: ads-manager-create-ad-group --- --- title: "Gérer les groupes d'annonces dans Adapty Ads Manager" description: "Créez et modifiez des groupes d'annonces Apple Ads dans Adapty Ads Manager." --- Adapty Ads Manager dispose d'une intégration bidirectionnelle avec Apple Ads : vous obtenez des données de performance en quasi-temps réel et pouvez créer et modifier des campagnes directement depuis le tableau de bord Adapty, de manière bien plus pratique que dans l'interface native. Si vous créez un groupe d'annonces dans le tableau de bord natif Apple Ads, il apparaîtra automatiquement dans Adapty Ads Manager dans les 24 heures. En plus d'[explorer des métriques de campagne complètes](adapty-ads-manager-analytics), vous pouvez gérer tous les paramètres des groupes d'annonces : - Créer des groupes d'annonces - Modifier des groupes d'annonces existants - Lancer et mettre en pause des groupes d'annonces ## Qu'est-ce qu'un groupe d'annonces \{#what-is-ad-group\} Un groupe d'annonces appartient à une [campagne](ads-manager-create-campaign) et c'est là que vous configurez le ciblage et la stratégie d'enchères de vos annonces. Chaque groupe d'annonces comprend des paramètres d'enchères, un ciblage d'audience et des [mots-clés](ads-manager-manage-keywords) qui déterminent quand et à qui vos annonces sont affichées. Les groupes d'annonces vous permettent d'organiser votre stratégie publicitaire au sein d'une campagne et de tester différentes approches de ciblage. :::important Une campagne ne peut pas fonctionner sans groupes d'annonces. Les groupes d'annonces sont le niveau où vous définissez l'enchère par défaut, l'audience et les mots-clés ; sans au moins un groupe d'annonces, une campagne n'a ni ciblage ni enchère et ne diffusera pas. Créez d'abord la campagne, puis [ajoutez au moins un groupe d'annonces](ads-manager-create-ad-group) pour l'activer. ::: ## Créer des groupes d'annonces \{#create-ad-groups\} Pour créer un nouveau groupe d'annonces Apple Ads : 1. Accédez à **Ads Manager** depuis le menu latéral. Sur n'importe quel onglet, cliquez sur **+** au-dessus du tableau, puis sélectionnez **Create ad group**. 2. Sélectionnez l'application à laquelle vous souhaitez ajouter le groupe d'annonces. 3. Sélectionnez la campagne à laquelle vous souhaitez ajouter le groupe d'annonces. 4. Configurez les paramètres du groupe d'annonces : - **Ad group name** : Le nom que vous attribuez pour identifier et rechercher votre groupe d'annonces dans le tableau de bord. - **Default max CPT bid** : Le montant maximum que vous êtes prêt à payer pour un tap sur votre annonce. Cette enchère s'applique à tous les mots-clés du groupe d'annonces, sauf si vous définissez des enchères individuelles par mot-clé. - **CPA cap (limits impressions)** (Optionnel) : Ce paramètre spécifie le montant maximum que vous êtes prêt à dépenser par conversion par tap (par exemple, un téléchargement ou une autre action cible). Il définit un plafond d'enchère pour tous les mots-clés de votre groupe d'annonces. Le plafond d'enchère est calculé en multipliant le CPA cap que vous fournissez par votre taux de conversion par tap : `CPA Cap × CR (Tap-Through)`. Si l'enchère CPT maximale du mot-clé est inférieure à cette valeur, c'est la valeur CPT maximale la plus basse qui sera appliquée. Par exemple, si votre CPA cap est de 5 $ et votre taux de conversion par tap est de 65 %, l'enchère maximale appliquée à tous les mots-clés du groupe d'annonces serait de 3,25 $. Si le CPT max est fixé à 4 $, l'enchère maximale appliquée resterait à 3,25 $. - **Search Match** : Activez cette option pour faire correspondre automatiquement votre annonce aux recherches pertinentes sans avoir à spécifier de mots-clés. Lorsqu'elle est activée, Apple Ads peut afficher votre annonce pour des recherches liées aux métadonnées et à la catégorie de votre application. - **Audience** : Les critères de ciblage qui déterminent quels utilisateurs voient vos annonces. - **All eligible users** : Affiche vos annonces à tous les utilisateurs éligibles à votre campagne. - **Specific audiences** : Ciblez des segments d'utilisateurs spécifiques en configurant : - **Devices** : Ciblez iPad, iPhone, ou les deux. - **Customer type** : Ciblez tous les utilisateurs, les nouveaux utilisateurs ou les utilisateurs existants. - **Gender** : Ciblez par genre ou tous les utilisateurs. - **Age range** : Ciblez des tranches d'âge spécifiques ou tous les utilisateurs. - **Ad scheduling** (Optionnel, disponible lorsque vous sélectionnez **Specific audiences**) : Définissez quand vos annonces commencent à être diffusées : - **Start date and time** : Quand votre groupe d'annonces doit commencer à diffuser des annonces. - **End date** (Optionnel) : Quand votre groupe d'annonces doit arrêter de diffuser des annonces. 5. Cliquez sur **Create**. 6. Si le type de placement de votre campagne est **Search results**, vous pouvez maintenant [ajouter des mots-clés](ads-manager-manage-keywords) pour commencer à diffuser des annonces. Pour les autres types de placement, c'est tout bon. :::note Dans une campagne **Max Conversions**, le groupe d'annonces dispose d'un bouton **Bidding strategy** : **Standard** ou **Automated**. Il n'y a pas de champ **Default max CPT bid**. Avec **Automated**, vous définissez un CPA cible et Apple optimise les enchères pour vous. ::: ## Modifier des groupes d'annonces \{#edit-ad-groups\} Pour modifier un groupe d'annonces existant : 1. Ouvrez les paramètres du groupe d'annonces en utilisant l'une ou l'autre méthode : - Cliquez sur le nom de la campagne dans **Ads Manager > Ad groups**. Cliquez ensuite sur **Edit ad group** en haut à droite. - Ou cochez la case à côté du nom du groupe d'annonces et cliquez sur **Actions > Edit ad group settings**. 2. Ajustez les paramètres du groupe d'annonces. L'application, la campagne, le type d'audience ainsi que la date et l'heure de début ne peuvent pas être modifiés. Dans un groupe d'annonces automatisé, seul le nom est modifiable. 3. Cliquez sur **Save changes**. Pour dupliquer un groupe d'annonces, sélectionnez-le dans **Ads Manager > Ad groups** et cliquez sur **Actions > Duplicate ad group**. :::note Les modifications apportées à un groupe d'annonces directement dans Apple Ads se synchronisent automatiquement avec Adapty Ads Manager, mais peuvent prendre un certain temps avant d'apparaître dans Adapty Ads Manager. ::: ## Exporter des groupes d'annonces \{#export-ad-groups\} Pour exporter le tableau des groupes d'annonces en CSV, cliquez sur l'icône de téléchargement au-dessus du tableau et sélectionnez **Export current page** ou **Export all pages**. **Export all pages** télécharge tous les groupes d'annonces de toutes les pages dans un seul fichier. Une fenêtre de progression suit le téléchargement ; vous pouvez l'annuler à tout moment. Deux filtres optionnels sont disponibles : - **Enabled only** : Inclure uniquement les groupes d'annonces actifs. - **With spend ≥** : Inclure uniquement les groupes d'annonces dont les dépenses dépassent un seuil spécifié. - **Group by country** : Décomposer chaque ligne de groupe d'annonces par pays. Le tableau est exporté tel qu'il apparaît dans votre tableau de bord, avec les colonnes que vous avez choisi d'afficher. ## Lancer et mettre en pause des groupes d'annonces \{#launch--pause-ad-groups\} Pour lancer ou mettre en pause un groupe d'annonces depuis Adapty Ads Manager : 1. Accédez à **Ads Manager > Ad groups**, ou naviguez vers une page de campagne pour voir ses groupes d'annonces. 2. Activez ou désactivez le bouton à côté du nom du groupe d'annonces dans la colonne **Status**. --- # File: ads-manager-manage-keywords --- --- title: "Gérer les mots-clés dans Adapty Ads Manager" description: "Ajoutez et gérez les mots-clés Apple Ads, les mots-clés négatifs et les mots-clés SKAG dans Adapty Ads Manager." --- Adapty Ads Manager dispose d'une intégration bidirectionnelle avec Apple Ads : vous obtenez des données de performance en quasi temps réel et vous pouvez créer et modifier des mots-clés directement depuis le tableau de bord Adapty, de manière bien plus pratique que dans l'interface native. Si vous créez un mot-clé dans le tableau de bord Apple Ads natif, il apparaîtra automatiquement dans Adapty Ads Manager sous 24 heures. En plus d'[explorer des analyses complètes](adapty-ads-manager-analytics), vous pouvez gérer tous vos paramètres de mots-clés : - Ajouter des mots-clés à des groupes d'annonces - Ajouter des mots-clés négatifs - Ajouter des mots-clés en tant que SKAG (Single Keyword Ad Group) - Modifier les mots-clés directement dans le tableau - Effectuer des actions en masse sur plusieurs mots-clés - Lancer et mettre en pause des mots-clés :::tip Pour repérer les mots-clés peu performants dans votre compte — par exemple, des mots-clés avec des dépenses mais aucune conversion — interrogez l'[agent IA](ads-manager-ai-agent). ::: ## Que sont les mots-clés \{#what-are-keywords\} Les mots-clés sont les termes de recherche qui déclenchent l'affichage de vos annonces dans les résultats de recherche de l'App Store. Ils sont organisés au sein de [groupes d'annonces](ads-manager-create-ad-group), qui appartiennent à des [campagnes](ads-manager-create-campaign). Cette structure hiérarchique vous permet d'organiser et de gérer efficacement votre stratégie publicitaire. :::important Les mots-clés s'appliquent uniquement aux campagnes de type de placement **Search results**. Pour les campagnes avec d'autres types de placement (Search tab ou Product pages), les mots-clés ne sont pas utilisés. ::: ### Mots-clés standard \{#standard-keywords\} Les mots-clés standard sont les principaux termes sur lesquels vous enchérissez pour déclencher vos annonces. Lorsque les utilisateurs recherchent ces termes dans l'App Store, votre annonce peut apparaître dans les résultats. ### Mots-clés négatifs \{#negative-keywords\} Les mots-clés négatifs empêchent votre annonce d'apparaître dans des recherches non pertinentes pour votre application. En ajoutant des mots-clés négatifs, vous réduisez les dépenses inutiles sur des recherches non ciblées. Les mots-clés négatifs peuvent être ajoutés au niveau du groupe d'annonces ou en tant que mots-clés négatifs inter-groupes qui s'appliquent à plusieurs campagnes simultanément. ### Mots-clés en tant que SKAG (Single Keyword Ad Group) \{#keywords-as-skag-single-keyword-ad-group\} Le SKAG (Single Keyword Ad Group) est une stratégie où vous créez des groupes d'annonces individuels, chacun contenant un seul mot-clé. Cette approche vous permet de : - Avoir un contrôle précis sur les enchères pour les mots-clés à forte valeur - Mieux analyser les performances au niveau du mot-clé Le SKAG est particulièrement utile pour identifier les mots-clés les plus performants et maximiser leur potentiel grâce à des groupes d'annonces dédiés. ## Ajouter des mots-clés \{#add-keywords\} Pour ajouter des mots-clés à un groupe d'annonces : :::note Les mots-clés dans les campagnes **Maximize Conversions** n'utilisent pas d'enchères — les enchères sont gérées automatiquement par l'objectif CPA de la campagne. Le champ **CPT bid** ne leur s'applique pas. ::: 1. Accédez à **Ads Manager** depuis le menu latéral. Sur n'importe quel onglet, cliquez sur **+** au-dessus du tableau, puis sélectionnez **Add keywords** dans le menu déroulant. 2. Dans la fenêtre modale, sélectionnez les campagnes et les groupes d'annonces auxquels vous souhaitez ajouter des mots-clés. Après avoir sélectionné des groupes d'annonces dans une campagne, vous pouvez ensuite sélectionner une autre campagne et ajouter d'autres groupes d'annonces à la liste. 3. Cliquez sur **Select** pour continuer. 4. Dans la boîte de dialogue **Add keywords**, saisissez les mots-clés dans le champ **Keywords list**. Si vous disposez d'un fichier délimité par des virgules avec des mots-clés, vous pouvez coller son contenu afin qu'Adapty Ads Manager importe tous les mots-clés en masse. 5. Pour chaque mot-clé dans le tableau, configurez : - **Match type** : sélectionnez le type de correspondance **Exact** ou **Broad** - **CPT bid** : définissez le coût maximum par clic pour ce mot-clé, ou laissez vide pour utiliser l'enchère CPT max par défaut du groupe d'annonces 6. Vérifiez vos mots-clés et cliquez sur **Add X keywords** (où X est le nombre de mots-clés que vous ajoutez). :::important Une fois un mot-clé enregistré, son type de correspondance ne peut plus être modifié. Si vous devez changer le type de correspondance, supprimez le mot-clé et ajoutez-le à nouveau avec le type souhaité. ::: ## Ajouter des mots-clés négatifs \{#add-negative-keywords\} Pour ajouter des mots-clés négatifs : 1. Accédez à **Ads Manager** depuis le menu latéral. Sur n'importe quel onglet, cliquez sur **+** au-dessus du tableau, puis sélectionnez **Add negative keywords** dans le menu déroulant. 2. Dans la fenêtre modale **Add negative keywords to**, sélectionnez le niveau auquel vous souhaitez ajouter des mots-clés négatifs : - **Selected campaigns** : ajouter des mots-clés négatifs au niveau de la campagne. - **Selected ad groups** : ajouter des mots-clés négatifs au niveau du groupe d'annonces. - **All ad groups in selected campaigns** : ajouter des mots-clés négatifs au niveau du groupe d'annonces à tous les groupes d'annonces des campagnes sélectionnées. :::note Gardez à l'esprit les points suivants : - Les mots-clés négatifs au niveau du groupe d'annonces ont une priorité plus élevée que ceux au niveau de la campagne. - Si vous ajoutez des mots-clés négatifs à tous les groupes d'annonces des campagnes sélectionnées, vous devrez les ajouter manuellement si vous décidez d'ajouter de nouveaux groupes d'annonces à ces campagnes ultérieurement. ::: 3. Saisissez les mots-clés négatifs dans le champ **Keywords list**. Si vous disposez d'un fichier délimité par des virgules avec des mots-clés, vous pouvez coller son contenu afin qu'Adapty Ads Manager importe tous les mots-clés en masse. 4. Pour chaque mot-clé dans le tableau, sélectionnez le **Match type** : - **Exact** : exclut uniquement le mot-clé exact ou ses variantes très proches. - **Broad** : exclut le mot-clé et les termes de recherche associés. Ou cochez les cases correspondantes et modifiez le type de correspondance en masse. 5. Vérifiez vos mots-clés négatifs et cliquez sur **Add X keywords** (où X est le nombre de mots-clés que vous ajoutez). :::note Les mots-clés négatifs inter-groupes sont particulièrement utiles lorsque vous souhaitez exclure certains termes de recherche dans plusieurs campagnes à la fois, ce qui permet de gagner du temps et d'assurer la cohérence de votre stratégie publicitaire. ::: ## Ajouter des mots-clés en tant que SKAG \{#add-keywords-as-skag\} Pour ajouter des mots-clés en tant que SKAG (Single Keyword Ad Group) : 1. Accédez à **Ads Manager** depuis le menu latéral. Sur n'importe quel onglet, cliquez sur **+** au-dessus du tableau, puis sélectionnez **Add keywords as SKAG** dans le menu déroulant. 2. Sélectionnez les campagnes dans lesquelles vous souhaitez créer les groupes d'annonces SKAG. Vous pouvez sélectionner plusieurs campagnes. 3. Par défaut, les nouveaux groupes d'annonces seront créés avec les paramètres par défaut ciblant tous les utilisateurs. Si vous souhaitez modifier cela, sélectionnez **Copy settings from ad group** et choisissez un groupe d'annonces existant dont vous souhaitez copier les paramètres. 4. Configurez les paramètres pour les nouveaux groupes d'annonces : - **Ad group name prefix** : préfixe optionnel à ajouter à chaque nom de groupe d'annonces (par exemple, "SKAG_" créera "SKAG_keyword1", "SKAG_keyword2", etc.). Vous pouvez cliquer sur **Tag** pour ajouter dynamiquement le mot-clé, le nom de la campagne et le pays aux noms de groupe. - **CPT bid** et **CPA cap** : définissez l'enchère pour tous les mots-clés à la fois, ou sélectionnez **Set CPT bid and CPA cap for each word manually** pour les définir individuellement pour chaque mot-clé. 5. Saisissez les mots-clés dans le champ **Keywords list**. Si vous disposez d'un fichier délimité par des virgules avec des mots-clés, vous pouvez coller son contenu afin qu'Adapty Ads Manager importe tous les mots-clés en masse. 6. Pour chaque mot-clé dans le tableau, sélectionnez le **Match type** : - **Exact** : correspond uniquement au mot-clé exact ou à ses variantes très proches - **Broad** : correspond au mot-clé et aux termes de recherche associés Ou cochez les cases correspondantes et modifiez le type de correspondance en masse. 7. Sélectionnez **Check for duplicates in target campaign** pour vous assurer qu'il n'y a pas de mots-clés identiques dans les campagnes cibles. 8. Cliquez sur **Create** pour créer les groupes d'annonces SKAG. Chaque mot-clé sera placé dans son propre groupe d'annonces au sein de chaque campagne sélectionnée, ce qui vous permet de les gérer et de les optimiser indépendamment. ## Modifier des mots-clés \{#edit-keywords\} Pour modifier des mots-clés existants : 1. Accédez à **Ads Manager > Keywords** ou **Ads Manager > Negative keywords** et trouvez le mot-clé que vous souhaitez modifier dans le tableau, ou naviguez vers une page de campagne, puis vers une page de groupe d'annonces, et trouvez le mot-clé. 2. Modifiez les valeurs directement dans le tableau : - **CPT bid** : cliquez sur la valeur de l'enchère et saisissez un nouveau coût maximum par clic - **Status** : utilisez le bouton bascule pour mettre en pause ou activer le mot-clé :::note Les modifications apportées aux mots-clés directement dans Apple Ads se synchronisent automatiquement avec Adapty Ads Manager, mais peuvent prendre un certain temps à apparaître dans Adapty Ads Manager. ::: ## Actions en masse \{#bulk-actions\} Vous pouvez effectuer des actions en masse sur plusieurs mots-clés pour gagner du temps et gérer vos mots-clés plus efficacement. Pour effectuer des actions en masse : 1. Accédez à l'onglet **Ads Manager > Keywords** ou **Ads Manager > Negative keywords**. 2. Sélectionnez plusieurs mots-clés en cochant les cases à côté des mots-clés que vous souhaitez gérer. 3. Cliquez sur le menu déroulant **Actions** et sélectionnez l'une des options suivantes : - **Add as keywords** : ajouter les mots-clés sélectionnés en tant que mots-clés standard - **Add as negative keywords** : ajouter les mots-clés sélectionnés en tant que mots-clés négatifs - **Add as SKAG** : créer des Single Keyword Ad Groups pour les mots-clés sélectionnés - **Activate** : activer les mots-clés sélectionnés - **Pause** : mettre en pause les mots-clés sélectionnés - **Create segment from keywords** : créer un segment d'audience à partir des mots-clés sélectionnés - **Copy keywords** : copier les noms des mots-clés sélectionnés dans le presse-papiers - **Edit CPT bids** : modifier les enchères CPT pour les mots-clés sélectionnés. Vous pouvez les modifier de différentes façons : - **Set to** : définir plusieurs enchères à un montant spécifique. - **Increase by/decrease by** : augmenter ou diminuer les enchères d'un montant spécifique en USD ou d'un pourcentage de l'enchère. Vous pouvez définir une limite d'enchère maximale pour éviter des dépenses excessives accidentelles. - **Set to average CPT** : utiliser la métrique CPT (coût par clic) pour aligner l'enchère sur celle-ci. Définissez un coefficient multiplicateur. Par exemple, définissez le multiplicateur à 0,9 si les performances sont inférieures aux attentes, ou à 1,1 si elles sont supérieures. - **Set to average CPA** : utiliser la métrique CPA (coût par acquisition) pour aligner l'enchère sur celle-ci. Définissez un coefficient multiplicateur. L'onglet **Negative keywords** propose un ensemble d'actions limité : - **Add as keywords** - **Add as negative keywords** - **Add as SKAG** - **Delete keywords** sont disponibles. :::tip Les actions en masse sont particulièrement utiles pour : - Convertir des mots-clés entre différents types (standard, négatif, SKAG) - Ajouter rapidement des mots-clés avec d'autres types de correspondance pour plusieurs mots-clés - Filtrer vos mots-clés les plus performants et ajuster leurs enchères - Identifier les mots-clés peu performants et les mettre en pause ::: ## Exporter les mots-clés \{#export-keywords\} Pour exporter le tableau des mots-clés au format CSV, cliquez sur l'icône de téléchargement au-dessus du tableau et sélectionnez **Export current page** ou **Export all pages**. **Export all pages** télécharge tous les mots-clés de toutes les pages dans un seul fichier. Une fenêtre de progression suit le téléchargement ; vous pouvez l'annuler à tout moment. Deux filtres optionnels sont disponibles : - **Enabled only** : inclure uniquement les mots-clés actifs. - **With spend ≥** : inclure uniquement les mots-clés dont les dépenses dépassent un seuil spécifié. - **Group by country** : décomposer chaque ligne de mot-clé par pays. Le tableau est exporté tel qu'il apparaît dans votre tableau de bord, avec les colonnes que vous avez sélectionnées pour l'affichage. ## Explorer les graphiques au niveau des mots-clés \{#explore-keyword-level-charts\} Vous pouvez ouvrir un graphique pour n'importe quel mot-clé directement depuis le tableau **Ads Manager > Keywords**. Cela permet une analyse des performances précise, jour par jour, pour chaque mot-clé individuel. Pour afficher un graphique, cliquez sur l'icône de graphique à côté du mot-clé dans le tableau. Par défaut, le graphique affiche la métrique **Spend** pour le mot-clé sélectionné. Vous pouvez afficher plusieurs métriques à la fois pour repérer des corrélations et des évolutions dans le temps. Cliquez sur **+** pour ajouter une nouvelle métrique. Cliquez sur **Reset** pour recommencer à zéro, ou décochez simplement les cases des métriques pour les masquer. ## Historique des enchères \{#bid-history\} Pour consulter l'historique des enchères d'un mot-clé, cliquez sur l'**icône de graphique** à côté de celui-ci dans le tableau. Un panneau s'ouvre avec deux onglets : **Metrics** et **Bid History**. - L'onglet **Metrics** affiche un graphique avec les métriques dans le temps. Vous pouvez ajouter et supprimer des métriques de la même façon que dans les graphiques au niveau des mots-clés — cliquez sur **+** pour en ajouter, ou décochez les cases pour les masquer. Un marqueur apparaît à chaque point où l'enchère a été modifiée — survolez un marqueur pour voir le montant exact de l'enchère à cette date. Utilisez-le pour mettre en corrélation les modifications d'enchères avec les variations de performances : si une métrique a chuté ou grimpé après une modification, le marqueur indique précisément quand cela s'est produit. - L'onglet **Bid History** liste chaque modification d'enchère : sa date, son type, les valeurs précédente et nouvelle, ainsi que la cause — une modification manuelle ou une règle d'automatisation (indiquée avec l'ID de la règle). --- # File: ads-manager-manage-ads --- --- title: "Gérer les publicités dans Adapty Ads Manager" description: "Créez et modifiez des publicités Apple Ads dans Adapty Ads Manager." --- Adapty Ads Manager s'intègre en mode bidirectionnel avec Apple Ads : vous obtenez des données de performance en quasi temps réel et pouvez créer et modifier des publicités directement depuis le tableau de bord Adapty, de façon bien plus pratique que dans l'interface native. Si vous créez une publicité dans le tableau de bord natif Apple Ads, elle apparaîtra automatiquement dans Adapty Ads Manager dans les 24 heures. ## Qu'est-ce qu'une publicité \{#what-are-ads\} Une publicité est un contenu créatif publicitaire assigné à un [groupe d'annonces](ads-manager-create-ad-group) au sein d'une [campagne](ads-manager-create-campaign). Vous pouvez assigner une seule publicité active par groupe d'annonces. ## Créer des publicités \{#create-ads\} Avant de commencer, assurez-vous d'avoir créé : - **Groupe d'annonces**. Vous pouvez [le créer directement dans Adapty Ads Manager](ads-manager-create-ad-group). - **Page produit personnalisée**. Vous devez [la configurer directement dans Apple Ads](https://developer.apple.com/help/app-store-connect/create-custom-product-pages/configure-multiple-product-page-versions/). Elle doit être approuvée par l'App Store avant de pouvoir être utilisée dans votre publicité. :::note Si un groupe d'annonces sélectionné contient déjà une publicité active, celle-ci sera mise en pause pour laisser place à la nouvelle. ::: Pour créer une nouvelle publicité Apple Ads : 1. Accédez à **Ads Manager** depuis le menu de la barre latérale. Sur n'importe quel onglet, cliquez sur **+** au-dessus du tableau et sélectionnez **Create ad**. 2. Sélectionnez l'application pour laquelle vous souhaitez lancer la publicité. 3. Sélectionnez un ou plusieurs groupes d'annonces. Adapty crée la publicité dans chaque groupe d'annonces sélectionné. 4. Saisissez le nom de la publicité. 5. Définissez le statut de la publicité. Désactivez le bouton **Status** pour démarrer la publicité plus tard. 6. Cliquez sur **Select CPP**. Vous verrez toutes les pages produit personnalisées de votre application approuvées par l'App Store. Vous ne pouvez sélectionner qu'une seule page produit personnalisée. 7. Cliquez sur **Create ad**. ## Modifier des publicités \{#edit-ads\} :::note Une fois une publicité créée, vous pouvez modifier son nom et son statut. Il n'est pas possible de changer sa CPP ni de la déplacer vers un autre groupe d'annonces. ::: Pour modifier le nom d'une publicité, utilisez l'une des options suivantes : - Cliquez sur le nom de la publicité dans **Ads Manager > Ads**. Modifiez le nom et cliquez sur la coche à côté. - Cochez la case à côté du nom de la publicité et cliquez sur **Actions > Edit ad**. Modifiez le nom ou le statut, puis cliquez sur **Save changes**. :::note Les modifications apportées à une publicité directement dans Apple Ads sont synchronisées automatiquement vers Adapty Ads Manager, mais peuvent prendre un certain temps avant d'y apparaître. ::: ## Exporter des publicités \{#export-ads\} Pour exporter le tableau des publicités au format CSV, cliquez sur l'icône de téléchargement au-dessus du tableau et sélectionnez **Export current page** ou **Export all pages**. **Export all pages** télécharge toutes les publicités de toutes les pages dans un seul fichier. Une fenêtre de progression suit le téléchargement ; vous pouvez l'annuler à tout moment. Deux filtres optionnels sont disponibles : - **Enabled only** : inclure uniquement les publicités actives. - **With spend ≥** : inclure uniquement les publicités dont les dépenses dépassent un seuil défini. - **Group by country** : décomposer chaque ligne de publicité par pays. Le tableau est exporté tel qu'il apparaît sur votre tableau de bord, avec les colonnes que vous avez choisi d'afficher. ## Lancer et mettre en pause des publicités \{#launch--pause-ads\} Pour lancer ou mettre en pause une publicité depuis Adapty Ads Manager, utilisez l'une des options suivantes : - Activez ou désactivez le bouton **Status** dans **Ads Manager > Ads**. - Cochez la case à côté du nom de la publicité, cliquez sur **Actions > Edit ad**, activez ou désactivez le bouton **Status**, puis cliquez sur **Save changes**. --- # File: ads-manager-create-segments --- --- title: "Créer des segments basés sur l'attribution Apple Ads dans Adapty Ads Manager" description: "Créez des segments à partir de campagnes, groupes d'annonces et mots-clés en deux clics dans Adapty Ads Manager." --- Vous pouvez créer des [segments](segments) utilisateurs directement depuis [Adapty Ads Manager](adapty-ads-manager) en sélectionnant des campagnes, groupes d'annonces ou mots-clés, puis en les transformant en segments en quelques clics. Cela facilite la personnalisation des paywalls et des offres en fonction de la source d'acquisition, sans avoir à définir manuellement les conditions de segment. Une fois un segment créé, vous pouvez l'utiliser pour attribuer différents produits et tarifs, lancer des tests A/B et personnaliser l'apparence des paywalls. ## Cas d'usage \{#use-cases\} Voici quelques exemples d'utilisation concrète des segments créés à partir des données Apple Ads : - **Paywalls basés sur les mots-clés**. Affichez un paywall axé sur les fonctionnalités aux utilisateurs issus de mots-clés à forte intention, et un paywall général aux utilisateurs issus de mots-clés de découverte plus larges. - **Offres au niveau des campagnes**. Proposez des essais plus longs ou des tarifs spéciaux aux utilisateurs provenant de certaines campagnes Apple Ads, tout en conservant une offre standard pour les autres. - **Cohérence publicité-paywall**. Redirigez les utilisateurs des groupes d'annonces mettant en avant des fonctionnalités spécifiques vers des paywalls qui présentent ces fonctionnalités en premier. - **Optimisation des campagnes à fort ROI**. Affichez un paywall premium plein tarif aux utilisateurs issus de campagnes qui génèrent systématiquement une valeur vie plus élevée. ## Créer des segments \{#create-segments\} Pour créer un segment depuis Adapty Ads Manager : 1. Allez dans **Ads Manager** et basculez sur l'onglet **Campaigns**, **Ad groups** ou **Keywords**. Cochez les cases à côté des entités que vous souhaitez utiliser. Notez que si vous sélectionnez plusieurs entités, elles seront utilisées pour créer un seul segment les regroupant toutes, et non un segment par entité. 2. Cliquez sur **Actions > Create segment from campaigns/ad groups/keywords**. 3. Si nécessaire, modifiez les détails du segment dans la fenêtre **Create segment** : - **Adapty project** : Application dans Adapty dans laquelle vous souhaitez créer ce segment. - **Build segment from campaign/ad group** : Lors de la création d'un segment à partir de campagnes ou de groupes d'annonces, vous pouvez ajuster les campagnes ou groupes d'annonces sélectionnés à cette étape. - **Segment name** - **Segment description** 4. Cliquez sur **Create**. 5. Une fois votre segment créé, vous pouvez préparer son utilisation : - Ajoutez-le à un [placement](placements) pour l'utiliser avec un paywall ou onboarding existant - Concevez un nouveau [paywall](adapty-paywall-builder) ou [onboarding](onboardings) qui sera affiché aux utilisateurs du segment - Lancez un [test A/B](ab-tests) --- # File: ads-manager-automations --- --- title: "Automations dans Adapty Ads Manager" description: "Automatisez vos campagnes Apple Ads avec des règles sur les mots-clés, les termes de recherche, les groupes d'annonces et les campagnes." --- Les règles d'automation dans Adapty Ads Manager agissent sur vos performances Apple Ads sans intervention manuelle. Vous définissez des conditions basées sur des métriques de performance, configurez une action et planifiez l'exécution de la règle. Il existe quatre types de règles d'automation, un pour chaque niveau de la structure de votre compte : | Type de règle | S'applique à | Actions | Cas d'usage | |---|---|---|---| | [Règles sur les mots-clés](ads-manager-automations-keyword-rules) | Mots-clés | Modifier l'enchère, activer, mettre en pause, ajouter comme mot-clé, ajouter comme négatifs | Gérer le cycle de vie complet des mots-clés en fonction des performances | | [Automations sur les termes de recherche](ads-manager-automations-search-terms) | Termes de recherche (requêtes réelles des utilisateurs) | Promouvoir les termes en mots-clés, ajouter comme négatifs | Construire un entonnoir de mots-clés à partir du trafic de découverte | | [Règles sur les groupes d'annonces](ads-manager-automations-ad-group-rules) | Groupes d'annonces | Modifier l'enchère par défaut, modifier l'objectif CPA, activer, mettre en pause | Ajuster les enchères et les limites de dépenses au niveau du groupe d'annonces | | [Règles sur les campagnes](ads-manager-automations-campaign-rules) | Campagnes | Modifier le budget quotidien, activer, mettre en pause | Contrôler le budget et le statut au niveau de la campagne | <CustomDocCardList ids={['ads-manager-automations-keyword-rules', 'ads-manager-automations-search-terms', 'ads-manager-automations-ad-group-rules', 'ads-manager-automations-campaign-rules']} /> Pour partir d'une règle préconfigurée plutôt que d'en créer une de zéro, cliquez sur **Templates** dans l'en-tête Automations. Des modèles sont disponibles pour les règles sur les mots-clés, les termes de recherche et les campagnes — les règles sur les groupes d'annonces n'en ont pas encore. ## Consulter les journaux \{#explore-logs\} L'onglet **Logs** affiche l'historique complet de toutes les exécutions de règles, ce qui vous permet de suivre les performances et de résoudre les problèmes. Pour consulter les journaux, dans la barre latérale gauche, accédez à **Automations** et passez à l'onglet **Logs**. Le tableau affiche : - **Rule name** : Le nom de la règle d'automation. - **Created at** : Date et heure d'exécution de la règle. - **Description** : Résumé de l'action effectuée, des conditions appliquées et des cibles (par exemple, « Decrease bid by 25%, IF Spend (previous 3 days) > $20 AND Installs (previous 3 days) is 0, Applied to: Keywords in 3 campaigns »). - **Status** : Statut d'exécution — Success, Ran with errors ou Failed. Pour exporter les données d'exécution détaillées au format CSV, cliquez sur l'icône de téléchargement à côté d'une entrée de journal. Les quatre types de règles produisent un CSV téléchargeable des éléments affectés. Les colonnes varient selon le type — par exemple : - **Keyword rules** : Liste tous les mots-clés affectés avec leurs enchères précédentes et nouvelles. - **Search term automations** : Liste chaque terme de recherche évalué avec sa campagne source et son groupe d'annonces, le groupe d'annonces cible, le résultat de l'action, le résultat de la négation, l'enchère et le type de correspondance. Pour filtrer le tableau par nom de règle, utilisez le filtre au-dessus du tableau. Si vous ne voyez pas les dernières mises à jour, cliquez sur **Refresh table** pour récupérer les données les plus récentes. Vous pouvez également suivre le calendrier des règles dans l'onglet **Automations** grâce aux colonnes **Date last run** et **Date next run**. ## Activer et mettre en pause des règles \{#launch-and-pause-rules\} Pour activer ou mettre en pause une règle, basculez le commutateur dans la colonne **Status** à côté de la règle. La mise en pause vous permet de désactiver temporairement une règle pendant des périodes de campagne spécifiques ou pendant que vous effectuez des ajustements, sans perdre la configuration de la règle. :::note Lorsqu'une règle est activée, elle peut remplacer vos modifications d'enchères manuelles lors de sa prochaine exécution si les conditions sont remplies. Pour vous appuyer temporairement sur la gestion manuelle, mettez la règle en pause plutôt que de la supprimer. ::: ## Exécuter une règle immédiatement \{#run-a-rule-immediately\} Bien que les règles s'exécutent selon leur planning, vous pouvez déclencher n'importe quelle règle immédiatement : 1. Cliquez sur les trois points à côté de la règle. 2. Sélectionnez **Run rule right now**. La règle s'exécute immédiatement et applique son action configurée à tous les éléments correspondants. Utilisez cette option après avoir ajouté des mots-clés, des groupes d'annonces ou d'autres modifications structurelles, lorsque vous souhaitez que la règle s'exécute avant la prochaine heure planifiée. ## Dupliquer une règle \{#duplicate-a-rule\} Pour gagner du temps lors de la création de règles similaires : 1. Cliquez sur les trois points à côté de la règle. 2. Sélectionnez **Duplicate**. 3. Modifiez la règle dupliquée selon vos besoins et cliquez sur **Save**. ## Supprimer une règle \{#delete-a-rule\} Pour supprimer une règle dont vous n'avez plus besoin : 1. Cliquez sur les trois points à côté de la règle. 2. Sélectionnez **Delete** et confirmez. La suppression d'une règle est définitive. Si vous pensez en avoir besoin plus tard, mettez-la plutôt en pause. --- # File: ads-manager-automations-keyword-rules --- --- title: "Règles pour les mots-clés dans Adapty Ads Manager" description: "Gérez automatiquement le cycle de vie des mots-clés — ajustez les enchères, activez ou mettez en pause des mots-clés, et déplacez-les entre les groupes d'annonces — selon les performances des campagnes." --- Les règles pour les mots-clés agissent automatiquement sur vos mots-clés en fonction des performances sur l'ensemble du funnel — des installations aux essais, abonnements et revenus. Définissez des conditions à l'aide de métriques comme les dépenses, le CPA, le ROAS et les données de cohorte, puis choisissez ce que la règle fait lorsque ces conditions sont remplies. Les règles s'exécutent selon un calendrier que vous définissez. Elles réagissent aux changements de performances sans intervention manuelle. ## Actions disponibles \{#available-actions\} Chaque règle de mot-clé effectue une action lorsque ses conditions sont remplies : | Action | Ce qu'elle fait | |--------|----------------| | **Change bid** | Augmente, diminue ou définit l'enchère CPT | | **Enable keyword** | Réactive un mot-clé mis en pause | | **Pause keyword** | Met en pause un mot-clé actif | | **Add as keyword to…** | Copie le mot-clé vers un autre groupe d'annonces avec une enchère et un type de correspondance spécifiés | | **Add as negative keyword to…** | Ajoute le mot-clé comme mot-clé négatif dans les groupes d'annonces ou campagnes indiqués | ## Créer une règle pour les mots-clés \{#create-a-keyword-rule\} Vous pouvez créer des règles pour les mots-clés à partir de modèles ou manuellement de zéro. ### À partir d'un modèle \{#from-a-template\} Adapty propose des modèles prêts à l'emploi pour les scénarios d'optimisation courants. Les modèles disponibles comprennent notamment : - **Cut waste on non-converting keywords** : diminuez les enchères lorsque les dépenses > X et que les installations ou essais = 0. - **Scale winning keywords** : augmentez les enchères lorsque le ROAS > cible ou le CPA < cible. Pour créer une règle à partir d'un modèle : 1. Dans la barre latérale gauche, allez dans **Automations** et cliquez sur **Templates**. 2. Choisissez un modèle et cliquez sur **Next**. 3. Vérifiez et ajustez les paramètres préremplis : - **Rule name** : automatiquement défini sur le nom du modèle et la date actuelle (par exemple, « Scale Winning Keywords - [2025-11-12] »). - **Apply to** : sélectionnez les groupes de campagnes, applications, campagnes ou groupes d'annonces auxquels la règle doit s'appliquer. - **Conditions** : modifiez les conditions préconfigurées si nécessaire. - **Action** : modifiez l'action prédéfinie si nécessaire. - **Schedule** : définissez la fréquence d'exécution de la règle. 4. Cliquez sur **Save** pour activer la règle. ### Manuellement \{#manually\} Pour créer une règle personnalisée pour les mots-clés de zéro : 1. Dans la barre latérale gauche, allez dans **Automations**, cliquez sur **Create rule** et sélectionnez **Keywords** comme type de règle. 2. Saisissez un **Rule name** descriptif. 3. Dans la section **Apply to**, sélectionnez les groupes de campagnes, applications, campagnes ou groupes d'annonces auxquels la règle doit s'appliquer. 4. Cliquez sur **Add condition** et sélectionnez une [métrique](adapty-ads-manager-metrics) dans la liste. Les métriques sont calculées pour la période sélectionnée dans la devise de votre compte. Les données sont mises à jour quasi en temps réel, de sorte que les règles utilisent toujours des données de performance récentes. 5. Définissez la période (par exemple, 3 jours précédents ou 7 jours précédents), choisissez l'opérateur de comparaison et saisissez la valeur seuil. 6. Pour ajouter d'autres conditions, cliquez sur **Add condition** et sélectionnez un opérateur **And** ou **Or** sur la gauche. 7. Dans la section **Action**, sélectionnez ce qui se passe lorsque les conditions sont remplies : **Change bid** - **Action type** : sélectionnez **Increase by**, **Decrease by** ou **Set to**. - **Value type** : basculez entre **$** (valeur absolue) et **%** (relatif à l'enchère actuelle au moment de l'exécution de la règle). - **Upper bid limit** (facultatif) : plafond d'enchère maximum pour éviter les surenchères si la règle se déclenche plusieurs fois sur des signaux forts. **Enable keyword** - Aucune configuration supplémentaire. La règle réactive les mots-clés mis en pause qui remplissent les conditions. **Pause keyword** - Aucune configuration supplémentaire. La règle met en pause les mots-clés actifs qui remplissent les conditions. **Add as keyword to…** - **Target ad groups** : sélectionnez les groupes d'annonces qui reçoivent les mots-clés copiés. - **CPT bid** : définissez l'enchère initiale pour les mots-clés copiés. - **Match type** : sélectionnez **Exact** ou **Broad**. - **Skip if keyword already exists** : lorsque cette option est activée, les termes déjà présents dans le groupe d'annonces cible sont ignorés. **Add as negative keyword to…** - **Scope** : sélectionnez les groupes d'annonces ou campagnes où le mot-clé négatif est ajouté. - **Match type** : sélectionnez **Exact** ou **Broad**. 8. Dans la section **Schedule** : - Choisissez la fréquence : **Every day**, **Every 2 days**, **Every week**, etc. - Sélectionnez l'heure d'exécution (toutes les heures sont en UTC). Les règles s'exécutent à l'heure planifiée en UTC. L'exécution se termine généralement en quelques minutes, après quoi vous pouvez voir les modifications dans Logs et dans le tableau de bord principal. 9. Cliquez sur **Save** pour créer la règle. ## Bonnes pratiques \{#best-practices\} - **Commencez avec un périmètre restreint** : appliquez les nouvelles règles à quelques campagnes ou groupes d'annonces en premier pour valider leur comportement avant de les étendre. - **Utilisez des fenêtres de consultation courtes pour les campagnes actives** : pour les campagnes qui évoluent rapidement, 3 à 7 jours précédents fonctionnent généralement mieux que 30 jours. - **Combinez dépenses et conversions** : évitez les règles à métrique unique. Utilisez les dépenses conjointement avec les installations, les essais ou le ROAS pour des signaux plus fiables. - **Définissez des plafonds d'enchères sur les règles Change bid** : la limite d'enchère supérieure évite les enchères incontrôlées lorsqu'un signal fort déclenche la règle plusieurs fois. - **Utilisez Enable keyword avec les données de cohorte** : un mot-clé mis en pause tôt en raison d'un CPA initial trop élevé peut afficher un ROAS D31 ou D61 solide une fois les données de cohorte matures. Définissez une condition sur le ROAS de cohorte et réactivez-le automatiquement lorsqu'il dépasse votre cible. - **Utilisez Add as keyword to… pour les pipelines de test vers la mise à l'échelle** : lorsqu'un mot-clé dans une campagne de test atteint votre cible CPA, copiez-le automatiquement vers une campagne de mise à l'échelle. - **Utilisez Add as negative keyword to… pour garder les campagnes Discovery propres** : lorsqu'un mot-clé est confirmé comme mot-clé en correspondance exacte, excluez-le de vos campagnes Discovery ou Search Match pour éviter de vous faire concurrence sur la même requête. - **Attendez avant que les règles d'enchères agissent sur les mots-clés nouvellement promus** : si vous utilisez des [automatisations de termes de recherche](ads-manager-automations-search-terms) pour promouvoir des termes dans des campagnes de mots-clés, laissez à ces mots-clés un ou deux jours pour accumuler des données. --- # File: ads-manager-automations-search-terms --- --- title: "Automatisations des termes de recherche dans Adapty Ads Manager" description: "Promouvez automatiquement les termes de recherche gagnants en mots-clés et niez-les à la source pour faire évoluer le trafic de découverte sans intervention manuelle" --- Les campagnes Discovery et Search Match génèrent des données sur les termes de recherche. Transformer ces données en une liste de mots-clés structurée implique de télécharger des rapports, de filtrer les termes et de les ajouter manuellement aux groupes d'annonces. Les automatisations des termes de recherche font tout cela automatiquement : dès qu'un terme remplit vos conditions, la règle agit dessus selon l'action que vous avez configurée. Il existe deux types d'actions pour les règles de termes de recherche : - **Add as keyword** : Promeut le terme en mot-clé en correspondance exacte dans un groupe d'annonces cible, et le nie optionnellement à la campagne source pour éviter les dépenses en double. - **Add as negative keyword** : Nie le terme directement, sans le promouvoir. Utilisez cette option pour exclure les termes de recherche non pertinents ou peu rentables de vos campagnes Discovery et Search Match. Le cas d'usage typique pour **Add as keyword** : laissez les campagnes Discovery ou Search Match collecter les vraies requêtes des utilisateurs, puis utilisez une règle pour détecter les termes au-delà d'un seuil de performance et les intégrer dans une campagne Probing en tant que mots-clés en correspondance exacte — tout en les niant à la source. Une campagne Probing est une campagne Apple Search Ads dédiée au test de mots-clés promus à des enchères contrôlées. Le cas d'usage typique pour **Add as negative keyword** : si un terme apparaît fréquemment sans jamais convertir (par exemple, beaucoup d'impressions mais zéro tap), niez-le automatiquement pour ne plus gaspiller de budget dessus. ## Créer une règle d'automatisation de termes de recherche \{#create-a-search-term-automation-rule\} Vous pouvez créer des règles d'automatisation de termes de recherche à partir de modèles ou manuellement depuis zéro. :::note Avant de créer une règle, assurez-vous d'avoir des campagnes Discovery ou Search Match actives qui collectent des données sur les termes de recherche. Les campagnes en correspondance exacte uniquement ne génèrent pas de rapports sur les termes de recherche, la règle n'aura donc rien sur quoi agir. ::: ### À partir d'un modèle \{#from-a-template\} Pour créer une règle à partir d'un modèle : 1. Dans la barre latérale gauche, accédez à **Automations** et cliquez sur **Templates**. 2. Choisissez un modèle et cliquez sur **Next**. 3. Vérifiez et ajustez les paramètres pré-remplis : - **Rule name** : Défini automatiquement sur le nom du modèle et la date du jour. - **Apply to** : Sélectionnez les groupes de campagnes, applications, campagnes ou groupes d'annonces où la règle doit rechercher des termes de recherche. - **Conditions** : Modifiez les conditions préconfigurées si nécessaire. - **Actions** : Ajustez les groupes d'annonces cibles, l'enchère CPT et la portée des mots-clés négatifs si nécessaire. - **Schedule** : Définissez la fréquence d'exécution de la règle. 4. Cliquez sur **Save** pour activer la règle. ### Manuellement \{#manually\} Pour créer une règle d'automatisation de termes de recherche personnalisée depuis zéro : 1. Dans la barre latérale gauche, accédez à **Automations**, cliquez sur **Create rule** et sélectionnez **Search terms** comme type de règle. 2. Saisissez un **Rule name** descriptif pour identifier l'objectif de la règle. 3. Dans la section **Apply to**, sélectionnez les groupes de campagnes, applications, campagnes ou groupes d'annonces où la règle doit rechercher des termes de recherche. 4. Cliquez sur **Add condition** et sélectionnez une [métrique](adapty-ads-manager-metrics) dans la liste. Les métriques sont calculées pour la plage de temps sélectionnée dans la devise de votre compte. Les données sont mises à jour quasi en temps réel, les règles utilisent donc toujours des données de performance récentes. 5. Définissez la période (par exemple, les 3 ou 7 derniers jours), choisissez l'opérateur de comparaison et saisissez la valeur seuil. 6. Pour ajouter d'autres conditions, cliquez sur **Add condition** et sélectionnez un opérateur **And** ou **Or** sur la gauche. 7. Dans la section **Action**, sélectionnez ce qui se passe lorsqu'un terme de recherche remplit les conditions : **Add as keyword** Promeut les termes de recherche correspondants en tant que mots-clés en correspondance exacte dans un groupe d'annonces cible. - **Target ad groups** : Sélectionnez les groupes d'annonces qui reçoivent les mots-clés promus. Pour construire un pipeline de découverte, sélectionnez des groupes d'annonces dans une campagne Probing ou autre campagne structurée. - **CPT bid** : Définissez l'enchère initiale au coût par tap pour chaque mot-clé promu. Options : enchère par défaut du groupe d'annonces, CPT actuel du terme de recherche, ou une valeur spécifique. - **Skip if keyword already exists** : Lorsque cette option est activée, ignore les termes déjà présents dans le groupe d'annonces cible. - **Add as negative** : Ajoute les mêmes termes comme mots-clés négatifs pour éviter de payer deux fois pour le même trafic. - **Scope** : Sélectionnez les groupes d'annonces où les mots-clés négatifs sont ajoutés. :::tip Activez **Add as negative** dans la même règle — promouvez le terme dans une campagne structurée et niez-le à la source en une seule étape. Cela maintient vos campagnes Discovery propres et construit automatiquement votre entonnoir de mots-clés. ::: **Add as negative keyword** Nie le terme de recherche correspondant sans le promouvoir. - **Scope** : Sélectionnez les groupes d'annonces ou campagnes où le mot-clé négatif est ajouté. - **Match type** : Sélectionnez **Exact** ou **Broad**. Utilisez cette action pour nier les termes de recherche non pertinents ou de faible qualité des campagnes Discovery et Max Conversion. Par exemple : si un terme cumule plus de 50 impressions et 0 tap, niez-le automatiquement. 8. Dans la section **Schedule** : - Choisissez la fréquence : **Every day**, **Every 2 days**, **Every week**, etc. - Sélectionnez l'heure d'exécution (toutes les heures sont en UTC). Les règles s'exécutent à l'heure planifiée en UTC. L'exécution se termine généralement en quelques minutes, après quoi vous pouvez voir les modifications dans Logs et dans le tableau de bord principal. 9. Cliquez sur **Save** pour créer la règle. Après l'exécution de la règle, accédez à **Automations** → **Logs** et ouvrez l'entrée correspondant à votre règle. Une exécution réussie liste chaque terme de recherche évalué avec sa campagne source, son groupe d'annonces cible, le résultat de l'action et le résultat de la négation. Si aucun terme n'apparaît, les conditions n'ont pas été remplies — vérifiez votre seuil ou élargissez la fenêtre de rétrospective. ## Bonnes pratiques \{#best-practices\} - **Utilisez les campagnes Discovery ou Search Match comme source** : Ces types de campagnes collectent les vraies requêtes des utilisateurs, offrant à vos règles un large pool de termes de recherche à évaluer. - **Adaptez votre seuil à votre fenêtre de rétrospective** : Deux téléchargements ou plus sur 7 jours est un bon point de départ. Une fenêtre plus longue (14–30 jours) abaisse la barre effective — les termes peuvent passer avec des conversions peu fréquentes. Pour les applications à fort volume, raccourcissez la fenêtre et relevez le seuil. - **Niez toujours à la source lorsque vous promouvez** : Si vous ajoutez un terme comme mot-clé dans une campagne Probing sans le nier dans Discovery, les deux campagnes se font concurrence sur la même requête. Activez **Add as negative** dans la même règle. - **Choisissez délibérément les groupes d'annonces cibles** : Orientez les termes promus vers un groupe d'annonces Probing spécifique plutôt que vers une campagne large. Cela maintient votre structure de mots-clés propre et facilite l'analyse des performances. - **Vérifiez les logs après chaque exécution** : Consultez l'onglet Logs pour confirmer quels termes ont été promus et où. Au début, exécutez la règle manuellement après la configuration pour valider qu'elle se comporte comme prévu. Voir [Automations](ads-manager-automations#explore-logs) pour savoir comment lire les logs. - **Laissez du temps aux mots-clés promus avant que les règles de mots-clés n'agissent dessus** : Si vous utilisez des règles de mots-clés dans les mêmes campagnes, excluez les mots-clés récemment promus ou attendez un jour ou deux avant que les règles ne s'exécutent sur eux. Une règle de mot-clé peut se déclencher sur un terme récent sans historique de performance et réduire son enchère avant qu'il ne convertisse. - **Utilisez Add as negative keyword pour les termes à forte impression et zéro tap** : Les campagnes Discovery et Max Conversion font souvent remonter des termes de recherche non pertinents. Une règle avec « Impressions > 50 ET Taps = 0 » les détecte automatiquement et les nie avant qu'ils n'accumulent davantage d'impressions gaspillées. ## Exporter les termes de recherche \{#export-search-terms\} Pour exporter le tableau des termes de recherche au format CSV, cliquez sur l'icône de téléchargement au-dessus du tableau et sélectionnez **Export current page** ou **Export all pages**. **Export all pages** télécharge tous les termes de recherche sur toutes les pages dans un seul fichier. Une fenêtre de progression suit le téléchargement ; vous pouvez l'annuler à tout moment. Le tableau est exporté tel qu'il apparaît dans votre tableau de bord, avec les colonnes que vous avez sélectionnées pour l'affichage. --- # File: ads-manager-automations-ad-group-rules --- --- title: "Règles de groupe d'annonces dans Adapty Ads Manager" description: "Ajustez automatiquement les enchères et les objectifs CPA des groupes d'annonces, et activez ou mettez-les en pause, en fonction des performances de la campagne." --- Ajoutez une **règle de groupe d'annonces** quand vous souhaitez que les paramètres d'un groupe d'annonces changent automatiquement selon ses performances. Contrairement aux règles de mots-clés qui agissent sur des mots-clés individuels, une règle de groupe d'annonces modifie l'ensemble du groupe en une seule fois. Chaque règle associe une condition à une action. Par exemple : si un groupe d'annonces dépense plus de 50 $ en trois jours sans aucun essai, réduire son enchère de 20 %. Adapty vérifie vos groupes d'annonces selon un planning que vous définissez — toutes les heures, tous les jours, toutes les semaines, etc. — et applique l'action chaque fois que la condition est remplie. Et comme Adapty suit les essais, les abonnements et les revenus, vos conditions peuvent réagir au revenu réel, pas seulement aux installations. ## Conditions disponibles \{#available-conditions\} Une règle surveille un ensemble de groupes d'annonces et se déclenche lorsque leurs performances franchissent un seuil que vous définissez. Commencez par choisir les groupes d'annonces qu'elle surveille : - **Groupes d'annonces dans les groupes de campagnes sélectionnés** - **Groupes d'annonces dans les applications sélectionnées** - **Groupes d'annonces dans les campagnes sélectionnées** - **Groupes d'annonces sélectionnés** Définissez ensuite la condition qui déclenche la règle. Chaque condition combine les éléments suivants : | Élément | Description | Exemple | | --- | --- | --- | | **Métrique** | Toute [métrique suivie par Adapty Ads Manager](adapty-ads-manager-metrics) — dépenses, installations, essais, abonnements, revenus, etc. | Dépenses | | **Fenêtre temporelle** | La période sur laquelle la métrique est mesurée. | 3 derniers jours | | **Comparaison** | La façon dont la métrique est comparée à votre valeur. | est supérieur à | | **Seuil** | La valeur contre laquelle vous comparez. | 50 $ | Combinez plusieurs conditions avec **Et** ou **Ou** pour un ciblage précis — par exemple, dépenses > 50 $ **et** essais = 0. ## Actions disponibles et leurs paramètres \{#available-actions-and-their-settings\} Lorsqu'un groupe remplit votre condition, Adapty peut modifier ses paramètres en déclenchant l'une des actions suivantes : | Action | Ce qu'elle fait | Quand l'utiliser | Configuration | | --- | --- | --- | --- | | **Modifier l'enchère par défaut** | Augmente, diminue ou définit l'enchère max **coût-par-tap (CPT)** par défaut du groupe d'annonces — le montant maximum que vous payez pour un tap sur votre annonce. | Misez davantage sur les groupes qui convertissent ; réduisez sur ceux qui ne convertissent pas. | **Type d'action** : Augmenter de, Diminuer de, ou Définir à.<br/>**Type de valeur** : $ (absolu) ou % (de l'enchère actuelle).<br/>**Limite** (facultatif) : Une limite haute lors d'une augmentation, ou une limite basse lors d'une diminution — plafonne jusqu'où les exécutions répétées déplacent l'enchère. | | **Modifier l'objectif CPA** | Augmente, diminue ou définit l'**objectif CPA (plafond)** du groupe d'annonces — coût par acquisition cible. | Resserrez le plafond de coût au fur et à mesure que vous optimisez, ou élargissez-le pour gagner plus de volume. | **Type d'action** : Augmenter de, Diminuer de, ou Définir à.<br/>**Type de valeur** : $ ou %.<br/>**Limite** (facultatif) : Une limite haute lors d'une augmentation, ou une limite basse lors d'une diminution. | | **Activer le groupe d'annonces** | Réactive un groupe d'annonces mis en pause. | Remettez en route les groupes d'annonces qui se redressent une fois que les revenus d'essais et d'abonnements tardifs arrivent. | Aucune. | | **Mettre en pause le groupe d'annonces** | Met en pause un groupe d'annonces actif. | Stoppez les groupes d'annonces qui continuent de dépenser sans convertir. | Aucune. | ## Créer une règle de groupe d'annonces \{#create-an-ad-group-rule\} 1. Allez dans **Automations**, cliquez sur **Create rule** et sélectionnez **For ad groups**. 2. Saisissez un **Rule name**. 3. Sous **Apply to**, choisissez une [portée](#available-conditions) et sélectionnez les groupes d'annonces. 4. Sous **Conditions**, ajoutez une ou plusieurs [conditions](#available-conditions). Vous pouvez combiner des conditions avec des opérateurs logiques. 5. Sous **Action**, choisissez une [action](#available-actions-and-their-settings) et configurez ses options. 6. Sous **Schedule**, définissez la fréquence d'exécution de la règle et son heure de démarrage (UTC), ou sélectionnez **Run immediately**. 7. Cliquez sur **Save**. Après l'enregistrement, la règle apparaît dans l'onglet **Automations**. Les colonnes **Date last run** et **Date next run** suivent son planning. Pour confirmer les changements de statut d'une exécution à l'autre, ouvrez **Automations > Logs**. Consultez [Automations](ads-manager-automations) pour savoir comment mettre en pause, dupliquer, supprimer une règle ou l'exécuter immédiatement. --- # File: ads-manager-automations-campaign-rules --- --- title: "Règles de campagne dans Adapty Ads Manager" description: "Ajustez automatiquement les budgets quotidiens des campagnes et activez ou mettez-les en pause selon leurs performances." --- Ajoutez une **règle de campagne** lorsque vous souhaitez que le budget ou le statut d'une campagne change automatiquement en fonction de ses performances. Contrairement aux règles de groupe d'annonces, qui agissent sur un seul groupe, une règle de campagne modifie toute la campagne en une fois. Chaque règle associe une condition à une action. Par exemple : si une campagne dépense plus de 200 $ en trois jours sans abonnement, réduisez son budget quotidien de 20 %. Adapty vérifie vos campagnes selon une planification que vous définissez — toutes les heures, quotidiennement, hebdomadairement, etc. — et applique l'action dès que la condition est remplie. Et comme Adapty suit les essais, les abonnements et les revenus, vos conditions peuvent répondre aux revenus réels, pas seulement aux installations. ## Conditions disponibles \{#available-conditions\} Une règle surveille un ensemble de campagnes et se déclenche lorsque leurs performances franchissent un seuil que vous définissez. Commencez par choisir les campagnes qu'elle surveille : - **Campaigns in selected campaign groups** - **Campaigns in selected apps** - **Selected campaigns** Définissez ensuite la condition qui déclenche la règle. Chaque condition combine les éléments suivants : | Élément | Description | Exemple | | --- | --- | --- | | **Metric** | Toute [métrique suivie par Adapty Ads Manager](adapty-ads-manager-metrics) — dépenses, installations, essais, abonnements, revenus, etc. | Spend | | **Time window** | La période sur laquelle la métrique est mesurée. | Yesterday | | **Comparison** | Comment la métrique est comparée à votre valeur. | is greater than | | **Threshold** | La valeur à laquelle vous comparez — un montant fixe ou le **Daily Budget** de la campagne. | Daily Budget | Combinez plusieurs conditions avec **And** ou **Or** pour un ciblage précis — par exemple, spend > Daily Budget **and** ROAS < 100 %. ## Actions disponibles et leurs paramètres \{#available-actions-and-their-settings\} Lorsqu'une campagne remplit votre condition, Adapty peut modifier ses paramètres en déclenchant l'une des actions suivantes : | Action | Ce qu'elle fait | Quand l'utiliser | Configuration | | --- | --- | --- | --- | | **Change daily budget** | Augmente, diminue ou définit le **daily budget** de la campagne — le montant maximum qu'elle peut dépenser par jour. | Réduire le budget des campagnes qui dépensent trop ; l'augmenter pour celles qui progressent de manière rentable. | **Action type** : Increase by, Decrease by ou Set to.<br/>**Value type** : $ (absolu) ou % (du budget actuel).<br/>**Limit** (facultatif) : Une limite supérieure lors d'une augmentation, ou une limite inférieure lors d'une diminution — plafonne l'amplitude des modifications sur plusieurs exécutions. | | **Enable campaign** | Réactive une campagne en pause. | Relancer les campagnes qui se redressent une fois que les revenus tardifs d'essais et d'abonnements arrivent. | Aucune. | | **Pause campaign** | Met en pause une campagne active. | Arrêter les campagnes qui continuent à dépenser sans convertir. | Aucune. | ## Créer une règle de campagne \{#create-a-campaign-rule\} Pour démarrer à partir d'un modèle, cliquez sur **Templates** dans l'en-tête **Automations** et sélectionnez **Decrease budget for low-performing campaigns**, puis vérifiez et enregistrez. Pour créer une règle de zéro : 1. Allez dans **Automations**, cliquez sur **Create rule** et sélectionnez **For campaigns**. 2. Saisissez un **Rule name**. 3. Sous **Apply to**, choisissez un [périmètre](#available-conditions) et sélectionnez les campagnes. 4. Sous **Conditions**, ajoutez une ou plusieurs [conditions](#available-conditions). Vous pouvez les combiner avec des opérateurs logiques. 5. Sous **Action**, choisissez une [action](#available-actions-and-their-settings) et configurez ses options. 6. Sous **Schedule**, définissez la fréquence d'exécution de la règle et son heure de démarrage (UTC), ou sélectionnez **Run immediately**. 7. Cliquez sur **Save**. Après l'enregistrement, la règle apparaît dans l'onglet **Automations**. Les colonnes **Date last run** et **Date next run** suivent sa planification. Pour confirmer les changements de statut entre les exécutions, ouvrez **Automations > Logs**. Consultez [Automations](ads-manager-automations) pour savoir comment mettre en pause, dupliquer, supprimer une règle ou l'exécuter immédiatement. --- # File: ads-manager-market-intelligence --- --- title: "Market Intelligence dans Adapty Ads Manager" description: "Voyez sur quels mots-clés vos concurrents enchérissent sur Apple Ads dans plus de 50 pays, et ajoutez-les directement à vos campagnes." --- Market Intelligence montre sur quels mots-clés vos concurrents enchérissent sur Apple Ads, dans plus de 50 pays. Les données sont agrégées sur les 30 derniers jours et mises à jour quotidiennement. Utilisez-le pour : - **Éviter la campagne Discovery** : voyez sur quoi enchérissent déjà vos concurrents plutôt que de dépenser du budget pour trouver ce qui fonctionne. Démarrez dès le premier jour avec une liste de mots-clés éprouvés. - **Trouver des mots-clés peu concurrentiels** : repérez les termes de longue traîne où la Share of Voice des concurrents est faible — moins de concurrence, coût par tap plus bas et meilleur CPA. - **Protéger votre marque** : vérifiez si des concurrents enchérissent sur le nom de votre application et dans quels pays, puis récupérez ce trafic. - **Entrer sur de nouveaux marchés avec des données** : consultez les mots-clés que vos concurrents utilisent dans un pays avant d'y dépenser le moindre centime. - **Découvrir des concurrents que vous avez manqués** : recherchez par mot-clé pour voir qui se positionne naturellement sur des termes de votre catégorie et ajoutez-les à votre analyse. ## Lancer une analyse Market Intelligence \{#run-a-market-intelligence-analysis\} ### 1. Sélectionnez votre application \{#1-select-your-app\} Dans la barre latérale gauche, accédez à **Market Intelligence**. Sélectionnez l'application que vous souhaitez analyser dans le menu déroulant, puis cliquez sur **Continue**. ### 2. Sélectionnez les concurrents \{#2-select-competitors\} Ajoutez les concurrents que vous souhaitez analyser : - **Suggested competitors** : Adapty détecte les concurrents probables en fonction de la catégorie de votre application. Parcourez la liste et sélectionnez ceux que vous souhaitez inclure. - **Search by keyword or app name** : saisissez un mot-clé (par exemple, « budget tracker ») ou un nom d'application dans le champ de recherche. Changez le pays si nécessaire, puis sélectionnez des applications dans les résultats. Répétez l'opération avec différents mots-clés pour découvrir des concurrents sur différentes intentions de recherche. - **Saved list** : cliquez sur **Create list** pour enregistrer jusqu'à 20 concurrents et les réutiliser lors de futures analyses. Vous pouvez également charger une liste créée précédemment. Une fois vos concurrents sélectionnés, cliquez sur **Run analysis**. ### 3. Explorez les résultats \{#3-explore-results\} Les résultats sont organisés en quatre onglets : **Overview**, **Most Contested**, **By App** et **By Country**. #### Overview \{#overview\} L'onglet par défaut affiche un résumé de l'analyse : - **Stats bar** : nombre total de concurrents analysés, pays avec une activité Apple Ads, mots-clés uniques trouvés sur tous les marchés et mot-clé le plus disputé. - **Keywords found by country** : un graphique à barres montrant le volume de mots-clés par pays sur les 25 principaux marchés. - **Top 10 competitors by keyword coverage** : un tableau classé avec le nombre total de mots-clés de chaque concurrent, la Share of Voice moyenne (Avg SOV) et les pays où ils sont actifs. #### Most Contested \{#most-contested\} Affiche les mots-clés sur lesquels le plus grand nombre de concurrents sont actifs simultanément. Utilisez cet onglet pour trouver les termes très demandés dans votre catégorie et voir où la concurrence est la plus concentrée. Utilisez le champ de recherche pour filtrer la liste par mot-clé. #### By App \{#by-app\} Affiche les données de mots-clés pour chaque concurrent individuellement. Utilisez cet onglet pour analyser en détail la stratégie de mots-clés d'une application spécifique par pays. Cliquez sur **Add filter** pour filtrer par application, pays ou mot-clé. Pour exporter les données au format CSV, cliquez sur l'icône de téléchargement. #### By Country \{#by-country\} Affiche les données de mots-clés regroupées par marché. Utilisez cet onglet lorsque vous souhaitez vous concentrer sur le paysage concurrentiel d'un pays spécifique avant d'y entrer ou de vous y développer. Cliquez sur **Add filter** pour filtrer par application, pays ou mot-clé. Pour exporter les données au format CSV, cliquez sur l'icône de téléchargement. ### 4. Ajoutez des mots-clés à vos campagnes \{#4-add-keywords-to-campaigns\} Une fois que vous avez identifié les mots-clés à tester, ajoutez-les à vos campagnes sans quitter l'outil : 1. Dans le tableau de mots-clés, cochez les cases à côté des mots-clés que vous souhaitez utiliser. Pour sélectionner tous les mots-clés visibles, utilisez la case à cocher dans l'en-tête du tableau. 2. Cliquez sur **Add to campaign**. 3. Choisissez si vous souhaitez les ajouter comme mots-clés, mots-clés négatifs ou SKAG. Sélectionnez ensuite la campagne et le groupe d'annonces cibles, définissez le type de correspondance et l'enchère CPT, puis confirmez. ## Ce qu'il faut rechercher \{#what-to-look-for\} Ces tendances méritent votre attention dans les résultats : - **Termes de longue traîne avec une faible Share of Voice** : les mots-clés où les concurrents ont une faible part d'impressions sont moins disputés. Ils ont généralement un coût par tap plus bas et de meilleurs taux de conversion, car l'intention de l'utilisateur est plus précise. - **Mots-clés absents de vos campagnes** : recherchez les termes utilisés par vos concurrents que vous n'avez pas encore testés. Il est prouvé qu'ils génèrent du trafic Apple Ads dans votre catégorie. - **Couverture des mots-clés de marque** : recherchez le nom de votre propre application. Si des concurrents apparaissent, ils enchérissent sur votre marque. Ajoutez ces mots-clés à vos campagnes avec des enchères agressives pour protéger votre trafic. - **Lacunes par pays** : vérifiez dans quels pays vos concurrents sont actifs. Les marchés avec peu ou pas d'activité concurrentielle sont plus faciles à pénétrer et nécessitent moins de budget pour gagner en visibilité. --- # File: ads-manager-cpp-ab-tests --- --- title: "Tests A/B CPP dans Adapty Ads Manager" description: "Comparez des pages produit personnalisées dans Apple Ads et trouvez la plus performante." --- Les tests A/B CPP vous permettent de comparer des pages produit personnalisées (CPP) entre elles dans Apple Ads. Vous sélectionnez 2 à 4 pages produit, et [Adapty Ads Manager](adapty-ads-manager) fait tourner le trafic entre elles, collecte les données de performance et vous indique quelle page convertit le mieux. Vous pouvez inclure votre **page produit par défaut** comme l'une des variantes, pour tester si une page personnalisée fait mieux que votre page par défaut actuelle. ## Prérequis \{#prerequisites\} Avant de créer un test A/B CPP, vérifiez que : - **Adapty Ads Manager est connecté** : Suivez le [guide de configuration](adapty-ads-manager-get-started) si ce n'est pas encore fait. - **Le groupe d'annonces source a du trafic** : Le groupe d'annonces que vous testez doit avoir au moins 28 jours d'ancienneté et afficher des impressions, des clics et des installations sur cette période. Adapty Ads Manager utilise cet historique pour estimer la durée du test et la taille d'échantillon nécessaire. - **Vous avez au moins une page produit personnalisée** : Créez des CPP dans App Store Connect d'abord. Adapty Ads Manager les lit automatiquement. ## Créer un test A/B CPP \{#create-a-cpp-ab-test\} Pour créer un test, dans la barre latérale gauche, allez dans **CPP A/B Tests** et cliquez sur **Create A/B Tests**. L'assistant comporte quatre étapes : **Ad Group(s)**, **Ad Creative(s)**, **Testing Method** et **Review**. ### 1. Ad Group(s) \{#1-ad-groups\} Saisissez un **Test Name** et cliquez sur **Select Ad Group** pour choisir le groupe d'annonces dont vous souhaitez tester les CPP. Vous pouvez sélectionner jusqu'à quatre groupes d'annonces d'une même campagne, mais uniquement si vous prévoyez de tester un seul créatif publicitaire sur l'ensemble de ces groupes. Pour comparer plusieurs CPP, sélectionnez un seul groupe d'annonces. ### 2. Ad Creative(s) \{#2-ad-creatives\} Choisissez les CPP à comparer. Vous pouvez inclure la **Default Product Page** (marquée comme **Control**) ainsi que jusqu'à trois **Custom Product Pages**, pour un total de 2 à 4 variantes. - **Default Product Page** : Cliquez sur **+ Add Default** pour inclure votre page produit par défaut actuelle comme variante de contrôle. - **Custom Product Pages** : Cliquez sur **+ Select CPP** pour choisir une page produit personnalisée depuis App Store Connect. ### 3. Testing Method \{#3-testing-method\} Configurez le déroulement du test. Adapty Ads Manager calcule automatiquement la **Calculated Test Duration**, la **Start Time** et la **End Time** — les valeurs se mettent à jour chaque fois que vous modifiez l'un des trois paramètres ci-dessous. #### Switch Time Preset \{#switch-time-preset\} La fréquence à laquelle le système alterne entre les variantes. Si vous sélectionnez un intervalle trop élevé par rapport au niveau de trafic, le système le réduit automatiquement. | Intervalle | Niveau de trafic typique | Durée d'un slot | Durée typique du test | |--------------|-----------------------------------------------|-----------------|-----------------------| | **Hourly** | Élevé (5 000+ impressions par jour) | 7 heures | Jours | | **Daily** | Normal | 24 heures | Semaines | | **Weekly** | Faible (moins de 400 impressions par jour) | 7 jours | Mois | Un **slot** est la durée de base pendant laquelle une variante est active avant que le système envisage de passer à la suivante. #### Desired Precision \{#desired-precision\} La plus petite différence de taux de conversion que le test peut détecter de manière fiable. Options : **1%**, **2%**, **3%**, **4%**, **5%**. Par défaut : **5%**. Un test à 1% de précision détecte de très petites différences, mais nécessite plus de données et dure plus longtemps. Un test à 5% de précision se termine plus vite, mais ne détecte que les différences importantes. | Précision | Quand l'utiliser | |-----------|-----------------------------------------------------------------------------------------------| | 1–2% | Vous attendez de petites différences entre les CPP et vous avez des groupes d'annonces à fort trafic. | | 3–4% | Valeur par défaut équilibrée pour la plupart des tests. | | 5% | Vous attendez un gagnant clair et souhaitez des résultats rapidement. | #### Confidence Level \{#confidence-level\} Le niveau de certitude que vous souhaitez avoir que le résultat est réel et non aléatoire. Options : **80%**, **85%**, **90%**, **95%**, **99%**. Par défaut : **90%**. Un niveau de confiance plus élevé nécessite davantage de données. | Confiance | Compromis | |------------|------------------------------------------------------------------------------------------| | 80–85% | Se termine plus vite, mais risque plus élevé que le résultat soit dû au hasard. | | 90% | Valeur par défaut recommandée pour la plupart des tests. | | 95–99% | Le plus conservateur. Nécessite le plus de données et la durée de test la plus longue. | ### 4. Review \{#4-review\} Vérifiez le récapitulatif — groupes d'annonces sélectionnés, créatifs, méthode de test, durée, précision et niveau de confiance — puis cliquez sur **Start CPP A/B Tests**. Une fois le test lancé, le système clone le groupe d'annonces pour chaque variante, active la première variante, et le statut du test passe à **Running** en quelques minutes. ## Suivre un test en cours \{#monitor-a-running-test\} Pour ouvrir la liste des tests, allez dans **CPP A/B Tests** dans la barre latérale gauche. Les quatre onglets en haut de la page filtrent les tests par état : - **Live** : Tests en cours d'exécution. - **Completed** : Tests terminés. - **Draft** : Tests qui n'ont pas encore été lancés. - **Archive** : Anciens tests dont vous n'avez plus besoin dans la vue principale. Chaque carte de test affiche son nom, son statut, l'intervalle de rotation, la précision souhaitée et depuis combien de temps il est en cours. Cliquez sur **View metrics** pour développer le tableau des variantes. ### Performance des variantes \{#variant-performance\} Le tableau des variantes compare les performances de toutes les variantes du test : | Colonne | Description | |--------------------------|------------------------------------------------------------------------------------------------------| | **Variant Name** | La CPP testée. La variante A est toujours la première variante que vous avez ajoutée. | | **Confidence Level** | Dans quelle mesure la variante s'approche de la taille d'échantillon requise, en pourcentage de 0 à 100. | | **Impressions** | Le nombre de fois qu'Apple a affiché une annonce pour cette variante. | | **TTR** | Taux de clics : clics divisés par les impressions. | | **Tap → Download CR** | Taux de conversion du clic au téléchargement. | | **CPT** | Coût moyen par clic. | | **Avg CPA (Tap-Through)**| Coût moyen par acquisition basé sur les téléchargements par clic. | | **Spend** | Dépenses totales attribuées à la variante. | | **Revenue** | Revenus totaux attribués à la variante. | | **ROAS** | Retour sur les dépenses publicitaires : revenus divisés par les dépenses. | Tant que chaque variante n'a pas un nombre d'impressions comparable, Adapty Ads Manager ne met pas en avant de gagnant. Pendant que les données arrivent encore, vous verrez une bannière au-dessus du tableau : **Winner highlighting is paused — variants don't have comparable impressions yet.** ### Métriques détaillées \{#detailed-metrics\} Pour une vue plus approfondie du test, cliquez sur **View metrics** pour ouvrir la page des métriques détaillées. Elle inclut des courbes de rétention par cohorte, une comparaison ARPPU et un tableau de métriques regroupé en deux sections : - **Top of funnel · Apple Search Ads** : TTR, Download Rate, CPM, CPT et Avg CPA par variante. - **Bottom of funnel · Monetization** : Paid users, Paid CR, Cost per Paid, ARPPU, Revenue et ROAS par variante. La colonne **Winner** indique quelle variante est en tête sur chaque métrique. Une variante n'est désignée comme gagnante globale que lorsqu'elle est en tête sur la métrique principale et atteint un niveau de confiance d'au moins 95%. Pour les définitions des métriques, consultez [Métriques dans Adapty Ads Manager](adapty-ads-manager-metrics). ## Arrêter un test \{#stop-a-test\} Vous pouvez arrêter un test à tout moment. Le test sera marqué comme **Stopped**, le groupe d'annonces d'origine sera restauré et les groupes d'annonces clonés seront mis en pause. Pour arrêter un test en cours : 1. Allez dans **CPP A/B Tests** dans la barre latérale gauche. 2. Cliquez sur **Stop A/B test** sur la carte du test, ou ouvrez le test et cliquez sur **Stop Test**. 3. Confirmez dans la boîte de dialogue **Stop A/B Test?**. :::important L'arrêt d'un test est définitif — vous ne pouvez pas le reprendre. Les résultats collectés jusqu'alors restent disponibles dans l'onglet **Completed**. ::: ## Statuts des tests \{#test-statuses\} Chaque test passe par un ensemble fixe de statuts : | Statut | Signification | |---------------|-----------------------------------------------------------------------------------------------------| | **Draft** | Test créé mais non lancé. Vous pouvez encore le modifier. | | **Starting** | Configuration en cours — le système clone les groupes d'annonces et crée les annonces. | | **Running** | Le test est actif. Les variantes sont alternées et les métriques collectées. | | **Completed** | La durée planifiée a expiré ou le niveau de confiance a été atteint. Le groupe d'annonces d'origine est restauré. | | **Stopped** | Vous avez arrêté le test manuellement. Le groupe d'annonces d'origine est restauré. | | **Failed** | La configuration a échoué ou trop d'erreurs consécutives se sont produites. Vous pouvez relancer un test en échec. | ## Fonctionnement \{#how-it-works\} Adapty Ads Manager utilise la méthode **Ad Group Switch** : 1. Au démarrage du test, le système clone le groupe d'annonces source une fois par variante. Chaque clone pointe vers une CPP différente (l'une d'elles peut être votre page par défaut). 2. Un seul clone est actif à la fois. Le système alterne le clone actif selon un calendrier fixe (toutes les heures, tous les jours ou toutes les semaines). 3. Le groupe d'annonces d'origine est mis en pause pendant le test. Il est restauré à son état précédent à la fin du test. 4. Adapty Ads Manager collecte les impressions, clics et téléchargements par variante, et suit dans quelle mesure chaque variante s'approche d'un échantillon statistiquement significatif. 5. Le test se termine automatiquement dès que chaque variante dispose de suffisamment de données, ou lorsque la durée planifiée est atteinte. ## Ce à quoi s'attendre pendant un test \{#what-to-expect-while-a-test-runs\} Quelques points à connaître sur le comportement d'un test en cours dans le tableau de bord : - **Les variantes ne s'alternent pas selon une horloge fixe** : L'intervalle de rotation est une base, mais Adapty Ads Manager ajuste le timing pour que chaque variante collecte une part équitable d'impressions. Une variante peut rester active plus longtemps qu'un seul slot si elle est en retard sur les impressions. - **La End Time peut être repoussée** : Si une variante manque de données à l'approche de la fin planifiée, le test est automatiquement prolongé pour continuer à collecter des clics. La nouvelle End Time apparaît sur la carte du test. - **À la fin du test, le groupe d'annonces d'origine est restauré** : Tous les groupes d'annonces clonés sont mis en pause et le groupe d'annonces source retrouve son statut d'avant le test. Les résultats restent disponibles dans l'onglet **Completed**. --- # File: ads-manager-settings --- --- title: "Paramètres dans Adapty Ads Manager" description: "Configurez les paramètres dans Adapty Ads Manager." --- Accédez à **Settings** dans le coin inférieur gauche du tableau de bord Adapty Ads Manager pour configurer les paramètres de votre compte. ## Groupes de campagnes \{#campaign-groups\} Depuis l'onglet **Campaign groups**, vous pouvez voir tous les comptes Apple Ads connectés à Adapty Ads Manager et en ajouter de nouveaux. Si vous connectez plusieurs comptes Apple Ads, toutes leurs données analytiques seront agrégées dans un seul tableau de bord Adapty Ads Manager. Pour ajouter un nouveau compte Apple Ads, cliquez sur **Connect Apple Ads account** et suivez le [guide](adapty-ads-manager-get-started). ## Gérer l'abonnement \{#manage-subscription\} Depuis l'onglet **Manage subscription**, vous pouvez consulter votre plan d'abonnement actuel et mettre à jour votre mode de paiement. ## Paramètres utilisateur \{#user-settings\} Depuis l'onglet **User settings**, vous pouvez activer le bouton **Hide Paused by Default**. Lorsqu'il est activé, les campagnes, groupes d'annonces et mots-clés en pause sont masqués pour vous permettre de vous concentrer sur les données de performance actives. Évitez d'activer cette option si vous expérimentez fréquemment en lançant et en mettant en pause différentes campagnes, groupes d'annonces et mots-clés, car vous pourriez avoir besoin d'accéder aux éléments en pause à tout moment. --- # File: adapty-user-acquisition --- --- title: "Adapty Attribution" description: "Éliminez le recours aux MMP et calculez toute l'économie de votre application en un seul endroit." --- <CustomDocCardList ids={['user-acquisition', 'ua-analytics', 'ua-integrations', 'ua-tracking-links', 'ua-deferred-data']} /> Adapty Attribution est une solution d'attribution qui relie les campagnes publicitaires aux installations d'applications et aux revenus des abonnements en combinant les données des plateformes publicitaires, des liens de suivi et de votre application. Elle propose un tableau de bord marketing unifié qui centralise toutes vos données d'acquisition en un seul endroit. - Calculez le ROAS (retour sur les dépenses publicitaires) sur l'ensemble de vos canaux - Visualisez toute l'économie de votre application en un seul endroit - Obtenez des données d'attribution précises pour prendre de meilleures décisions - Analysez les performances par cohorte et le comportement des utilisateurs dans le temps :::tip Vous souhaitez en savoir plus sur la façon dont Adapty Attribution peut vous être utile ? [Réservez un appel](https://calendly.com/tnurutdinov-adapty/30min) avec nous. ::: ## Pourquoi choisir Adapty Attribution ? \{#why-choose-adapty-attribution\} Mesurer les performances de l'acquisition d'utilisateurs est un vrai défi. Les données sont souvent éparpillées sur plusieurs plateformes, l'attribution devient difficile en raison des changements liés à la confidentialité, et développer des solutions personnalisées prend beaucoup de temps. Adapty Attribution offre une attribution intégrée et des analyses unifiées dans un seul tableau de bord marketing. Toutes vos métriques d'acquisition — des dépenses publicitaires aux installations en passant par les revenus des abonnements — sont automatiquement consolidées et mises à jour en temps réel. Fini de réconcilier des données dans des feuilles de calcul ou de jongler entre plusieurs outils. Vous pouvez vous concentrer sur la croissance de votre application plutôt que sur la gestion des systèmes de données. ## Comment ça fonctionne \{#how-it-works\} Adapty Attribution attribue les installations d'applications et les revenus des abonnements aux campagnes publicitaires en combinant les données des plateformes publicitaires, des liens de suivi et de votre application. En résumé : - Les plateformes publicitaires fournissent la structure des campagnes et les dépenses publicitaires - Les liens de suivi générés dans Adapty Attribution transportent le contexte de la campagne depuis le web jusqu'à l'installation de l'application - Le SDK Adapty envoie les événements d'installation et de revenus depuis votre application Le flow d'attribution fonctionne comme suit : 1. **Un lien de suivi est généré dans Adapty Attribution et ajouté à une campagne publicitaire.** Le lien contient les paramètres de la campagne tels que la plateforme, la campagne, l'ensemble de publicités et le créatif. 2. **Un utilisateur clique sur l'annonce et installe l'application depuis le store.** L'utilisateur est redirigé via le lien de suivi et installe l'application depuis l'App Store ou Google Play. 3. **L'application envoie un événement d'installation à Adapty.** Au premier lancement, le SDK Adapty envoie un événement d'installation. Adapty extrait les paramètres de campagne associés à cette installation. 4. **L'installation est attribuée à une campagne.** En utilisant les paramètres de campagne du lien de suivi, Adapty associe l'installation à la campagne qui l'a générée. 5. **Les dépenses publicitaires et les revenus sont reliés.** Adapty récupère les données de dépenses publicitaires auprès des plateformes publicitaires compatibles (actuellement Meta Ads et TikTok for Business) et relie les événements d'abonnement et d'achat aux installations attribuées. En résultat, Adapty fournit des métriques au niveau de la campagne telles que les installations, les revenus, la LTV et le ROAS dans un tableau de bord analytique unifié. Vous pouvez analyser les cohortes, suivre les performances dans le temps et prendre des décisions d'optimisation basées sur les données — sans avoir à réconcilier manuellement des données provenant de sources différentes. :::tip Les liens de suivi peuvent également inclure des paramètres personnalisés, ce qui permet à votre application de gérer les [deep links différés](ua-deferred-data) et de réagir aux données de campagne lors du traitement de l'événement d'installation. ::: --- # File: user-acquisition --- --- title: "Premiers pas avec Adapty Attribution" description: "Connectez-vous à Adapty Attribution pour combiner les dépenses publicitaires et les revenus d'abonnement et voir toute l'économie de votre app en un seul endroit." --- Adapty Attribution vous permet de connecter vos dépenses publicitaires aux revenus d'abonnement dans les campagnes web-to-app, pour avoir une vue complète de l'économie de votre app en un seul endroit. Pour voir vos données de revenus dans Adapty Attribution, vous devez d'abord activer l'intégration dans l'Adapty Dashboard. Aucune clé API, token ou identifiant n'est nécessaire. Il suffit de mettre à jour et configurer le SDK Adapty. :::important Adapty Attribution est disponible avec : - iOS, Android et Flutter SDK version 3.9.1 ou supérieure. - React Native et Capacitor SDK version 3.10.0 ou supérieure. - Unity SDK version 3.12.0 ou supérieure. - Kotlin Multiplatform SDK version 3.15.0 ou supérieure. ::: ## Avant de commencer \{#before-you-start\} Pour connecter vos données de revenus aux performances de vos campagnes, laissez Adapty suivre vos achats : - Si vous **avez déjà des achats intégrés implémentés avec Adapty**, vous n'avez rien d'autre à faire à cette étape. - Si vous **n'avez pas encore d'achats intégrés et souhaitez utiliser Adapty**, suivez les étapes du [guide de démarrage rapide](quickstart) pour déléguer la gestion des achats à Adapty. - Si vous **avez déjà des achats intégrés implémentés sans Adapty** et ne prévoyez pas de migrer vers Adapty, [installez le SDK Adapty pour votre plateforme en mode observateur](implement-observer-mode). À cette étape, il vous suffit d'ajouter le SDK à votre projet, de l'activer avec le mode observateur activé, et de signaler les transactions. Cette configuration active l'attribution web-to-app : - Lorsque des utilisateurs installent votre app, le SDK Adapty récupère les détails d'installation depuis les paramètres du lien, ce qui permet à Adapty Attribution d'obtenir les informations de campagne. - Le SDK Adapty est informé de tous les événements liés aux revenus dans l'app et peut les attribuer aux campagnes web. ## Étape 1. Ouvrir Adapty Attribution \{#step-1-open-adapty-attribution\} :::important Si **Attribution** n'apparaît pas quand vous cliquez sur le logo Adapty, videz les cookies et les données du site adapty.io dans les paramètres de votre navigateur, puis rechargez la page. ::: Cliquez sur le logo Adapty dans l'en-tête et choisissez **Attribution**. Les événements d'abonnement commencent à affluer automatiquement dans Adapty Attribution. Les données de campagne apparaissent après avoir connecté une source de données à l'étape 2. Pour suspendre la transmission des événements, ouvrez **Integrations > Adapty** dans l'Adapty Dashboard et désactivez le bouton. ### Événements pris en charge \{#supported-events\} Par défaut, Adapty envoie trois groupes d'événements à Adapty Attribution : - Essais - Abonnements - Problèmes Consultez la [liste complète des événements pris en charge](events). ## Étape 2. Connecter votre plateforme publicitaire et ajouter des liens de suivi \{#step-2-connect-your-ad-platform-and-add-tracking-links\} Adapty utilise des liens de suivi pour associer les installations d'app aux données de campagne. Vous devez utiliser un lien de suivi comme URL de destination dans chaque campagne publicitaire que vous souhaitez mesurer dans Adapty Attribution. Si vous diffusez des annonces sur plusieurs plateformes, configurez des liens de suivi pour chaque plateforme séparément. Adapty fonctionne de deux façons avec les plateformes publicitaires : - **Intégrations natives (Meta Ads, TikTok Ads).** Adapty se connecte directement à la plateforme publicitaire. Les liens de suivi sont générés automatiquement et les paramètres de campagne sont remplis dynamiquement en fonction de l'endroit où le lien est utilisé. Vous pouvez utiliser le même lien dans différentes campagnes, ensembles de publicités ou créations, et Adapty recevra automatiquement les données de campagne et les dépenses publicitaires correctes. - **Liens de suivi uniquement (toutes les autres plateformes publicitaires).** Adapty ne se connecte pas à la plateforme publicitaire. Les liens de suivi sont créés manuellement et tous les paramètres de campagne doivent être définis explicitement lors de la création du lien. Les données de dépenses publicitaires ne sont pas disponibles pour ces plateformes. <Tabs> <TabItem value="meta" label="Meta Ads" default> Pour créer un lien de suivi pour Meta Ads : 1. Accédez à [Integrations > Meta](https://app.adapty.io/ua/integrations/facebook/accounts) dans l'Adapty Attribution Dashboard et cliquez sur **Continue with Facebook**. 2. Connectez-vous avec votre compte Facebook et cliquez sur **Continue**. 3. Vérifiez les autorisations demandées et cliquez sur **Save**. 4. Passez à l'onglet **Web campaigns** et cliquez sur **Create campaign**. Sélectionnez l'app et cliquez sur **Save**. 5. Dans l'onglet **General**, développez la section **iOS** et/ou **Android** et collez les URL d'application App Store et/ou Google Play. Ensuite, cliquez sur **Save**. 6. Copiez la valeur du champ **Click link** pour **un seul lien** ou pour un lien spécifique à une plateforme. Ensuite, dans Meta Ads Manager, ouvrez votre annonce et collez ce lien comme URL de destination. :::important Dans le champ **Website URL**, collez `https://api-ua.adapty.io/api/v1/attribution/click`. Collez le reste du lien dans le champ **URL parameters** de la section **Tracking**. Cela aidera votre annonce Meta à être approuvée. Voir plus de [recommandations sur la configuration de vos annonces dans Meta Ads Manager](meta-create-campaign). ::: 7. Désormais, lorsque vous lancez votre annonce dans Meta Ads, ses données seront disponibles pour analyse dans le tableau de bord Adapty Attribution. </TabItem> <TabItem value="tiktok" label="TikTok for Business"> Pour créer un lien de suivi pour TikTok for Business : 1. Accédez à [Integrations > TikTok Ads](https://app.adapty.io/ua/integrations/tiktok/accounts) dans l'Adapty Attribution Dashboard et cliquez sur **Continue with TikTok**. 2. Connectez-vous avec votre compte TikTok et cliquez sur **Continue**. 3. Vérifiez les autorisations demandées et cliquez sur **Save**. 4. Passez à l'onglet **Web campaigns** et cliquez sur **Create campaign**. Sélectionnez l'app et cliquez sur **Save**. 5. Dans l'onglet **General**, développez la section **iOS** et/ou **Android** et collez les URL d'application App Store et/ou Google Play. Ensuite, cliquez sur **Save**. 6. Copiez la valeur du champ **Click link** pour **un seul lien** ou pour un lien spécifique à une plateforme. Ensuite, dans TikTok Ads Manager, lors de la création de votre annonce, collez cette valeur dans le champ **Tracking URL** sous la section **Advanced Settings**. Cela permettra à Adapty de relier les installations et les achats aux annonces dans TikTok. Consultez le [guide de configuration de votre campagne dans TikTok Ads](tiktok-create-campaign). 7. Désormais, lorsque vous lancez votre annonce dans TikTok for Business, ses données seront disponibles pour analyse dans le tableau de bord Adapty Attribution. </TabItem> <TabItem value="others" label="Autres plateformes publicitaires"> Pour créer un lien de suivi pour d'autres plateformes publicitaires : 1. Dans le tableau de bord Adapty Attribution, accédez à **Tracking links** depuis le menu latéral. Cliquez ensuite sur **Create link**. 2. Sélectionnez votre app dans la liste et cliquez sur **Next**. 3. Renseignez les paramètres du lien pour le faire correspondre à la campagne et à l'annonce que vous souhaitez suivre. 4. Par défaut, vous créez un One Link. Il détecte automatiquement la plateforme de l'utilisateur et le redirige vers l'App Store ou Google Play après avoir suivi le clic. Si vous préférez utiliser des URL de redirection distinctes pour chaque plateforme, décochez la case **One Link** et fournissez manuellement des liens de store spécifiques à chaque plateforme. 5. Cliquez sur **Create**. 6. Ouvrez la page de votre lien de suivi et copiez le **Click link** depuis l'une des sections : - **One link** – utilisez ce lien pour suivre les clics et rediriger automatiquement les utilisateurs vers le bon store. - **iOS link** ou **Android link** — versions spécifiques à chaque plateforme, optionnelles, si vous souhaitez des liens séparés pour chaque store. 7. Accédez à votre plateforme publicitaire et collez le lien dans votre annonce comme URL de destination. </TabItem> </Tabs> ## Étape 3. Lancer votre campagne web-to-app et consulter les résultats \{#step-3-launch-your-web-to-app-campaign-and-view-results\} Une fois votre campagne lancée et les utilisateurs qui commencent à installer votre app, Adapty commence à attribuer les installations et les revenus à vos campagnes. Dans le [tableau de bord analytique Adapty Attribution](ua-analytics), vous verrez des métriques au niveau de la campagne, notamment : - Installations et conversions - Revenus d'abonnement et d'achat - Ventilation des performances par plateforme publicitaire, campagne, ensemble de publicités et création Les métriques apparaissent dès que les événements d'installation et de revenus sont reçus depuis votre app. Les données de dépenses publicitaires sont disponibles pour les plateformes avec des intégrations natives. ## En savoir plus \{#learn-more\} Poursuivez avec la documentation approfondie sur les analyses Adapty Attribution et les guides pratiques pour mener des campagnes sur les principales plateformes publicitaires : - [**Analyses dans Adapty Attribution**](ua-analytics) : Découvrez comment utiliser efficacement le tableau de bord analytique. - [**Métriques dans Adapty Attribution**](ua-metrics) : Explorez les métriques disponibles pour l'analyse de l'acquisition utilisateur. - [**Intégrations**](ua-integrations) : Consultez les plateformes publicitaires et les intégrations prises en charge par Adapty Attribution. - [**Lancer des annonces dans Meta Ads Manager**](meta-create-campaign) : Apprenez à configurer et lancer des campagnes dans Meta Ads Manager. - [**Lancer des annonces dans TikTok for Business**](tiktok-create-campaign) : Apprenez à configurer et lancer des campagnes dans TikTok for Business. --- # File: ua-analytics --- --- title: "Analytics dans Adapty Attribution" description: "Consultez les analyses de l'application dans Adapty Attribution." --- [Analytics](https://app.adapty.io/ua/analytics) est une section du tableau de bord Adapty Attribution qui vous permet de consulter plusieurs métriques de campagne en un seul endroit. Vous pouvez personnaliser les graphiques à afficher et visualiser les données de toutes vos campagnes en même temps. La section Analytics comporte deux onglets : - **Analytics** : un tableau de vos métriques de campagne basé sur des cohortes. - **Charts** : des graphiques en courbes pour des métriques individuelles dans le temps. ## Métriques \{#metrics\} Adapty Attribution fournit des **métriques** complètes pour mesurer les performances des campagnes et le comportement des utilisateurs. Ces métriques sont disponibles sous forme de valeurs standard, les métriques clés étant également proposées en **métriques de cohorte** pour une analyse temporelle des groupes d'utilisateurs. Consultez la liste complète des métriques [ici](ua-metrics). ## Personnaliser les métriques affichées \{#customize-which-metrics-to-show\} Vous pouvez personnaliser les métriques à afficher ainsi que leur ordre. Pour cela, cliquez sur le nom du preset actuel (par défaut **Default**) en haut à droite, sélectionnez **Edit columns**, puis supprimez les graphiques dont vous n'avez pas besoin, ajoutez-en d'autres ou réorganisez-les par glisser-déposer. Pour les métriques de cohorte, vous pouvez ajouter une ou plusieurs cohortes à la fois. Sélectionnez-les parmi les cohortes existantes ou créez-en des personnalisées. Vous pouvez également enregistrer les vues que vous utilisez le plus souvent comme presets pour basculer rapidement de l'une à l'autre. Cliquez sur le nom du preset actuel et cliquez sur l'icône **Save**, ou, dans la fenêtre **Edit columns**, cliquez sur **Save as preset**. ## Contrôles \{#controls\} Sur la page **Analytics**, vous disposez de quatre contrôles principaux : - **Time ranges** : voir [plus](controls-filters-grouping-compare-proceeds#set-the-date-range). - **Filters** : filtrez par métriques pour n'afficher que les valeurs supérieures ou inférieures à un certain seuil. - **Group by** : regroupez par paramètres de campagne (comme l'identifiant de campagne ou le pays) ou par périodes, afin de mieux organiser les résultats. - **Store commission and taxes** : voir [plus](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). ## Ensembles de filtres \{#filter-sets\} Les ensembles de filtres vous permettent d'enregistrer un groupe de filtres et de basculer entre eux en un seul clic. Utilisez-les pour conserver les vues que vous consultez le plus souvent, comme « Campagnes au-dessus de 1 000 $ de dépenses » ou « iOS uniquement ». Sous les contrôles de filtres principaux, chaque ensemble de filtres enregistré apparaît sous forme de puce. Cliquez sur une puce pour appliquer ses filtres, ou cliquez sur le **×** d'une puce pour la supprimer. L'ensemble actif est mis en surbrillance. Pour enregistrer les filtres actuels comme nouvel ensemble : 1. Configurez les filtres que vous souhaitez enregistrer. 2. Cliquez sur **+** à la fin de la ligne des ensembles de filtres. 3. Saisissez un nom et cliquez sur **Save**. ## Graphiques \{#charts\} L'onglet **Charts** affiche un graphique en courbes pour une seule métrique sur la période sélectionnée. Utilisez la navigation de gauche pour passer d'une métrique à l'autre. Métriques disponibles dans les graphiques : - Spend - Impressions - Clicks - CPC - CPM - CTR - Installs - Total Revenue - ARPU - CPI - ARPPU - ROAS - ICR - Cost Per Trial - Cost Per Subscription La même plage de temps, le même regroupement, les mêmes filtres et ensembles de filtres s'appliquent sur les onglets **Analytics** et **Charts**. ## Exporter les données \{#export-data\} Pour analyser les données brutes des analytics, vous pouvez les exporter au format CSV en cliquant sur le bouton **Export**. --- # File: ua-metrics --- --- title: "Métriques dans Adapty Attribution" description: "Découvrez les métriques disponibles dans Adapty Attribution." --- Adapty Attribution fournit des **métriques** complètes pour mesurer la performance des campagnes et le comportement des utilisateurs. Ces métriques sont disponibles en tant que valeurs standard, certaines étant également proposées en tant que **métriques de cohorte** pour une analyse temporelle des groupes d'utilisateurs. ## Métriques standard \{#standard-metrics\} | **Métrique** | Description | Cohorte | |-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------| | **Spend** | La somme du coût de chaque clic d'un client sur votre annonce. | Non | | **Impressions** | Le nombre de fois où votre annonce a été affichée durant la période sélectionnée. | Non | | **Clicks** | Le nombre de fois où des utilisateurs ont cliqué sur votre annonce durant la période de rapport. | Non | | **CPI** | **CPI (Cost per Install)** est le montant que vous payez par installation. <br/>**Formule** : `Spend / Installs` | Non | | **CPC** | **CPC (Cost per Click)** est le montant que vous payez par clic sur votre annonce. <br/>**Formule** : `Spend / Clicks` | Non | | **CPM** | **CPM (Cost per Mille)** est le montant que vous payez pour mille impressions publicitaires. <br/>**Formule** : `Spend / (Impressions / 1000)` | Non | | **ICR** | **ICR (Install Conversion Rate)** est le pourcentage de clics sur l'annonce ayant abouti à une installation. <br/>**Formule** : `(Installs / Clicks) × 100%` | Non | | **IPM** | **IPM (Installs per Mille)** représente le nombre d'installations pour mille impressions publicitaires. <br/>**Formule** : `(Installs / Impressions) × 1000` | Non | | **CTR** | **CTR (Click-Through Rate)** est le pourcentage d'impressions ayant abouti à des clics. <br/>**Formule** : `(Clicks / Impressions) × 100%` | Non | | **Inline link clicks** | Le nombre de fois où des utilisateurs ont cliqué sur des liens intégrés dans vos créations publicitaires ou votre page d'application. | Non | | **Cost per inline link click** | Le montant moyen que vous payez par clic sur un lien intégré. <br/>**Formule** : `Spend / Inline Link Clicks` | Non | | **Inline link click CTR** | Le pourcentage d'impressions ayant abouti à des clics sur des liens intégrés. <br/>**Formule** : `(Inline Link Clicks / Impressions) × 100%` | Non | | **Installs** | Le nombre total d'utilisateurs ayant installé votre application (y compris les réinstallations) durant la période de rapport. | Non | | **Revenue** | Le montant total généré par les achats associés à cette campagne (avant commission du store) durant la période sélectionnée. | Oui | | **ROAS** | **ROAS (Return on Ad Spend)** est le revenu généré par vos annonces divisé par les dépenses publicitaires, exprimé en pourcentage. <br/> **Formule** : `(Revenue / Spend) × 100% si Spend > 0, sinon 0% ` | Oui | | **ARPU** | **ARPU (Average Revenue per User)** est le revenu moyen par utilisateur dans la cohorte. <br/>**Formule** : `Revenue / Users` | Oui | | **LTV** | **LTV (Lifetime Value)** est le revenu moyen attribué à un utilisateur sur toute sa durée de vie. <br/>**Formule** : `Revenue / Installs` | Non | | **Cost per trial** | Le montant moyen que vous payez par essai démarré. <br/>**Formule** : `Spend / Count trial started` | Non | | **Cost per subscription** | Le montant moyen que vous payez par abonnement souscrit. <br/>**Formule** : `Spend / Count subscription started` | Non | | **Count subscription events** | Le groupe de métriques comptabilisant les événements liés aux abonnements sur la période de rapport. Les métriques sont : <br/>- Count subscription started<br/>-Count subscription renewed<br/>-Count subscription renewal cancelled<br/>-Count subscription renewal reactivated<br/>-Count subscription expired<br/>-Count [subscription deferred](https://adapty.io/glossary/subscription-purchase-deferral/)<br/>-Count subscription refunded | Oui | | **Count trial events** | Le groupe de métriques comptabilisant les événements liés aux essais sur la période de rapport. Les métriques sont : <br/>- Count trial started<br/>- Count trial converted<br/>- Count trial expired<br/>- Count trial renewal reactivated | Oui | | **Count billing issue detected** | Le nombre de problèmes de facturation détectés sur la période de rapport. | Oui | | **Count entered grace period** | Le nombre d'abonnements ayant entré un délai de grâce suite à des problèmes de facturation. | Oui | | **Count non-subscription events** | Le groupe de métriques comptabilisant les événements non liés aux abonnements sur la période de rapport. Les métriques sont : <br/>- Count non-subscription purchased<br/>-Count non-subscription refunded | Oui | | **Subscription events rate** | Métriques indiquant le taux d'événements liés aux abonnements par rapport aux installations de l'application durant la période de rapport. Les métriques sont : <br/>- Rate subscription started<br/>-Rate subscription renewed<br/>-Rate subscription renewal cancelled<br/>-Rate subscription renewal reactivated<br/>-Rate subscription expired<br/>-Rate [subscription deferred](https://adapty.io/glossary/subscription-purchase-deferral/)<br/>-Rate subscription refunded | Oui | | **Trial events rate** | Métriques indiquant le taux d'événements liés aux essais par rapport aux installations de l'application durant la période de rapport. Les métriques sont : <br/>- Rate trial started<br/>- Rate trial converted<br/>- Rate trial expired<br/>- Rate trial renewal reactivated | Oui | | **Rate billing issue detected** | Le taux de problèmes de facturation par rapport aux installations de l'application durant la période de rapport. | Oui | | **Rate entered grace period** | Le taux d'abonnements ayant entré un délai de grâce par rapport aux installations de l'application durant la période de rapport. | Oui | | **Non-subscription events rate** | Métriques indiquant le taux d'événements non liés aux abonnements par rapport aux installations de l'application durant la période de rapport. Les métriques sont : <br/>- Rate non-subscription purchased<br/>-Rate non-subscription refunded | Oui | ## Métriques prédites \{#predicted-metrics\} Les métriques prédites projettent les performances futures d'une cohorte à partir des données historiques de l'application. Elles sont disponibles pour plusieurs périodes de cohorte, notamment D30, D60, D90, D180 et D360, ainsi que des périodes personnalisées que vous pouvez ajouter en jours. Pour plus d'informations sur le calcul de ces valeurs, consultez [Métriques prédites dans Adapty Attribution](ua-predicted-metrics). | **Métrique** | Description | Cohorte | |---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------| | **pRevenue** | Revenu total prédit qu'une cohorte devrait générer d'ici l'horizon cible. Modélisé à partir de la rétention historique des cohortes de l'application. | Oui | | **pROAS** | Retour sur les dépenses publicitaires prédit sur le même horizon. **Formule** : `(pRevenue / Spend) × 100%` | Oui | | **pAdProfit** | Revenu prédit net des dépenses publicitaires sur l'horizon. **Formule** : `pRevenue − Spend` | Oui | | **pARPU** | Revenu moyen prédit par installation sur l'horizon (LTV prédit). **Formule** : `pRevenue / Installs` | Oui | | **pARPPU** | Revenu moyen prédit par utilisateur payant sur l'horizon. **Formule** : `pRevenue / paying users at d{N}`, où `d{N}` correspond à l'horizon sélectionné. | Oui | --- # File: ua-predicted-metrics --- --- title: "Métriques prédictives dans Adapty Attribution" description: "Prévoyez les revenus, le ROAS, les bénéfices publicitaires et la LTV pour les cohortes dans Adapty Attribution." --- :::important Cet article traite des prédictions dans Adapty Attribution uniquement. Pour la LTV et les revenus prédits sur la page d'analyse par cohortes, consultez [Prédictions dans les cohortes](predicted-ltv-and-revenue). ::: Adapty Attribution projette les revenus futurs et l'économie unitaire pour chaque cohorte, ce qui vous permet de comparer des campagnes avant qu'elles aient eu le temps de mûrir. Les prédictions sont générées à partir des données historiques de cohortes de l'application et sont mises à jour quotidiennement. Elles sont particulièrement utiles pour évaluer les cohortes récentes qui n'ont pas encore complété de longs cycles d'abonnement. ## Métriques prédictives \{#predicted-metrics\} | **Métrique** | Description | |---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **pRevenue** | Revenu total prédit qu'une cohorte devrait générer d'ici l'horizon cible. Modélisé à partir de la rétention historique des cohortes de l'application. | | **pROAS** | Retour sur les dépenses publicitaires prédit sur le même horizon. **Formule** : `(pRevenue / Spend) × 100%` | | **pAdProfit** | Revenu prédit net des dépenses publicitaires sur l'horizon. **Formule** : `pRevenue − Spend` | | **pARPU** | Revenu moyen prédit par installation sur l'horizon (LTV prédite). **Formule** : `pRevenue / Installs` | | **pARPPU** | Revenu moyen prédit par utilisateur payant sur l'horizon. **Formule** : `pRevenue / paying users at d{N}`, où `d{N}` correspond à l'horizon sélectionné. | `pRevenue` est la valeur de base. Les quatre autres métriques en sont dérivées à partir des données de cohorte observées — dépenses, installations et utilisateurs payants — sans faire tourner le modèle séparément. Chaque métrique prédictive est disponible sur plusieurs périodes de cohorte : D0, D3, D7, D30, D60, D90, D180 et D360. Vous pouvez également ajouter une période personnalisée en jours. La période définit jusqu'où dans le futur la valeur est projetée à partir de la date d'installation de la cohorte. ## Comment les prédictions sont calculées \{#how-predictions-are-calculated\} Les prédictions sont construites à partir des cohortes historiques propres à chaque application. Le modèle mesure la progression des revenus des cohortes passées après leur jour de référence, puis projette la cohorte actuelle vers l'avenir en suivant la même trajectoire. ### Jour de référence \{#baseline-day\} Les prédictions ne deviennent disponibles qu'une fois que la cohorte a atteint son jour de référence. Le jour de référence est le premier jour où 90 % des revenus initiaux d'une cohorte ont généralement été reçus. Les revenus initiaux comprennent les débuts d'abonnement, les conversions de période d'essai et les achats hors abonnement ; les renouvellements ne sont pas comptabilisés dans ce seuil. Le jour de référence dépend de la durée de l'essai et du mix produit de l'application : - **Applications sans période d'essai** : Le jour de référence se situe généralement dans les premiers jours suivant l'installation. - **Applications avec des essais courts** : Le jour de référence arrive généralement peu après la conversion de l'essai. - **Applications avec des essais plus longs** : Le jour de référence peut se situer une semaine ou plus après l'installation, car la plupart des revenus initiaux ne se matérialisent qu'une fois l'essai terminé. ### Projection par type d'abonnement \{#projection-by-subscription-type\} Au jour de référence, les revenus initiaux de la cohorte sont répartis en cinq catégories — abonnements mensuels, annuels, hebdomadaires et trimestriels, plus les achats hors abonnement. Chaque catégorie est projetée indépendamment vers l'avenir à l'aide d'une trajectoire mesurée à partir des cohortes passées de l'application. Le modèle accorde plus de poids aux cohortes récentes et aux cohortes ayant une économie comparable, comme un revenu par transaction similaire et un mix produit similaire. Une prédiction reflète donc la performance réelle des cohortes les plus récentes et les plus similaires de l'application. ## Quand les prédictions sont disponibles \{#when-predictions-are-available\} Une prédiction n'est affichée que si la cohorte dispose de suffisamment de données pour la prendre en charge. Lorsqu'une valeur ne peut pas être produite, la colonne affiche un tiret cadratin (`—`) à la place. Raisons fréquentes pour lesquelles une prédiction n'est pas disponible : - **La cohorte n'a pas atteint son jour de référence** : Le modèle a besoin que les revenus initiaux de la cohorte se stabilisent avant de pouvoir projeter vers l'avenir. - **Données historiques insuffisantes pour l'application** : Si l'application ne dispose pas de suffisamment de cohortes passées pour le type d'abonnement concerné, le modèle ne peut pas établir des taux de rétention fiables. Les prédictions sont recalculées quotidiennement avec les dernières données transactionnelles, de sorte que les valeurs d'une même cohorte peuvent évoluer au fur et à mesure que de nouveaux revenus sont observés. --- # File: ua-tracking-links --- --- title: "Liens de suivi dans Adapty Attribution" description: "Suivez vos campagnes et mesurez leur succès où que ce soit." --- Les liens de suivi vous permettent de mesurer la provenance de vos utilisateurs et de relier les installations à vos campagnes publicitaires. Quand quelqu'un clique sur votre annonce, Adapty enregistre le clic et l'associe ensuite à l'événement d'installation envoyé par le SDK. Vous pouvez ainsi voir quels canaux, campagnes, ensembles d'annonces et annonces génèrent le plus de revenus sur votre [page Analytics](ua-analytics). Vous pouvez créer deux types de liens de suivi : - **One link** — un lien universel qui détecte automatiquement la plateforme de l'utilisateur, enregistre le clic et le redirige vers l'App Store ou Google Play. - **Liens spécifiques au store** — des liens ciblés par plateforme qui enregistrent le clic et redirigent automatiquement les utilisateurs vers l'App Store ou Google Play. Vous pouvez également y ajouter des paramètres de deep link différé. ## Créer des liens de suivi \{#create-tracking-links\} Pour créer un lien de suivi : 1. Dans le tableau de bord Adapty Attribution, accédez à **Tracking links** depuis le menu latéral. Cliquez ensuite sur **Create link**. 2. Sélectionnez votre application dans la liste et cliquez sur **Next**. 3. Renseignez les paramètres du lien pour l'associer à la campagne et à l'annonce que vous souhaitez suivre. | Paramètre | Description | |-------------------|----------------------------------------------------------------------------------------------------| | **Name** | Le nom interne du lien de suivi. | | **Channel** | La source de trafic, par exemple Meta, Reddit ou TikTok. Sert à regrouper les campagnes dans l'analytics. | | **Campaign ID** | L'identifiant unique de la campagne dans votre plateforme publicitaire. | | **Campaign name** | Le nom lisible de la campagne. | | **Ad set ID** | L'identifiant unique de l'ensemble d'annonces (groupe d'annonces) dans votre plateforme publicitaire. | | **Ad set name** | Le nom de l'ensemble d'annonces. | | **Ad ID** | L'identifiant unique du créatif publicitaire. | | **Ad name** | Le nom du créatif ou de la variante publicitaire. | 4. Par défaut, vous créez un One Link. Il détecte automatiquement la plateforme de l'utilisateur et le redirige vers l'App Store ou Google Play après avoir enregistré le clic. Si vous préférez utiliser des URL de redirection distinctes pour chaque plateforme, décochez la case **One Link** et renseignez manuellement les liens de store spécifiques à chaque plateforme. 5. Cliquez sur **Create**. 6. Ouvrez la page de votre lien de suivi et copiez le **Click link** depuis l'une des sections : - **One link** — utilisez ce lien pour suivre les clics et rediriger automatiquement les utilisateurs vers le store approprié. - **iOS link** ou **Android link** — versions optionnelles spécifiques à chaque plateforme si vous souhaitez des liens séparés pour chaque store. :::tip Vous pouvez également définir des paramètres de lien supplémentaires pour [travailler avec des données différées](ua-deferred-data). Par exemple, vous pouvez implémenter le deep linking différé. ::: 7. Accédez à votre plateforme publicitaire et collez le lien dans votre annonce en tant qu'URL de destination. Les installations de l'application seront alors associées aux annonces et campagnes dont elles sont issues, ce qui vous permet de mesurer l'efficacité de vos campagnes sur la page **Analytics**. --- # File: ua-deferred-data --- --- title: "Deeplinks différés dans Adapty Attribution" description: "Configurez des deeplinks différés dans Adapty Attribution." --- Les deeplinks différés vous permettent de transmettre des données personnalisées à votre application lorsque des utilisateurs l'installent après avoir cliqué sur vos publicités. Par exemple, vous pouvez les rediriger vers un endroit spécifique de votre application dès qu'ils l'installent et la lancent. Voici comment cela fonctionne : 1. Quand un utilisateur clique sur votre publicité, Adapty enregistre les données du clic. 2. Quand Adapty détecte l'événement d'installation, il récupère les données différées à partir du clic. 3. Après que l'utilisateur a installé votre application et qu'elle est lancée pour la première fois, Adapty récupère les données stockées et votre application reçoit les paramètres personnalisés, ce qui vous permet de réagir à différentes valeurs dans le code de l'application. Adapty prend en charge les paramètres de données différées suivants : - `ios_deferred_data` - `android_deferred_data` - `deferred_data_sub[1-10]` Pour ajouter des paramètres de données différées, ajoutez-les à votre lien dans les paramètres de votre campagne : 1. Ouvrez votre campagne depuis la page **Integrations -> Meta/TikTok Ads**. Ou bien, ouvrez votre lien de suivi depuis la page **Tracking links**. Copiez le lien de clic que vous utiliserez dans votre campagne. 2. Dans votre plateforme publicitaire (Meta, TikTok, Google Ads, etc.), collez le lien dans le champ URL de destination de l'annonce, puis ajoutez-y les paramètres de données différées en tant que paramètres de requête supplémentaires — chacun précédé de `&`. Par exemple, pour envoyer les utilisateurs iOS vers un écran « Welcome » après l'installation, ajoutez `&ios_deferred_data=welcome`. L'URL de destination finale ressemblera à ceci : ``` https://api-ua.adapty.io/api/v1/attribution/click?adpt_cid=__ADAPTY__ID__&ios_deferred_data=welcome&campaign_id=__CAMPAIGN_ID__&adset_id=__AID__&ad_id=__CID__&campaign_name=__CAMPAIGN_NAME__&adset_name=__AID_NAME__&ad_name=__CID_NAME__&redirect_url=__APP_LINK__ ``` 3. Réagissez aux paramètres dans le code de votre application. Notez que les paramètres de données différées se trouvent dans le paramètre `payload`, et que `payload` est un JSON échappé — vous devez donc le parser dans le code de votre application. Par exemple, voici comment gérer les installations où `ios_deferred_data` vaut `welcome` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers Adapty.delegate = self nonisolated func onInstallationDetailsSuccess(_ details: AdaptyInstallationDetails) { guard let payloadStr = details.payload, let data = payloadStr.data(using: .utf8), let payload = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let deeplink = payload["ios_deferred_data"] as? String, deeplink == "welcome" else { return } DispatchQueue.main.async { print("Navigate to welcome screen") // navigate to your screen here } } ``` </TabItem> <TabItem value="android" label="Kotlin"> ```kotlin showLineNumbers Adapty.setOnInstallationDetailsListener(object : OnInstallationDetailsListener { override fun onInstallationDetailsSuccess(details: AdaptyInstallationDetails) { details.payload?.let { runCatching { val json = JSONObject(it) if (json.optString("android_deferred_data") == "welcome") { println("Navigate to welcome screen") // navigate here } }.onFailure(Throwable::printStackTrace) } } }) ``` </TabItem> <TabItem value="rn" label="React Native" default> ```typescript showLineNumbers adapty.addEventListener('onInstallationDetailsSuccess', details => { // Parse the payload JSON and navigate to welcome screen if needed try { if (details.payload) { const payload = JSON.parse(details.payload); if (payload.ios_deferred_data === 'welcome') { // Navigate to welcome screen // Replace with your app's navigation logic // For example, using React Navigation: // navigation.navigate('Welcome'); console.log('Navigate to welcome screen'); } } } catch (error) { console.error('Error parsing installation details payload:', error); } }); ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers Adapty().onUpdateInstallationDetailsSuccessStream.listen((details) { final payloadStr = details.payload; if (payloadStr == null) return; final payload = json.decode(payloadStr) as Map<String, dynamic>; if (payload['ios_deferred_data'] == 'welcome') { print('Navigate to welcome screen'); } }); ``` </TabItem> </Tabs> --- # File: ua-attribution-data --- --- title: "Recevoir les données d'attribution dans votre application" description: "Accédez aux données d'attribution de campagne dans votre application après qu'Adapty a associé une installation à une campagne." --- Lorsqu'Adapty associe une installation à une campagne, il renvoie les données d'attribution à votre application via le callback `onInstallationDetailsSuccess`. Utilisez ces données pour personnaliser l'expérience utilisateur en fonction du canal ou de la campagne qui a généré l'installation. Les données d'attribution sont renvoyées sous forme d'objet `attribution` imbriqué dans le champ `payload`. Il contient les champs suivants : | Champ | Description | |---|---| | `channel` | Canal d'acquisition (ex. `facebook`, `tiktok`, `google`, `organic`) | | `campaign_id` | Identifiant de la campagne | | `campaign_name` | Nom de la campagne | | `adset_id` | Identifiant du groupe d'annonces | | `adset_name` | Nom du groupe d'annonces | | `ad_id` | Identifiant de l'annonce / du visuel | | `ad_name` | Nom de l'annonce / du visuel | Tous les champs sont optionnels. Pour les installations organiques ou lorsque l'attribution n'a pas pu être déterminée, le champ `payload` ne contient pas l'objet `attribution`. Pour lire les données d'attribution dans votre application : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers Adapty.delegate = self nonisolated func onInstallationDetailsSuccess(_ details: AdaptyInstallationDetails) { guard let payloadDict = details.payload?.dictionary, let attribution = payloadDict["attribution"] as? [String: Any] else { return } let channel = attribution["channel"] as? String let campaignName = attribution["campaign_name"] as? String let adName = attribution["ad_name"] as? String print("Channel: \(channel ?? "organic")") } ``` </TabItem> <TabItem value="android" label="Kotlin"> ```kotlin showLineNumbers Adapty.setOnInstallationDetailsListener(object : OnInstallationDetailsListener { override fun onInstallationDetailsSuccess(details: AdaptyInstallationDetails) { val payloadStr = details.payload ?: return runCatching { val payload = JSONObject(payloadStr) val attribution = payload.optJSONObject("attribution") ?: return val channel = attribution.optString("channel") val campaignName = attribution.optString("campaign_name") val adName = attribution.optString("ad_name") println("Channel: $channel") }.onFailure(Throwable::printStackTrace) } }) ``` </TabItem> <TabItem value="rn" label="React Native"> ```typescript showLineNumbers adapty.addEventListener('onInstallationDetailsSuccess', details => { try { if (!details.payload) return; const payload = JSON.parse(details.payload); const attribution = payload.attribution; if (!attribution) return; const channel = attribution.channel; const campaignName = attribution.campaign_name; const adName = attribution.ad_name; console.log('Channel:', channel ?? 'organic'); } catch (error) { console.error('Error parsing payload:', error); } }); ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers Adapty().onUpdateInstallationDetailsSuccessStream.listen((details) { final payloadStr = details.payload; if (payloadStr == null) return; final payload = json.decode(payloadStr) as Map<String, dynamic>; final attribution = payload['attribution'] as Map<String, dynamic>?; if (attribution == null) return; final channel = attribution['channel'] as String?; final campaignName = attribution['campaign_name'] as String?; final adName = attribution['ad_name'] as String?; print('Channel: ${channel ?? 'organic'}'); }); ``` </TabItem> </Tabs> --- # File: ua-integrations --- --- title: "Intégrations dans Adapty Attribution" description: "Découvrez les intégrations disponibles pour Adapty Attribution." --- ## Réseau \{#network\} <CustomDocCardList ids={['ua-facebook', 'ua-tiktok']} /> ## Analytics \{#analytics\} <CustomDocCardList ids={['ua-funnelfox']} /> ## Analytics \{#analytics\} <CustomDocCardList ids={['ua-funnelfox']} /> ## Export \{#export\} <CustomDocCardList ids={['ua-custom-s3', 'ua-amazon-s3', 'ua-google-cloud-storage']} /> --- # File: ua-facebook --- --- title: "Intégrer Meta Ads avec Adapty Attribution" description: "Connectez Meta Ads à Adapty Attribution pour suivre et optimiser les performances de vos campagnes sur Facebook, Instagram, Messenger et Audience Network." --- L'intégration Meta d'Adapty Attribution vous permet de suivre et d'optimiser les performances de vos campagnes sur Facebook, Instagram, Messenger et Audience Network. :::tip Consultez notre [guide de configuration des publicités dans Meta Ads Manager](meta-create-campaign). ::: ## Étape 1. Connecter votre compte Facebook \{#step-1-connect-your-facebook-account\} Pour connecter Meta Ads à Adapty Attribution, rendez-vous dans **Integrations > Meta** depuis le menu de gauche. Deux options s'offrent à vous : - **Continue with Facebook** : connexion via OAuth. Utilisez cette option si vous vous connectez à Meta Ads Manager avec votre compte Facebook personnel ou professionnel. - **Add system token** : connexion via un token système permanent. Utilisez cette option si votre organisation gère des comptes publicitaires via un utilisateur système Meta Business. <Tabs> <TabItem value="oauth" label="Continue with Facebook"> :::important Assurez-vous que votre compte Facebook a accès aux campagnes et pixels dont vous avez besoin. ::: 1. Cliquez sur **Continue with Facebook**. 2. Connectez-vous avec votre compte Facebook et cliquez sur **Continue**. 3. Vérifiez les autorisations demandées et cliquez sur **Save**. </TabItem> <TabItem value="system" label="Add system token"> Générez un [token d'accès utilisateur système](https://developers.facebook.com/documentation/ads-commerce/marketing-api/collaborative-ads/managed-partner-ads/api-guide/prerequisites/generate-access-token-system-user) dans les paramètres Meta Business, puis ajoutez-le à Adapty Attribution. :::important Avant de commencer, vous devez disposer d'un [utilisateur système](https://www.facebook.com/business/help/503306463479099) dans votre portfolio Meta Business, avec les comptes publicitaires à suivre déjà associés. Vous devez également avoir ajouté une application au portfolio — c'est cette application que vous sélectionnez lors de la génération du token. ::: **Dans les paramètres Meta Business, générez le token :** 1. Accédez à **Business Settings**. 2. Sous **Users**, sélectionnez **System users**. 3. Sélectionnez votre utilisateur système, puis cliquez sur **Generate new token**. 4. Choisissez votre application dans le menu déroulant. 5. Dans la liste des autorisations, activez `ads_read`. C'est la seule autorisation dont Adapty Attribution a besoin pour lire vos données de campagne et d'annonce. 6. Cliquez sur **Generate token**. 7. Copiez le token et conservez-le en lieu sûr. Meta ne l'affiche qu'une seule fois. :::note Le paramètre **Token expiration** détermine la durée de validité de la connexion. Un token avec une date d'expiration doit être régénéré et reconnecté avant son expiration, faute de quoi l'attribution s'arrête. Un token sans expiration évite ce problème, mais constitue un identifiant de longue durée. Conservez-le en lieu sûr et révoquez-le s'il venait à être compromis. ::: **Dans Adapty Attribution, ajoutez le token :** 1. Cliquez sur **Add system token**. 2. Collez le token et cliquez sur **Connect**. </TabItem> </Tabs> Une fois cette étape terminée, tous vos comptes publicitaires seront ajoutés à Adapty Attribution. Vous pouvez ensuite passer à l'ajout de campagnes. ## Étape 2. Ajouter des campagnes \{#step-2-add-campaigns\} Pour ajouter une campagne Meta à Adapty Attribution et suivre les performances de vos publicités Meta dans Adapty : 1. Passez à l'onglet **Web Campaigns** et cliquez sur **Create configuration**. 2. Dans l'onglet **General**, développez la section **iOS** et/ou **Android** et collez les URLs de votre application sur l'App Store et/ou Google Play. 3. Copiez la valeur du champ **Click link**. Ensuite, dans Meta Ads Manager, ouvrez votre annonce et collez ce lien. Cela permettra à Adapty de relier les installations et achats aux annonces Meta. 4. Pour renvoyer les événements de conversion vers Meta, vous pouvez également associer vos pixels Meta à des campagnes dans Adapty Attribution. Pour ce faire, sélectionnez l'un de vos pixels existants dans le menu déroulant **Pixel**. Après avoir sélectionné un pixel, vous pouvez cliquer sur **Send test event** pour vérifier la connexion. ## Étape 3. Mapper les événements \{#step-3-map-events\} Pour renvoyer les événements de conversion vers Meta afin d'optimiser vos campagnes, vous devez configurer la correspondance des événements dans la section **Events names**. Cela permet à Adapty d'envoyer automatiquement les événements d'abonnement à votre pixel Meta lorsque les utilisateurs effectuent des actions dans votre application. Dans la section **Events names**, activez les événements que vous souhaitez suivre dans Meta Ads Manager. Pour chaque événement activé, sélectionnez l'événement Meta correspondant dans le menu déroulant ou définissez-en un personnalisé. Par défaut, Adapty associe ses événements aux événements standard de Meta. Cliquez sur **Save** pour appliquer votre configuration de correspondance des événements. ## Configuration avancée \{#additional-configuration\} ### Paramètres supplémentaires \{#additional-parameters\} Le champ **Additional parameter** vous permet d'ajouter des données personnalisées pour une analyse en dehors d'Adapty. C'est utile lorsque vous devez transmettre des données de campagne ou d'utilisateur spécifiques à des outils d'analyse externes ou à des partenaires d'attribution. Dans le champ **Additional parameter**, saisissez les données personnalisées à inclure dans votre suivi d'attribution. Le paramètre supplémentaire sera inclus dans toutes les données d'attribution envoyées à Meta et pourra être utilisé pour une analyse et une optimisation avancées des campagnes. Par exemple, si vous exécutez plusieurs variantes d'une même campagne, vous pouvez ajouter `variant=A` ou `variant=B` pour distinguer différentes approches créatives. :::important Les paramètres supplémentaires modifient le **Click link** que vous collez dans Meta Ads Manager. Si vous avez déjà copié ce lien et ajouté un paramètre personnalisé par la suite, veillez à copier et coller le lien mis à jour contenant le paramètre personnalisé. ::: <br/> ### Paramètres \{#settings\} L'onglet **Settings** contrôle la façon dont Adapty associe les actions des utilisateurs à vos campagnes Meta Ads. Ces paramètres définissent les fenêtres temporelles pour la correspondance d'attribution déterministe et probabiliste. Pour les configurer, accédez à l'onglet **Settings** dans la configuration de votre campagne. Vous y trouverez deux paramètres principaux à ajuster : - **Deterministic matching window** : utilise des identifiants d'appareils exacts (comme l'IDFA sur iOS ou l'Advertising ID sur Android) pour associer les utilisateurs aux campagnes avec une grande précision. Réglez cette valeur sur 168 heures (7 jours) pour une précision d'attribution maximale — c'est la valeur par défaut et recommandée. Lorsqu'un utilisateur clique sur votre annonce Meta et installe votre application dans cette fenêtre, Adapty peut attribuer définitivement l'installation à ce clic d'annonce spécifique grâce aux identifiants d'appareils. - **Probabilistic matching window** : utilise la modélisation statistique et le fingerprinting d'appareils pour associer les utilisateurs lorsque la correspondance déterministe n'est pas possible. Réglez cette valeur sur 6 heures pour la plupart des campagnes — c'est la valeur par défaut qui convient à la majorité des cas. Pour les campagnes à fort volume de clics, vous pouvez la réduire à 1-2 heures. Pour les utilisateurs ne pouvant pas être associés de manière déterministe (en raison de paramètres de confidentialité ou d'autres facteurs), Adapty utilise la correspondance probabiliste dans cette fenêtre plus courte. Cliquez sur **Save** pour appliquer vos paramètres. ### Remplacement de revenus \{#revenue-override\} Si vous suivez des événements d'essai et souhaitez que Meta leur attribue des revenus, utilisez la section **Revenue override**. Elle apparaît lorsque l'événement **Trial started** est activé. Pour chaque cible d'événement d'essai, définissez le pourcentage du prix de l'abonnement à déclarer comme revenu. Par exemple, à 30 %, Adapty envoie 30 % du prix de l'abonnement comme valeur de conversion pour les événements d'essai. Pour ajouter un remplacement : 1. Activez **Trial started** dans la section **Events names**. 2. Dans **Revenue override**, cliquez sur **Add override**. 3. Sélectionnez l'événement cible et saisissez un pourcentage de revenu (0-100). 4. Cliquez sur **Save**. ### Envoyer tous les événements \{#send-all-events\} Par défaut, Adapty n'envoie des événements à votre pixel que pour les utilisateurs attribués à une campagne Meta. Activez **Send all events** pour également transmettre les événements des utilisateurs organiques et non attribués au pixel. Lorsque cette option est activée, chaque événement d'installation et de transaction est envoyé au pixel, quelle que soit l'attribution de campagne. Utilisez cette option pour fournir à Meta des données de conversion plus larges pour la modélisation d'audience et l'optimisation des campagnes. Pour activer cette option, dans les paramètres de la campagne, sélectionnez **Send all events (forward organic/non-attributed events to this pixel)** et cliquez sur **Save**. --- # File: ua-tiktok --- --- title: "Intégrer TikTok for Business avec Adapty Attribution" description: "Connectez TikTok for Business à Adapty Attribution pour suivre et optimiser les performances de vos campagnes dans TikTok Ads Manager." --- L'intégration TikTok for Business d'Adapty Attribution vous permet de suivre et d'optimiser les performances de vos campagnes sur TikTok. :::tip Consultez notre [guide pour configurer des publicités dans TikTok for Business](tiktok-create-campaign). ::: ## Étape 1. Connecter votre compte TikTok \{#step-1-connect-your-tiktok-account\} 1. Accédez à **Integrations > TikTok Ads** dans la barre latérale gauche et cliquez sur **Continue with TikTok**. 2. Connectez-vous avec votre compte TikTok et cliquez sur **Continue**. 3. Vérifiez les autorisations demandées et cliquez sur **Save**. Après cela, tous vos comptes publicitaires seront ajoutés à Adapty Attribution. Vous pouvez ensuite passer à l'ajout de campagnes. ## Étape 2. Ajouter des campagnes \{#step-2-add-campaigns\} Pour ajouter une campagne TikTok for Business à Adapty Attribution et suivre les performances de vos publicités TikTok dans Adapty : 1. Passez à l'onglet **Web Campaigns** et cliquez sur **Create configuration**. 2. Dans l'onglet **General**, développez la section **iOS** et/ou **Android** et collez les URL de votre application depuis l'App Store et/ou Google Play. 3. Copiez la valeur du champ **Click link**. Ensuite, dans TikTok Ads Manager, lors de la création de votre publicité, collez cette valeur dans le champ **Tracking URL** sous la section **Advanced Settings**. Cela permettra à Adapty de relier les installations et les achats aux publicités TikTok. 4. (Facultatif) Pour renvoyer les événements de conversion vers TikTok, vous pouvez également associer vos pixels TikTok aux campagnes dans Adapty Attribution. Pour ce faire, sélectionnez l'un de vos pixels existants dans le menu déroulant **Pixel**. Après avoir sélectionné un pixel, vous pouvez cliquer sur **Send test event** pour vérifier la connexion. ## Étape 3. Mapper les événements \{#step-3-map-events\} Pour envoyer des événements de conversion vers TikTok afin d'optimiser vos campagnes, vous devez configurer le mapping des événements dans la section **Events names**. Cela permet à Adapty d'envoyer automatiquement les événements d'abonnement à votre pixel TikTok lorsque les utilisateurs effectuent des actions dans votre application. Dans la section **Events names**, activez les événements que vous souhaitez suivre dans TikTok Ads Manager. Pour chaque événement activé, sélectionnez l'événement TikTok correspondant dans le menu déroulant ou définissez-en un personnalisé. Par défaut, Adapty associe les événements Adapty aux événements standard de TikTok. Cliquez sur **Save** pour appliquer votre configuration de mapping des événements. ## Configuration supplémentaire \{#additional-configuration\} ### Paramètres supplémentaires \{#additional-parameters\} Le champ **Additional parameter** vous permet d'ajouter des données personnalisées pour une analyse en dehors d'Adapty. C'est utile lorsque vous devez transmettre des données de campagne ou d'utilisateur spécifiques à des outils d'analyse externes ou à des partenaires d'attribution. Dans le champ **Additional parameter**, saisissez les données personnalisées que vous souhaitez inclure dans votre suivi d'attribution. Le paramètre supplémentaire sera inclus dans toutes les données d'attribution envoyées à TikTok et peut être utilisé pour une analyse et une optimisation avancées des campagnes. Par exemple, si vous exécutez plusieurs variantes d'une même campagne, vous pourriez ajouter `variant=A` ou `variant=B` pour distinguer les différentes approches créatives. :::important Les paramètres supplémentaires modifient le **Click link** que vous collez dans TikTok Ads Manager. Si vous avez déjà copié ce lien et ajouté un paramètre personnalisé par la suite, assurez-vous de copier et coller le lien mis à jour qui contient le paramètre personnalisé. ::: <br/> ### Paramètres \{#settings\} L'onglet **Settings** contrôle la façon dont Adapty fait correspondre les actions des utilisateurs à vos campagnes TikTok Ads. Ces paramètres définissent les fenêtres de temps pour l'attribution déterministe et probabiliste. Pour les configurer, accédez à l'onglet **Settings** dans la configuration de votre campagne. Vous y trouverez deux paramètres principaux à ajuster : - **Deterministic matching window** : utilise des identifiants d'appareils exacts (comme l'IDFA sur iOS ou l'Advertising ID sur Android) pour associer les utilisateurs aux campagnes avec une grande précision. Réglez cette valeur à 168 heures (7 jours) pour une précision d'attribution maximale — c'est la valeur par défaut et recommandée. Lorsqu'un utilisateur clique sur votre publicité TikTok et installe votre application dans cette fenêtre, Adapty peut attribuer définitivement l'installation à ce clic publicitaire grâce aux identifiants d'appareil. - **Probabilistic matching window** : utilise la modélisation statistique et l'empreinte numérique de l'appareil pour associer les utilisateurs lorsque l'attribution déterministe n'est pas possible. Réglez cette valeur à 6 heures pour la plupart des campagnes — c'est la valeur par défaut et fonctionne bien dans la majorité des cas. Pour les campagnes à fort volume de clics, vous pouvez la réduire à 1-2 heures. Pour les utilisateurs qui ne peuvent pas être associés de façon déterministe (en raison de paramètres de confidentialité ou d'autres facteurs), Adapty utilise l'attribution probabiliste dans cette fenêtre plus courte. Cliquez sur **Save** pour appliquer vos paramètres. ### Remplacement de revenus \{#revenue-override\} Si vous suivez les événements d'essai et souhaitez que TikTok leur attribue des revenus, utilisez la section **Revenue override**. Elle apparaît lorsque l'événement **Trial started** est activé. Pour chaque cible d'événement d'essai, définissez le pourcentage du prix de l'abonnement à déclarer comme revenu. Par exemple, à 30 %, Adapty envoie 30 % du prix de l'abonnement comme valeur de conversion pour les événements d'essai. Pour ajouter un remplacement : 1. Activez **Trial started** dans la section **Events names**. 2. Dans **Revenue override**, cliquez sur **Add override**. 3. Sélectionnez l'événement cible et saisissez un pourcentage de revenu (0–100). 4. Cliquez sur **Save**. ### Envoyer tous les événements \{#send-all-events\} Par défaut, Adapty envoie des événements à votre pixel uniquement pour les utilisateurs attribués à une campagne TikTok. Activez **Send all events** pour également transmettre les événements des utilisateurs organiques et non attribués au pixel. Lorsque cette option est activée, chaque événement d'installation et de transaction est envoyé au pixel, quelle que soit l'attribution de la campagne. Utilisez-la pour fournir à TikTok des données de conversion plus larges pour la modélisation d'audience et l'optimisation des campagnes. Pour activer cette option, dans les paramètres de la campagne, sélectionnez **Send all events (forward organic/non-attributed events to this pixel)** et cliquez sur **Save**. --- # File: ua-funnelfox --- --- title: "Intégrer FunnelFox avec Adapty Attribution" description: "Connectez les funnels web-to-app FunnelFox à Adapty Attribution pour suivre le parcours d'acquisition complet, du point de contact web jusqu'à l'abonné payant." --- [FunnelFox](https://funnelfox.com) est une plateforme de création de funnels web2app qui vous permet d'acquérir et de facturer des utilisateurs en dehors de l'App Store, en contournant ses frais et autres restrictions. Une fois connecté, FunnelFox envoie les événements de transaction à Adapty Attribution, ce qui vous donne un parcours d'attribution complet, du point de contact web jusqu'à l'abonné payant. Pour configurer l'intégration, liez un ou plusieurs projets FunnelFox à votre application Adapty via un **Project ID**. ## Comment ça fonctionne \{#how-it-works\} Lorsqu'un utilisateur finalise un achat dans votre funnel FunnelFox, FunnelFox envoie l'événement de transaction à Adapty Attribution. Adapty utilise le **Project ID** pour identifier à quelle application appartient la transaction. L'événement est ensuite stocké et apparaît dans vos analyses Adapty Attribution. Chaque transaction inclut : - **Événement du cycle de vie de l'abonnement** : démarré, renouvelé, annulé, essai converti, remboursé, et plus encore - **Données d'attribution** : identifiants de campagne, d'ensemble de publicités et d'annonce ; paramètres UTM ; identifiants de clic de plateforme (fbclid, ttclid, gclid) - **Données de funnel et d'expérience** : nom du funnel FunnelFox et nom de l'expérience, pour comparer les variantes de tests A/B Adapty détermine automatiquement le **canal** (Facebook, TikTok, Google ou organique) à partir de l'identifiant de clic dans la transaction. Vous n'avez pas à le configurer manuellement. :::note Les transactions FunnelFox utilisent la **date du premier paiement** comme date de cohorte plutôt que la date d'installation, car les achats web ne génèrent pas d'événement d'installation d'application. ::: ## Configurer l'intégration \{#configure-integration\} ### Étape 1. Obtenez votre Project ID dans FunnelFox \{#step-1-get-your-project-id-in-funnelfox\} 1. Dans votre tableau de bord FunnelFox, cliquez sur **Settings** dans la barre latérale gauche. 2. Dans la section **Project info**, copiez la valeur **ID**. ### Étape 2. Ajoutez le projet dans Adapty Attribution \{#step-2-add-the-project-in-adapty-attribution\} 1. Dans Adapty Attribution, accédez à [**Integrations > FunnelFox**](https://app.adapty.io/ua/integrations/funnelfox). 2. Collez le Project ID que vous avez copié depuis FunnelFox. 3. Cliquez sur **Save**. Pour connecter des projets FunnelFox supplémentaires, cliquez sur **Add project** et répétez les deux étapes pour chaque projet. --- # File: ua-custom-s3 --- --- title: "Custom S3 dans Adapty Attribution" description: "Exportez vos données d'acquisition utilisateur vers votre stockage compatible S3 personnalisé pour des analyses et des rapports avancés." --- L'intégration d'Adapty Attribution avec un stockage compatible S3 personnalisé vous permet de stocker les données de vos campagnes d'acquisition utilisateur en toute sécurité dans votre propre solution de stockage compatible S3. Vous pourrez enregistrer vos données de performance de campagne, vos données d'attribution et vos événements d'acquisition utilisateur dans votre bucket S3 personnalisé sous forme de fichiers .csv. Pour configurer cette intégration, vous devrez suivre quelques étapes simples dans la console de votre stockage compatible S3 et dans le tableau de bord Adapty Attribution. :::note Adapty Attribution envoie vos données toutes les **24h** à 4:00 UTC. Chaque fichier contiendra les données des événements créés pour l'intégralité du jour calendaire précédent en UTC. Par exemple, les données exportées automatiquement à 4:00 UTC le 8 mars contiendront tous les événements créés le 7 mars de 00:00:00 à 23:59:59 UTC. ::: ## Configurer l'intégration Custom S3 \{#set-up-custom-s3-integration\} Pour commencer à recevoir des données, configurez l'intégration dans Adapty Attribution : 1. Accédez à [**Integrations** -> **Custom S3**](https://app.adapty.io/ua/integrations/custom-s3) 2. Activez le bouton **Export install events to custom S3**. 3. Renseignez les champs requis pour établir une connexion entre votre stockage S3 personnalisé et les profils Adapty Attribution | Champ | Description | |:----------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Access Key ID** | Un identifiant unique utilisé pour authentifier l'accès d'un utilisateur ou d'une application à votre service de stockage compatible S3. Trouvez cet identifiant dans la console de votre fournisseur de stockage. | | **Secret Access Key** | Une clé privée utilisée conjointement avec l'Access Key ID pour authentifier l'accès d'un utilisateur ou d'une application à votre service de stockage compatible S3. Trouvez cette clé dans la console de votre fournisseur de stockage. | | **S3 Bucket Name** | Un nom globalement unique qui identifie un bucket S3 spécifique dans votre environnement de stockage. Les buckets S3 sont un service de stockage simple qui permet aux utilisateurs de stocker et de récupérer des objets de données, comme des fichiers et des images, dans le cloud. | | **Region** (Optionnel) | Obtenez votre région depuis la Management Console. | | **Folder Inside the Bucket** (Optionnel) | Le nom du dossier que vous souhaitez créer dans le bucket S3 sélectionné. Notez que S3 simule les dossiers à l'aide de préfixes de clés d'objet, qui sont essentiellement des noms de dossiers. | | **Custom Endpoint URL** | L'URL de point de terminaison de votre service de stockage compatible S3. Elle doit être fournie par votre fournisseur de stockage (par exemple, MinIO, DigitalOcean Spaces, Wasabi, etc.). | :::note Vous pouvez également spécifier des répertoires imbriqués dans le champ S3 bucket name, par exemple `adapty-ua-events/com.sample-app` ::: ## Export manuel des données \{#manual-data-export\} En plus de l'export automatique des données d'événements vers votre stockage S3 personnalisé, Adapty Attribution propose également une fonctionnalité d'export manuel de fichiers. Grâce à cette fonctionnalité, vous pouvez sélectionner une date pour les données d'acquisition utilisateur et les exporter manuellement dans votre bucket S3. Cela vous permet de mieux contrôler les données que vous exportez et le moment où vous les exportez. ## Structure de la table \{#table-structure\} Dans l'intégration Custom S3, Adapty Attribution fournit une table pour stocker les données historiques des événements d'installation. La table contient des informations sur le profil utilisateur, les revenus et les gains nets, ainsi que le store d'origine, parmi d'autres points de données. :::warning Notez que cette structure est susceptible d'évoluer au fil du temps — avec de nouvelles données introduites par nos soins ou par les tiers avec lesquels nous travaillons. Assurez-vous que le code qui traite ces données est suffisamment robuste et s'appuie sur des champs spécifiques, et non sur la structure dans son ensemble. ::: Voici la structure de la table pour les événements : | Colonne | Description | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Identifiant unique du profil Adapty | | `install_id` | Identifiant unique de l'installation | | `created_at` | Horodatage de création de l'enregistrement (ISO 8601) | | `installed_at` | Horodatage d'installation de l'application (ISO 8601) | | `store` | Store applicatif (`ios`, `android`) | | `country` | Code pays de l'utilisateur (ISO 3166-1 alpha-2) | | `ip_address` | Adresse IP du client | | `idfa` | iOS Identifier for Advertisers | | `idfv` | iOS Identifier for Vendors | | `gaid` | Google Advertising ID (Android) | | `android_id` | Identifiant d'appareil Android | | `app_set_id` | Android App Set ID | | `bundle_id` | Identifiant de bundle de l'application (ex. `com.example.app`) | | `device_brand` | Marque de l'appareil (ex. `Apple`, `Samsung`) | | `device_model` | Modèle de l'appareil (ex. `iPhone15,2`) | | `os_version` | Version majeure du système d'exploitation | | `app_version` | Version de l'application reportée par le SDK Adapty | | `sdk_version` | Version du SDK Adapty | | `channel` | Canal d'attribution | | `campaign_id` | Identifiant de campagne | | `campaign_name` | Nom de la campagne | | `adset_id` | Identifiant du groupe d'annonces | | `adset_name` | Nom du groupe d'annonces | | `ad_id` | Identifiant de l'annonce | | `ad_name` | Nom de l'annonce | | `keyword_id` | Identifiant du mot-clé | | `keyword_name` | Nom du mot-clé | | `asa_org_id` | Identifiant d'organisation Apple Search Ads | | `asa_keyword_match_type` | Type de correspondance de mot-clé ASA (`Exact`, `Broad`) | | `asa_attribution` | Données d'attribution ASA (chaîne JSON) | | `asa_conversion_type` | Type de conversion ASA | | `asa_country_or_region` | Pays ou région ASA | | `asa_creative_set_name` | Nom du jeu de créatifs ASA | | `fbclid` | Facebook Click ID | | `ttclid` | TikTok Click ID | | `utm_source` | Paramètre UTM source | | `utm_medium` | Paramètre UTM medium | | `utm_campaign` | Paramètre UTM campaign | | `utm_term` | Paramètre UTM term | | `utm_content` | Paramètre UTM content | --- # File: ua-amazon-s3 --- --- title: "Amazon S3 dans l'attribution Adapty" description: "Exportez les données d'acquisition utilisateur vers S3 pour des analyses et des rapports avancés." --- L'intégration d'Adapty Attribution avec Amazon S3 vous permet de stocker les données de vos campagnes d'acquisition utilisateur de façon sécurisée en un seul endroit. Vous pouvez ainsi enregistrer les performances de vos campagnes, les données d'attribution et les événements d'acquisition dans votre bucket Amazon S3 sous forme de fichiers .csv. Pour configurer cette intégration, il vous suffit de suivre quelques étapes simples dans AWS Console et dans le tableau de bord Adapty Attribution. :::note Adapty Attribution envoie vos données toutes les **24h** à 4h00 UTC. Chaque fichier contient les données des événements créés sur l'ensemble de la journée calendaire précédente en UTC. Par exemple, les données exportées automatiquement à 4h00 UTC le 8 mars contiendront tous les événements créés le 7 mars de 00:00:00 à 23:59:59 UTC. ::: ## Comment configurer l'intégration Amazon S3 \{#how-to-set-up-amazon-s3-integration\} Pour commencer à recevoir des données, vous aurez besoin des identifiants suivants : 1. Access key ID 2. Secret access key 3. Nom du bucket S3 4. Nom du dossier dans le bucket S3 :::note Répertoires imbriqués Vous pouvez spécifier des répertoires imbriqués dans le champ du nom du bucket Amazon S3, par exemple : adapty-ua-events/com.sample-app ::: ### Étape 1. Créer les identifiants Amazon S3 \{#step-1-create-amazon-s3-credentials\} Ce guide vous aide à créer les identifiants nécessaires dans votre AWS Console. #### 1.1. Créer une politique d'accès \{#11-create-access-policy\} 1. Accédez au [tableau de bord des politiques IAM](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) dans votre AWS Console 2. Sélectionnez l'option **Create Policy** <img src="/assets/shared/img/7af075c-CleanShot_2023-03-21_at_10.52.002x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans l'éditeur de politique, collez le JSON suivant et remplacez `adapty-s3-integration-test` par le nom de votre bucket : ```json showLineNumbers title="Json" { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListObjectsInBucket", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::adapty-s3-integration-test" }, { "Sid": "AllowAllObjectActions", "Effect": "Allow", "Action": "s3:*Object", "Resource": [ "arn:aws:s3:::adapty-s3-integration-test/*", "arn:aws:s3:::adapty-s3-integration-test" ] }, { "Sid": "AllowBucketLocation", "Effect": "Allow", "Action": "s3:GetBucketLocation", "Resource": "arn:aws:s3:::adapty-s3-integration-test" } ] } ``` <img src="/assets/shared/img/d4e474a-CleanShot_2023-03-21_at_10.56.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Une fois la politique configurée, vous pouvez ajouter des tags (facultatif), puis cliquer sur **Next** pour passer à l'étape finale 5. Dans cette étape, donnez un nom à votre politique et cliquez sur le bouton **Create policy** pour finaliser la création <img src="/assets/shared/img/7dcb02f-CleanShot_2023-03-21_at_11.03.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 1.2. Créer un utilisateur IAM \{#12-create-iam-user\} Pour permettre à Adapty Attribution de charger des rapports de données brutes dans votre bucket, vous devez lui fournir l'Access Key ID et la Secret Access Key d'un utilisateur disposant d'un accès en écriture sur le bucket concerné. 1. Accédez à la console IAM et sélectionnez la [section Utilisateurs](https://console.aws.amazon.com/iamv2/home#/users) 2. Cliquez sur le bouton **Add users** <img src="/assets/shared/img/bb612c8-CleanShot_2023-03-21_at_11.12.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Donnez un nom à l'utilisateur, choisissez **Access key – Programmatic access**, puis passez aux permissions <img src="/assets/shared/img/467ee4d-j6aoX.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Pour l'étape suivante, sélectionnez l'option **Add user to group**, puis cliquez sur le bouton **Create group** <img src="/assets/shared/img/bfd0e80-CleanShot_2023-03-21_at_11.24.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Ensuite, donnez un nom à votre groupe d'utilisateurs et sélectionnez la politique que vous avez créée précédemment 6. Une fois la politique sélectionnée, cliquez sur le bouton **Create group** pour finaliser le processus <img src="/assets/shared/img/df29c12-CleanShot_2023-03-21_at_11.28.052x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Après avoir créé le groupe, **sélectionnez-le** et passez à l'étape suivante <img src="/assets/shared/img/1f3722e-CleanShot_2023-03-21_at_11.36.192x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. C'est la dernière étape de cette section ; cliquez simplement sur le bouton **Create User** <img src="/assets/shared/img/ea43722-CleanShot_2023-03-21_at_11.40.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Enfin, vous pouvez soit **télécharger les identifiants au format .csv**, soit les copier-coller directement depuis le tableau de bord <img src="/assets/shared/img/bcf35e1-S3created.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Étape 2. Configurer l'intégration dans Adapty Attribution \{#step-2-configure-integration-in-adapty-attribution\} 1. Accédez à [**Integrations** -> **Amazon S3**](https://app.adapty.io/ua/integrations/s3) 2. Activez le bouton **Export install events to Amazon S3**. 3. Remplissez les champs suivants pour établir la connexion entre Amazon S3 et les profils Adapty Attribution : | Champ | Description | |:-----------------------------| :----------------------------------------------------------- | | **Access Key ID** | Identifiant unique utilisé pour authentifier l'accès d'un utilisateur ou d'une application à un service AWS. Retrouvez cet identifiant dans le [fichier csv](ua-amazon-s3#step-1-create-amazon-s3-credentials) téléchargé. | | **Secret Access Key** | Clé privée utilisée conjointement avec l'Access Key ID pour authentifier l'accès d'un utilisateur ou d'une application à un service AWS. Retrouvez cette clé dans le [fichier csv](ua-amazon-s3#step-1-create-amazon-s3-credentials) téléchargé. | | **S3 Bucket Name** | Nom unique au monde identifiant un bucket S3 spécifique dans le cloud AWS. Les buckets S3 sont un service de stockage simple permettant de stocker et de récupérer des objets de données, comme des fichiers et des images, dans le cloud. | | **Folder Inside the Bucker** | Nom du dossier que vous souhaitez créer dans le bucket S3 sélectionné. Notez que S3 simule les dossiers à l'aide de préfixes de clés d'objet, qui correspondent essentiellement à des noms de dossiers. | | **Region** (Optionnel) | Retrouvez votre région dans AWS Management Console sous votre compte utilisateur IAM. | ## Export manuel des données \{#manual-data-export\} En plus de l'export automatique des données d'événements vers Amazon S3, Adapty Attribution propose également une fonctionnalité d'export manuel de fichiers. Cette fonctionnalité vous permet de sélectionner une date précise pour les données d'acquisition utilisateur et de les exporter manuellement dans votre bucket S3, pour un contrôle total sur les données exportées et le moment de leur export. ## Structure de la table \{#table-structure\} Dans l'intégration AWS S3, Adapty Attribution fournit une table pour stocker l'historique des événements d'installation. Cette table contient des informations sur le profil utilisateur, les revenus et les produits, le store d'origine, entre autres points de données. :::warning Notez que cette structure peut évoluer avec le temps — de nouvelles données peuvent être introduites par nos soins ou par les tiers avec lesquels nous travaillons. Assurez-vous que le code qui traite ces données est suffisamment robuste et s'appuie sur des champs spécifiques, et non sur la structure dans son ensemble. ::: Voici la structure de la table pour les événements : | Colonne | Description | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Identifiant unique du profil Adapty | | `install_id` | Identifiant unique de l'installation | | `created_at` | Horodatage de création de l'enregistrement (ISO 8601) | | `installed_at` | Horodatage d'installation de l'application (ISO 8601) | | `store` | Store (`ios`, `android`) | | `country` | Code pays de l'utilisateur (ISO 3166-1 alpha-2) | | `ip_address` | Adresse IP du client | | `idfa` | Identifiant iOS pour les annonceurs | | `idfv` | Identifiant iOS pour les vendeurs | | `gaid` | Identifiant publicitaire Google (Android) | | `android_id` | Identifiant de l'appareil Android | | `app_set_id` | Android App Set ID | | `channel` | Canal d'attribution | | `campaign_id` | Identifiant de la campagne | | `campaign_name` | Nom de la campagne | | `adset_id` | Identifiant du groupe d'annonces | | `adset_name` | Nom du groupe d'annonces | | `ad_id` | Identifiant de l'annonce | | `ad_name` | Nom de l'annonce | | `keyword_id` | Identifiant du mot-clé | | `keyword_name` | Nom du mot-clé | | `asa_org_id` | Identifiant d'organisation Apple Search Ads | | `asa_keyword_match_type` | Type de correspondance du mot-clé ASA (`Exact`, `Broad`) | | `asa_attribution` | Données d'attribution ASA (chaîne JSON) | | `asa_conversion_type` | Type de conversion ASA | | `asa_country_or_region` | Pays ou région ASA | | `asa_creative_set_name` | Nom du jeu de créatifs ASA | | `fbclid` | Facebook Click ID | | `ttclid` | TikTok Click ID | | `utm_source` | Paramètre source UTM | | `utm_medium` | Paramètre medium UTM | | `utm_campaign` | Paramètre campagne UTM | | `utm_term` | Paramètre terme UTM | | `utm_content` | Paramètre contenu UTM | --- # File: ua-google-cloud-storage --- --- title: "Google Cloud Storage dans Adapty Attribution" description: "Intégrez Google Cloud Storage avec Adapty Attribution pour stocker en toute sécurité les données d'acquisition utilisateur." --- L'intégration d'Adapty Attribution avec Google Cloud Storage vous permet de stocker en toute sécurité les données de vos campagnes d'acquisition utilisateur en un seul endroit centralisé. Vous pourrez enregistrer vos données de performance de campagne, vos données d'attribution et vos événements d'acquisition utilisateur dans votre bucket Google Cloud Storage sous forme de fichiers .csv. Pour configurer cette intégration, vous devrez suivre quelques étapes simples dans la Google Cloud Console et dans le tableau de bord Adapty Attribution. :::note Planification Adapty Attribution envoie vos données vers Google Cloud Storage toutes les 24h à 4h00 UTC. Chaque fichier contiendra les données des événements créés pour l'ensemble de la veille en UTC. Par exemple, les données exportées automatiquement à 4h00 UTC le 8 mars contiendront tous les événements créés le 7 mars de 00:00:00 à 23:59:59 UTC. ::: ## Comment configurer l'intégration Google Cloud Storage \{#how-to-set-up-google-cloud-storage-integration\} ### Étape 1. Créer les identifiants Google Cloud Storage \{#step-1-create-google-cloud-storage-credentials\} Ce guide vous aidera à créer les identifiants nécessaires dans votre Google Cloud Platform Console. Pour qu'Adapty Attribution puisse envoyer des rapports de données brutes dans votre bucket désigné, la clé du compte de service est requise, ainsi qu'un accès en écriture au bucket correspondant. En fournissant la clé du compte de service et en accordant l'accès en écriture au bucket, vous permettez à Adapty Attribution de transférer en toute sécurité les rapports de données brutes vers votre environnement de stockage. :::warning Veuillez noter que nous prenons uniquement en charge l'autorisation par clé HMAC de compte de service. Il est donc indispensable que votre clé HMAC de compte de service dispose des rôles « Storage Object Viewer », « Storage Legacy Bucket Writer » et « Storage Object Creator » pour activer l'accès approprié à Google Cloud Storage. ::: #### 2.1. Créer un compte de service \{#21-create-service-account\} 1. Accédez à la section [IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts) de votre compte Google Cloud et choisissez le projet concerné ou créez-en un nouveau <img src="/assets/shared/img/30a81ef-CleanShot_2023-03-17_at_15.22.142x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Ensuite, créez un nouveau compte de service pour Adapty Attribution en cliquant sur le bouton « + CREATE SERVICE ACCOUNT » <img src="/assets/shared/img/98f8ebf-CleanShot_2023-03-17_at_15.40.062x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Remplissez les champs de la première étape ; l'accès sera accordé ultérieurement. Pour plus de détails sur cette page, consultez la documentation [ici](https://docs.cloud.google.com/iam/docs/service-accounts-create) <img src="/assets/shared/img/2190c50-CleanShot_2023-03-17_at_15.48.552x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Pour créer et télécharger une [clé JSON privée](https://docs.cloud.google.com/iam/docs/keys-create-delete), accédez à la section KEYS et cliquez sur le bouton « ADD KEY » <img src="/assets/shared/img/8a45468-CleanShot_2023-03-17_at_15.58.092x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Dans la section DETAILS, repérez la valeur Email associée au compte de service récemment créé et copiez-la. Ces informations seront nécessaires pour les étapes suivantes afin d'autoriser le compte et lui permettre d'écrire dans le bucket <img src="/assets/shared/img/6ccd0f0-CleanShot_2023-03-17_at_16.03.162x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 2.2. Configurer les permissions du bucket \{#22-configure-bucket-permissions\} 6. Accédez à la page [Buckets](https://console.cloud.google.com/storage/browser) de Google Cloud Storage et sélectionnez un bucket existant ou créez-en un nouveau pour stocker les rapports de données d'acquisition utilisateur d'Adapty Attribution 7. Accédez à la section PERMISSIONS et sélectionnez l'option [GRANT ACCESS](https://docs.cloud.google.com/identity/docs/how-to?hl=en) <img src="/assets/shared/img/3cdd937-CleanShot_2023-03-17_at_16.14.232x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. Dans la section PERMISSIONS, saisissez l'Email du compte de service obtenu à la cinquième étape, puis choisissez le rôle Storage Object Creator 9. Enfin, cliquez sur SAVE pour appliquer les modifications <img src="/assets/shared/img/62801f4-CleanShot_2023-03-17_at_16.17.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 10. Notez le nom du bucket pour référence ultérieure 11. Une fois ces étapes terminées, vous avez effectué avec succès la configuration nécessaire dans la Google Cloud Console ! La dernière étape consiste à saisir le nom du bucket et à télécharger le fichier JSON à utiliser dans Adapty Attribution <img src="/assets/shared/img/c967e16-CleanShot_2023-03-17_at_16.23.332x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Étape 2. Configurer l'intégration dans Adapty Attribution \{#step-2-configure-integration-in-adapty-attribution\} 1. Accédez à [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/ua/integrations/google-cloud-storage) 2. Activez le bouton **Export install events to Google Cloud Storage** 3. Remplissez les champs requis pour établir la connexion entre Google Cloud Storage et Adapty Attribution : | Champ | Description | |:------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Google Cloud service account key file** | Le [fichier de clé JSON](ua-google-cloud-storage#step-1-create-google-cloud-storage-credentials) privé téléchargé. | | **Google Cloud bucket name** | Le nom du bucket dans Google Cloud Storage où vous souhaitez stocker vos données. Il doit être unique dans l'environnement Google Cloud Storage et ne doit pas contenir d'espaces. | | **Folder inside the bucket** | Le nom du dossier à l'intérieur du bucket où vous souhaitez stocker vos données. Il doit être unique au sein du bucket et peut servir à organiser vos données. Ce champ est facultatif. | ## Export manuel des données \{#manual-data-export\} En plus de l'export automatique des données d'événements vers Google Cloud Storage, Adapty Attribution propose également une fonctionnalité d'export manuel de fichiers. Grâce à cette fonction, vous pouvez sélectionner une date précise pour les données d'acquisition utilisateur et les exporter manuellement dans votre bucket GCS. Cela vous donne un contrôle accru sur les données que vous exportez et sur le moment où vous les exportez. ## Structure de la table \{#table-structure\} Dans l'intégration Google Cloud Storage, Adapty Attribution fournit une table pour stocker les données historiques des événements d'installation. La table contient des informations sur le profil utilisateur, les revenus et les gains, ainsi que sur le store d'origine, entre autres données. :::warning Notez que cette structure peut évoluer au fil du temps — de nouvelles données pouvant être introduites par nous-mêmes ou par les tiers avec lesquels nous travaillons. Assurez-vous que votre code qui la traite est suffisamment robuste et s'appuie sur des champs spécifiques, et non sur la structure dans son ensemble. ::: Voici la structure de la table pour les événements : | Colonne | Description | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Identifiant unique du profil Adapty | | `install_id` | Identifiant unique d'installation | | `created_at` | Horodatage de création de l'enregistrement (ISO 8601) | | `installed_at` | Horodatage d'installation de l'application (ISO 8601) | | `store` | Store d'application (`ios`, `android`) | | `country` | Code pays de l'utilisateur (ISO 3166-1 alpha-2) | | `ip_address` | Adresse IP du client | | `idfa` | Identifiant iOS pour les annonceurs | | `idfv` | Identifiant iOS pour les vendeurs | | `gaid` | Google Advertising ID (Android) | | `android_id` | Identifiant d'appareil Android | | `app_set_id` | Android App Set ID | | `channel` | Canal d'attribution | | `campaign_id` | Identifiant de campagne | | `campaign_name` | Nom de la campagne | | `adset_id` | Identifiant du groupe d'annonces | | `adset_name` | Nom du groupe d'annonces | | `ad_id` | Identifiant de l'annonce | | `ad_name` | Nom de l'annonce | | `keyword_id` | Identifiant du mot-clé | | `keyword_name` | Nom du mot-clé | | `asa_org_id` | Identifiant d'organisation Apple Search Ads | | `asa_keyword_match_type` | Type de correspondance de mot-clé ASA (`Exact`, `Broad`) | | `asa_attribution` | Données d'attribution ASA (chaîne JSON) | | `asa_conversion_type` | Type de conversion ASA | | `asa_country_or_region` | Pays ou région ASA | | `asa_creative_set_name` | Nom du jeu créatif ASA | | `fbclid` | Facebook Click ID | | `ttclid` | TikTok Click ID | | `utm_source` | Paramètre UTM source | | `utm_medium` | Paramètre UTM medium | | `utm_campaign` | Paramètre UTM campaign | | `utm_term` | Paramètre UTM term | | `utm_content` | Paramètre UTM content | --- # File: adapty-mail --- --- title: "Adapty Mail" description: "Campagnes e-mail générées par IA qui convertissent les utilisateurs en essai en abonnés payants." --- <CustomDocCardList ids={['mail-get-started', 'mail-brand', 'mail-collect-emails', 'mail-send-data-via-api', 'mail-sending-domain', 'mail-create-campaign', 'mail-analytics']} /> Adapty Mail transforme vos données utilisateurs Adapty en séquences d'e-mails générées par IA pour convertir les utilisateurs en essai en abonnés payants. Il exploite les données de profil déjà présentes dans votre projet Adapty pour créer, envoyer et attribuer des campagnes — sans plateforme e-mail séparée. ## Pourquoi Adapty Mail ? \{#why-adapty-mail\} Envoyer des campagnes e-mail ciblées demande de la rédaction, du design, une infrastructure d'envoi et une attribution des revenus. Chacun de ces aspects représente un problème à résoudre séparément. Adapty Mail s'occupe de tout. Votre profil de marque est construit à partir de l'URL de votre store et de toutes les autres sources que vous ajoutez, puis une séquence d'e-mails complète est générée en moins de 2 minutes — envoyée depuis votre propre domaine avec des liens de paiement personnalisés et une attribution des achats. ## Comment ça fonctionne \{#how-it-works\} 1. **Collectez les e-mails** : votre application transmet les e-mails des utilisateurs et les valeurs `customer_user_id` à Adapty via le SDK. Adapty Mail utilise ces données pour identifier les destinataires et attribuer les revenus à l'e-mail précis qui a déclenché chaque achat. Vous pouvez également envoyer ces données depuis votre serveur via l'[API Adapty Mail](mail-send-data-via-api). 2. **Créez un paywall web** : la page de paiement vers laquelle renvoie chaque e-mail. 3. **Générez une séquence** : l'IA s'appuie sur votre profil de marque pour produire 1 à 15 e-mails — rédaction, design, images hero et liens de paiement personnalisés adaptés à la catégorie et au ton de votre application. 4. **Lancez un flow** : choisissez un déclencheur (aucun achat, renouvellement annulé, problème de facturation, abonnement expiré ou remboursé) et un segment, puis associez votre campagne. Les e-mails s'envoient automatiquement, et les revenus issus des achats générés par e-mail sont attribués à l'e-mail spécifique qui a conduit à la conversion. ## Prérequis \{#requirements\} Pour utiliser Adapty Mail, vous avez besoin de : - Un compte Adapty - La collecte d'e-mails configurée dans votre application — voir [Collecter les e-mails des utilisateurs](mail-collect-emails) - `customer_user_id` configuré dans votre SDK Adapty - Un domaine que vous contrôlez avec accès à ses paramètres DNS - Un prestataire de paiement web (Stripe, Paddle ou PayPal) ## Démarrer \{#get-started\} Suivez le guide [Démarrer avec Adapty Mail](mail-get-started) pour finaliser la configuration et lancer votre première campagne. --- # File: mail-get-started --- --- title: "Démarrer avec Adapty Mail" description: "Configurez Adapty Mail et lancez votre premier flow d'emails." --- Dans ce guide, vous allez configurer Adapty Mail et lancer votre premier flow d'emails. :::note Vous pouvez également envoyer des données à Adapty Mail depuis votre propre serveur, sans le SDK Adapty. Si vous détenez déjà les emails des utilisateurs et les achats sur votre backend, ou si vous importez des abonnés depuis une autre source, consultez [Envoyer des emails et des transactions via l'API Adapty Mail](mail-send-data-via-api). ::: La configuration comporte six étapes : 1. [Configurer votre SDK Adapty](#1-configure-your-adapty-sdk) 2. [Configurer votre domaine d'envoi](#2-set-up-your-sending-domain) 3. [Créer un paywall web](#3-create-a-web-paywall) 4. [Générer une campagne avec l'IA](#4-generate-a-campaign-with-ai) 5. [Lancer un flow](#5-launch-a-flow) 6. [Activer l'envoi](#6-enable-sending) :::tip Si vous vous êtes inscrit à Adapty Mail via Adapty, votre **profil de marque** est créé automatiquement à partir de l'URL du store de votre projet. Ouvrez **Brand** à tout moment pour le consulter ou l'affiner — voir [Brand](mail-brand). Si vous vous êtes inscrit de façon autonome, configurez votre marque sur la même page avant de générer des campagnes ou des paywalls web. ::: ## Avant de commencer \{#before-you-start\} Assurez-vous que les éléments suivants sont en place avant de commencer : - **Accès DNS** : vous pouvez ajouter des enregistrements à votre domaine racine. - **Prestataire de paiement web** : vous disposez d'un compte Stripe, Paddle ou PayPal avec vos produits d'abonnement configurés. ## 1. Configurer votre SDK Adapty \{#1-configure-your-adapty-sdk\} :::important Adapty Mail est un **produit autonome**. Vous pouvez l'utiliser même si vos paywalls, abonnements ou analyses ne sont pas gérés par Adapty — migrer l'intégralité de votre stack n'est pas obligatoire. Pour obtenir des données de revenus précises, la configuration minimale consiste à installer le SDK Adapty en mode observateur et à activer les notifications serveur de l'App Store. ::: Adapty Mail a besoin de trois éléments de votre application : les données d'achat (pour attribuer les revenus à l'email qui a généré chaque conversion), un identifiant utilisateur stable et les emails des utilisateurs. 1. **Permettez à Adapty de suivre vos revenus.** La première étape dépend de si vous avez déjà mis en œuvre des achats intégrés : - Si vous **avez déjà mis en œuvre des achats intégrés avec Adapty**, vous n'avez rien d'autre à faire à cette étape. - Si vous **avez déjà mis en œuvre des achats intégrés sans Adapty** et ne prévoyez pas de migrer vers Adapty, installez le SDK Adapty pour votre plateforme en mode observateur. À cette étape, vous devez seulement ajouter le SDK à votre projet, l'activer avec le mode observateur activé, et signaler les transactions. Guides par plateforme : [iOS](implement-observer-mode), [Android](implement-observer-mode-android), [React Native](implement-observer-mode-react-native), [Flutter](implement-observer-mode-flutter), [Unity](implement-observer-mode-unity), [Kotlin Multiplatform](implement-observer-mode-kmp), [Capacitor](implement-observer-mode-capacitor). - Si vous **n'avez pas encore mis en œuvre des achats intégrés et souhaitez utiliser Adapty**, suivez les étapes du [guide de démarrage rapide](quickstart) pour déléguer la gestion des achats à Adapty. Ensuite, [activez les notifications serveur de l'App Store dans Adapty](enable-app-store-server-notifications) pour recevoir les mises à jour liées aux revenus directement depuis l'App Store. 2. **Configurez l'identification des utilisateurs.** Transmettez un identifiant stable — votre identifiant utilisateur backend, Firebase UID, ou similaire — soit en appelant `Adapty.identify()`, soit en passant `customerUserId` à `.activate()` au démarrage du SDK. Le `customer_user_id` est ce qu'Adapty Mail utilise pour relier les campagnes, les clics et les achats au bon profil. Guides par plateforme : [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Unity](unity-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Capacitor](capacitor-identifying-users). 3. **Collectez les emails des utilisateurs.** Dès qu'un utilisateur fournit son email dans votre application (par exemple, lors de l'inscription ou du paiement), transmettez-le à Adapty en appelant `updateProfile` avec l'attribut email. Chaque destinataire d'une campagne a besoin de cette valeur. Guides par plateforme : [iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes), [Unity](unity-setting-user-attributes), [Kotlin Multiplatform](kmp-setting-user-attributes), [Capacitor](capacitor-setting-user-attributes). Si votre application ne collecte pas encore les emails, consultez [Stratégies de collecte d'emails](mail-collect-emails#email-collection-strategies). ## 2. Configurer votre domaine d'envoi \{#2-set-up-your-sending-domain\} Ouvrez Adapty Mail : cliquez sur le logo Adapty dans l'en-tête et choisissez **Mail**. Adapty Mail envoie depuis votre propre domaine. Vous ajoutez les enregistrements DNS une seule fois — toutes les campagnes utilisent le même domaine vérifié. 1. Dans Adapty Mail, allez dans **Settings → Email Domains**. 2. Saisissez votre domaine racine (par exemple, `votreapp.com`) et cliquez sur **Preview**. Seuls les domaines apex sont acceptés — les sous-domaines comme `app.votreapp.com` sont refusés à la saisie. 3. Adapty génère deux sous-domaines d'envoi (`mail.votreapp.com` et `email.votreapp.com`). Cliquez sur **Confirm** pour afficher les enregistrements DNS requis. 4. Dans votre registrar de domaine, ajoutez les 10 enregistrements DNS affichés (5 par sous-domaine) : - 3 enregistrements CNAME (DKIM) par sous-domaine - 1 enregistrement MX (Mail-From) par sous-domaine - 1 enregistrement TXT (SPF, `v=spf1 include:amazonses.com ~all`) par sous-domaine 5. Optionnellement, ajoutez un enregistrement TXT DMARC sur votre domaine racine (recommandé). 6. Revenez dans **Settings → Email Domains** et cliquez sur **Check Verification**. Délais de vérification en bref : - **Vérification automatique** : la première vérification s'effectue environ 5 minutes après votre soumission. Les intervalles augmentent jusqu'à une fois par heure jusqu'à ce que les enregistrements soient trouvés. - **Vérification manuelle** : cliquez sur **Check Verification** à tout moment pour déclencher une vérification immédiate. - **Propagation DNS** : généralement en quelques minutes, jusqu'à 48 heures dans de rares cas. - **Fenêtre de vérification** : 7 jours. Si elle expire, vos enregistrements DNS restent en place — saisissez à nouveau votre domaine dans **Settings → Email Domains** pour démarrer une nouvelle fenêtre. Pour plus de détails sur chaque type d'enregistrement et le préchauffage du domaine, consultez [Configurer votre domaine d'envoi](mail-sending-domain). ## 3. Créer un paywall web \{#3-create-a-web-paywall\} Chaque email renvoie vers un paywall web — la page de paiement sur laquelle les utilisateurs arrivent lorsqu'ils cliquent sur un CTA. Vous avez deux options : - **Générer avec l'IA** : laissez le générateur de paywall web intégré en créer un pour votre application. - **Utiliser votre propre paywall hébergé** : intégrez un paywall que vous hébergez déjà. Pour commencer, dans Adapty Mail, allez dans **Web Paywalls → Create**. ### Option A : Générer avec l'IA \{#option-a-generate-with-ai\} La page affiche une liste de contrôle **Prerequisites** avec des boutons intégrés — parcourez-la dans l'ordre, puis revenez pour générer. La liste couvre la connexion au générateur de paywall, la connexion à Stripe, l'ajout de produits et la vérification du résultat. Consultez [Configurer le paiement](mail-checkout) pour la procédure complète. Quand tous les prérequis sont validés, cliquez sur **Generate** pour ouvrir la boîte de dialogue de génération : - **Environment** : choisissez **Production** ou **Sandbox**. Sandbox utilise vos produits en mode test Stripe et est l'option par défaut sécurisée pour les environnements de développement et locaux. - **Plans** : sélectionnez jusqu'à **3 plans Stripe** (chaque plan est un produit + un prix). Ce sont les offres que le paywall généré présente aux utilisateurs lors du paiement. Cliquez sur **Generate** pour lancer la génération. Lorsqu'elle est terminée, ouvrez l'éditeur pour vérifier et publier. :::important Le paywall doit être publié avant de pouvoir traiter le trafic de paiement. Les paywalls non publiés renvoient une erreur lorsque les utilisateurs cliquent sur les liens de paiement dans les emails. ::: ### Option B : Utiliser votre propre paywall hébergé \{#option-b-use-your-own-hosted-paywall\} 1. Sélectionnez **Enter URL manually**. 2. Collez l'URL de votre paywall hébergé. L'URL doit inclure les paramètres `{email}` et `{external_profile_id}` en tant que paramètres de requête — Adapty Mail les renseigne pour chaque destinataire afin que la page de paiement sache qui est le visiteur. Exemple : ``` https://example.com/paywall?email={email}&profile={external_profile_id} ``` 3. Enregistrez et publiez. Pour l'anatomie du tunnel de paiement et le fonctionnement de la personnalisation, consultez [Configurer le paiement](mail-checkout). ## 4. Générer une campagne avec l'IA \{#4-generate-a-campaign-with-ai\} L'IA crée la séquence d'emails complète pour vous — texte, design, images hero et liens de paiement personnalisés, le tout adapté à votre marque. 1. Dans Adapty Mail, allez dans **Campaigns** et cliquez sur **Create**. 2. Définissez le nom de la campagne. 3. Dans le menu déroulant **Web paywall**, sélectionnez le paywall web que vous avez ajouté à l'étape précédente. 4. Cliquez sur **Generate emails**. 5. Remplissez la boîte de dialogue de génération — ton, langue, une invite personnalisée optionnelle (jusqu'à 2 000 caractères) et le nombre d'emails (1 à 15, par défaut 4). Consultez [Créer une campagne](mail-create-campaign) pour savoir ce que fait chaque champ. 6. Cliquez sur **Generate**. La génération prend généralement quelques minutes. Le système expire après 5 minutes s'il ne parvient pas à terminer — réessayez si cela se produit. 7. Prévisualisez chaque email. L'en-tête de prévisualisation dispose d'un **bouton de thème** (Auto, Light, Dark) qui contrôle l'affichage de la prévisualisation — le contenu généré est identique dans tous les modes. Vous pouvez régénérer des emails individuels, modifier le texte ou ouvrir l'éditeur HTML pour un contrôle précis. 8. Cliquez sur **Create** pour enregistrer la campagne. La campagne est enregistrée en tant que **brouillon** et n'envoie pas encore — les campagnes ne deviennent actives que lorsqu'elles sont associées à un flow (étape suivante). Il n'y a pas d'action "publier" distincte dans l'éditeur de campagne. ## 5. Lancer un flow \{#5-launch-a-flow\} Un flow associe un **déclencheur** (un événement comme l'expiration d'un abonnement) à un **segment**, et envoie à ce segment la **campagne** que vous choisissez. Adapty Mail est livré avec cinq déclencheurs fixes, chacun avec sa propre vue de flow. 1. Dans Adapty Mail, allez dans **Flows**, puis ouvrez le déclencheur que vous souhaitez configurer : - **Never purchased** — utilisateurs qui se sont inscrits mais n'ont pas encore effectué d'achat. - **Renewal cancelled** — utilisateurs qui ont désactivé le renouvellement automatique mais disposent encore d'un abonnement actif. - **Billing issue** — échec de paiement, carte refusée ou expirée, ou délai de grâce. - **Expired** — l'abonnement a expiré et l'accès est révoqué. - **Refunded** — utilisateurs qui ont demandé un remboursement après un achat. Consultez [Flows](mail-flows) pour les objectifs et les conseils de ton associés à chaque déclencheur. 2. Cliquez sur **Create** pour ouvrir la boîte de dialogue. 3. Dans la boîte de dialogue : - Choisissez un **Segment** (par exemple, **All Users** pour cibler tous ceux qui atteignent ce déclencheur, ou créez un nouveau segment basé sur les attributs du profil). - Laissez le type de contenu défini sur **Campaign** (l'option A/B Test est décrite dans [Tests A/B](mail-ab-testing)). - Sélectionnez la **Campaign** que vous avez enregistrée à l'étape 4. 4. Cliquez sur **Save**. Le flow est actif immédiatement — il n'y a pas d'étape de lancement distincte. À partir de ce moment, les utilisateurs correspondant au segment commenceront à recevoir la campagne dès qu'ils atteignent l'événement déclencheur. :::note Vous pouvez ajouter plusieurs lignes segment → campagne au même déclencheur ; elles s'exécutent par ordre de priorité. La ligne **All Users**, si elle est utilisée, doit être la dernière (priorité la plus basse) afin de capturer tous ceux qui ne correspondent pas à un segment plus spécifique. ::: ## 6. Activer l'envoi \{#6-enable-sending\} Jusqu'à présent, votre campagne est configurée mais n'envoie pas réellement — l'**intégration Adapty** qui synchronise les événements d'abonnement dans Adapty Mail est encore désactivée. L'activer est le dernier interrupteur : les événements commencent à circuler, les segments commencent à correspondre, et les emails commencent à être envoyés. Cette étape n'est débloquée qu'après l'étape 5. Avant de lancer un flow, le bouton **Enable** dans **Settings → Integrations** est désactivé avec l'info-bulle *« Set up at least one flow before enabling Adapty integration. »* 1. Dans Adapty Mail, allez dans **Settings → Integrations**. 2. Cliquez sur **Enable Adapty integration** (ou **Enable** si l'intégration existe déjà suite à une configuration précédente). Une fois activée, Adapty envoie chaque événement d'abonnement — nouveaux abonnements, renouvellements, essais, conversions, remboursements, problèmes de facturation — dans Adapty Mail. Ces événements alimentent l'appartenance aux segments, le routage des campagnes et les conditions d'arrêt qui mettent en pause une séquence lorsqu'un utilisateur convertit. :::note Le bouton **Adapty integration** dans les paramètres n'est *pas* le même que l'espace de travail partenaire Adapty qui vous a connecté à Adapty Mail. L'espace de travail partenaire est ce qui a créé votre compte et (si vous vous êtes inscrit via Adapty) votre marque. Le bouton d'intégration ici contrôle la synchronisation des événements — il doit être activé par projet. ::: ## Dépannage \{#troubleshooting\} | Problème | Solution | | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Vérification DNS bloquée | Vérifiez que les enregistrements correspondent exactement — pas de points finaux, cibles CNAME correctes. Attendez 5 à 10 minutes, puis cliquez à nouveau sur **Check Verification** | | Fenêtre de vérification expirée | Vos enregistrements restent en place. Saisissez à nouveau votre domaine dans **Settings → Email Domains** pour démarrer une nouvelle fenêtre | | Génération échouée ou expirée | Vérifiez votre connexion internet et réessayez. Si le problème persiste, contactez le support Adapty | ## En savoir plus \{#learn-more\} - **[Collecter les emails des utilisateurs](mail-collect-emails)** : stratégies pour obtenir la couverture email si votre application ne les collecte pas encore. - **[Configurer votre domaine d'envoi](mail-sending-domain)** : détails des enregistrements DNS, niveaux de préchauffage et dépannage. - **[Configurer le paiement](mail-checkout)** : anatomie du tunnel de paiement et personnalisation. - **[Analytique des campagnes](mail-analytics)** : suivez la délivrabilité, l'engagement et les revenus. - **[Tests A/B](mail-ab-testing)** : testez plusieurs versions de séquences. --- # File: mail-collect-emails --- --- title: "Collecter les emails des utilisateurs pour Adapty Mail" description: "Transmettez les emails des utilisateurs et des identifiants stables à Adapty pour que les campagnes puissent les atteindre." --- Adapty Mail a besoin d'un `customer_user_id` stable et d'un email pour chaque utilisateur auquel il envoie des messages. Configurez les deux dans le code de votre application avant de lancer une campagne. ## Collecter les emails des utilisateurs \{#collect-user-emails\} Deux valeurs doivent parvenir à Adapty par utilisateur : un `customer_user_id` stable qui identifie l'utilisateur, et l'email lui-même. L'identification doit intervenir en premier — sans elle, Adapty n'a aucun profil auquel rattacher l'email. 1. **Identifiez l'utilisateur.** Transmettez un ID stable — l'ID utilisateur de votre backend, un UID Firebase, ou similaire — soit en le passant comme `customerUserId` à `.activate()` au démarrage du SDK, soit en appelant `Adapty.identify()` plus tard (par exemple, à la connexion). Dans tous les cas, l'ID doit être défini avant l'affichage d'un paywall. Guides par plateforme : [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Unity](unity-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Capacitor](capacitor-identifying-users). 2. **Transmettez l'email.** Dès que l'utilisateur fournit son email, envoyez-le à Adapty via `updateProfile` en utilisant le paramètre `email`. Guides par plateforme : [iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes), [Unity](unity-setting-user-attributes), [Kotlin Multiplatform](kmp-setting-user-attributes), [Capacitor](capacitor-setting-user-attributes). :::important - Transmettez toujours un `customer_user_id` **stable**, jamais un identifiant anonyme. Si un utilisateur désinstalle puis réinstalle votre application, Adapty utilise cet ID pour relier la réinstallation au profil existant et rattacher les achats au bon utilisateur. - Obtenez le consentement explicite de l'utilisateur avant de collecter et d'envoyer des emails à Adapty. Vous êtes responsable du respect du RGPD, du CAN-SPAM et des réglementations similaires sur vos marchés cibles. ::: <Details> <summary>Vérifier la couverture de vos emails</summary> Après avoir mis en place la collecte, vérifiez la couverture dans Adapty : 1. Rendez-vous dans **Customers → Profiles**. 2. Filtrez par profils ayant un email renseigné. Visez au moins 30 à 50 % de couverture email parmi vos utilisateurs actifs avant de lancer votre première campagne. Pas besoin d'attendre 100 % — lancez dès que vous atteignez 30 %. Les utilisateurs qui fournissent leur email ultérieurement sont automatiquement intégrés aux campagnes actives dès qu'ils remplissent les conditions. </Details> ## Stratégies de collecte des emails \{#email-collection-strategies\} La plupart des applications ne collectent pas d'emails par défaut. Choisissez l'approche qui correspond à l'état actuel de votre application. | Stratégie | Idéale pour | Comment ça marche | | -------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Authentification existante** | Les applications avec n'importe quelle forme de connexion | Vous avez déjà l'email — transmettez-le à Adapty après l'authentification de l'utilisateur. Consultez la référence par méthode d'authentification ci-dessous pour savoir où le lire. | | **Porte email avant le paywall** | Applications sans authentification — santé, bien-être, astrologie, retouche photo | Ajoutez un écran de saisie d'email entre l'onboarding et le paywall. Le taux de conversion atteint généralement 70 à 90 % car les utilisateurs ont déjà investi du temps. | | **Checkout du web paywall builder** | Peu de travail SDK ; email collecté sur le web | Le premier écran du web paywall builder collecte l'email et le transmet à Adapty — utile pour les utilisateurs qui cliquent sur une campagne avant qu'une porte in-app soit active. | | **Étape dans l'onboarding** | Onboarding sous forme de quiz (fitness, nutrition, éducation) | Placez une saisie d'email 2 à 3 étapes après le début de l'onboarding. Présentez-la comme une valeur ajoutée (« Nous vous enverrons votre plan personnalisé par email ») et évitez de rendre cette étape facultative. | | **API Adapty Mail** | Envoi d'emails depuis votre serveur, sans le SDK Adapty | Envoyez des profils au point de terminaison [Save profile](api-mail/operations/saveProfile) de l'API Adapty Mail. Voir [Envoyer des emails et des transactions via l'API Adapty Mail](mail-send-data-via-api). | ## Limitations \{#limitations\} - **Utilisateurs anonymes** : les utilisateurs sans `customer_user_id` stable ne peuvent pas recevoir de campagnes. Identifiez-les lorsqu'ils créent un compte ou se connectent — à partir de ce moment, tout email qu'ils fournissent est associé à leur profil Adapty. - **Utilisateurs sans email** : les profils sans email sont exclus de la diffusion des campagnes et n'apparaissent pas dans les analyses de campagnes. Dès qu'ils fournissent un email, ils deviennent éligibles aux futures campagnes. --- # File: mail-send-data-via-api --- --- title: "Envoyer des e-mails et des transactions via l'API Adapty Mail" description: "Envoyez des profils utilisateurs et des transactions à Adapty Mail directement depuis votre serveur, sans le SDK Adapty." --- L'API Adapty Mail vous permet d'envoyer des profils utilisateurs et des transactions à Adapty Mail directement depuis votre serveur, sans passer par le SDK Adapty. Utilisez-la quand vous souhaitez : - Ajouter des abonnés si vous n'avez pas encore de base dans Adapty Mail. - Réutiliser la base d'abonnés de vos autres applications. - Alimenter Adapty Mail en serveur à serveur, avec votre backend comme source de vérité. :::note **API ou SDK ?** La plupart des applications envoient les données à Adapty Mail via le SDK Adapty, qui collecte automatiquement les e-mails et les achats. Optez pour l'API quand votre application n'intègre pas le SDK Adapty, quand les données se trouvent déjà sur votre serveur, ou quand vous importez des abonnés depuis une autre source. ::: ## Avant de commencer \{#before-you-start\} :::warning Terminez la configuration d'Adapty Mail avant d'envoyer des données — cela inclut une campagne, des segments (si nécessaire), un paywall web et un flow lancé. Adapty Mail n'envoie des e-mails qu'aux profils créés après cette configuration ; les profils envoyés avant ne recevront aucun e-mail. Suivez d'abord le guide [Démarrer avec Adapty Mail](mail-get-started), puis revenez ici. ::: Vous avez également besoin de votre clé API et de l'URL de base : - **Clé API secrète** : dans Adapty Mail, rendez-vous dans **Settings** et copiez votre clé API secrète. La clé est spécifique au projet, ce qui permet à l'API de savoir à quel projet appartiennent les données. - **URL de base** : toutes les requêtes sont adressées à `https://api-mail.adapty.io`. - **Authentification** : envoyez la clé dans l'en-tête **Authorization** sous la forme `Bearer {your_secret_api_key}`. :::important Obtenez un consentement explicite avant de collecter des e-mails et de les envoyer à Adapty Mail. Vous êtes responsable du respect du RGPD, du CAN-SPAM et des réglementations similaires en vigueur sur vos marchés. ::: ## Envoyer des profils utilisateurs \{#send-user-profiles\} Un profil contient l'adresse e-mail de l'utilisateur et ses attributs. Pour en créer ou en mettre à jour un, envoyez une requête POST à `/api/v1/profile/save/`. Trois champs sont obligatoires : - Un `external_profile_id` stable, propre à votre application ou à votre backend - L'`email` auquel Adapty Mail envoie les campagnes - `external_created_at` — la date de création de l'utilisateur, utilisable dans les segments :::important Envoyez toujours un `external_profile_id` stable, jamais une valeur anonyme ou propre à une installation. Adapty Mail s'en sert pour associer les e-mails, les clics et les achats à un seul profil. ::: ```bash curl --request POST \ --url 'https://api-mail.adapty.io/api/v1/profile/save/' \ --header 'Authorization: Bearer {your_secret_api_key}' \ --header 'Content-Type: application/json' \ --data '{ "external_profile_id": "user_12345", "external_created_at": "2026-06-01T10:30:00Z", "email": "jane@example.com", "country": "US", "custom_attributes": { "plan": "trial" } }' ``` Consultez la référence [Save profile](api-mail/operations/saveProfile) pour la liste complète des champs disponibles. ## Envoyer des événements de transaction \{#send-transaction-events\} :::note Un profil avec une adresse e-mail suffit pour atteindre les utilisateurs dans le flow **never purchased**. Les utilisateurs dans tous les autres flows ont également besoin d'événements de transaction. ::: Tous les flows, sauf **never purchased**, reposent sur l'historique d'achats. Envoyez les événements de transaction d'un profil au fur et à mesure que vous gérez les achats, les renouvellements et les annulations, afin qu'Adapty Mail puisse le placer dans le bon flow. Les événements de transaction alimentent également l'attribution des revenus. Ne les envoyez pas uniquement si vous gérez exclusivement des campagnes **never purchased**. Pour enregistrer une transaction, envoyez une requête POST à `/api/v1/profile/transaction-event/save/`. Utilisez le même `external_profile_id` que celui envoyé avec le profil afin qu'Adapty Mail associe la transaction au bon utilisateur. ```bash curl --request POST \ --url 'https://api-mail.adapty.io/api/v1/profile/transaction-event/save/' \ --header 'Authorization: Bearer {your_secret_api_key}' \ --header 'Content-Type: application/json' \ --data '{ "event_type": "subscription_started", "event_id": "evt_abc123", "event_datetime": "2026-06-10T14:20:05Z", "external_profile_id": "user_12345", "store": "app_store", "store_product_id": "premium_monthly", "store_transaction_id": "1000000123456789", "store_original_transaction_id": "1000000123456789", "purchased_at": "2026-06-10T14:20:00Z", "originally_purchased_at": "2026-06-10T14:20:00Z", "price_usd": "9.99" }' ``` Consultez la référence [Save transaction event](api-mail/operations/saveTransactionEvent) pour la liste complète des champs disponibles. ### Associer vos événements aux flows \{#map-your-events-to-flows\} Envoyez l'`event_type` correspondant à ce qui s'est passé. Adapty Mail déduit l'état du profil à partir de son historique d'événements et le dirige vers le flow correspondant. | `event_type` | À envoyer quand | Flow | | --- | --- | --- | | `subscription_started` | Un utilisateur démarre un nouvel abonnement. | Active — no re-engagement flow | | `subscription_renewed` | Un abonnement se renouvelle automatiquement. | Active — no re-engagement flow | | `subscription_renewal_reactivated` | Un utilisateur réactive le renouvellement automatique. | Active — no re-engagement flow | | `non_subscription_purchase` | Un utilisateur effectue un achat unique. | Active — no re-engagement flow | | `subscription_renewal_cancelled` | Un utilisateur désactive le renouvellement automatique (l'abonnement reste actif jusqu'à expiration). | Renewal cancelled | | `billing_issue_detected` | Un paiement de renouvellement échoue. | Billing issue | | `entered_grace_period` | Le paiement échoue mais l'utilisateur est toujours dans un délai de grâce. | Billing issue | | `subscription_expired` | Un abonnement expire et l'accès prend fin. | Expired | | `subscription_refunded` | Un achat d'abonnement est remboursé. | Refunded | | `non_subscription_purchase_refunded` | Un achat unique est remboursé. | Refunded | --- # File: mail-brand --- --- title: "Marque dans Adapty Mail" description: "Consultez et affinez le profil de marque qui alimente la génération d'e-mails et les paywalls web." --- Une **marque** est un profil consolidé qu'Adapty Mail construit à partir des sources publiques de votre app — fiche App Store ou Google Play, page de destination, pages de conditions et de confidentialité, et profils sociaux. Il pilote la rédaction des e-mails, le ton, les visuels, le contenu des paywalls web et la démo. Une seule marque par projet ; chaque fonctionnalité en aval lit le même profil. Ouvrez la marque depuis l'entrée **Brand** dans la barre latérale d'Adapty Mail. - **Si vous vous êtes inscrit à Adapty Mail via Adapty** : votre marque a été créée automatiquement à partir de l'URL du store de votre projet Adapty. La page Brand s'ouvre sur le profil complet, prêt à être consulté et affiné. - **Si vous vous êtes inscrit en standalone** : la page Brand s'ouvre sur un écran de configuration — voir [Configurer depuis zéro](#set-up-from-scratch). ## Contenu d'un profil de marque \{#whats-in-a-brand-profile\} Une marque comporte 13 sections. Adapty Mail les utilise directement lors de la génération des e-mails et des paywalls web. - **Identity** : nom de l'app, description courte, accroche. - **Visual identity** : couleurs (principale, arrière-plan, secondaire, accent, texte, CTA), typographie, notes de style, URL du logo. - **Audience** : données démographiques, langues, marchés. - **Features** : chaque fonctionnalité a un nom, le bénéfice qu'elle apporte et une description facultative. - **Insights** : proposition de valeur unique, observations, objections courantes avec leurs réponses, et tags. - **Brand voice** : ton, niveau de formalité, vocabulaire, registre émotionnel. - **Voice samples** : exemples de titres, exemples de CTA et préréglages de ton utilisés lors de la génération des e-mails. - **Social proof** : nombre d'utilisateurs, note, nombre d'avis, mentions dans la presse, métriques clés. - **Social links** : Twitter, Instagram, TikTok, YouTube, Facebook, LinkedIn. - **Legal links** : URL des conditions, URL de la confidentialité, e-mail d'assistance. - **Reviews** : avis utilisateurs extraits de la source du store — contenu, auteur, note, source. - **Pain points** : énoncés de problèmes issus des avis ou des signaux sociaux. - **FAQs** : questions et réponses utilisées dans le contenu des e-mails et les sections des paywalls web. ## Modifier une section manuellement \{#edit-a-section-manually\} Chaque section de la vue marque dispose d'un bouton **Edit**. En cliquant dessus, un éditeur inline s'ouvre pour cette section. 1. Cliquez sur **Edit** dans la section à modifier. 2. Mettez les champs à jour directement. Adapty Mail suit les modifications non enregistrées sous forme de brouillon. 3. Cliquez sur **Save** dans la bannière de brouillon en haut de la page pour appliquer. Cliquez sur **Discard** pour annuler les modifications. Une seule section peut être ouverte à la fois. Si vous essayez d'en ouvrir une deuxième, la première vous invite à terminer ou à annuler. :::important Les modifications sont suspendues pendant qu'une source est en cours de traitement — une source en fin de traitement pourrait écraser vos modifications en cours. Tout éditeur ouvert se ferme automatiquement au démarrage du traitement, et le bouton **Save** reste désactivé dans la bannière de brouillon jusqu'à la fin du traitement. ::: ## Affiner avec l'IA \{#refine-with-ai\} Le bouton **Refine with AI** en bas à droite ouvre un panneau de chat à côté de la marque. Décrivez les modifications en langage courant ; l'IA propose un brouillon affiné que vous pouvez enregistrer ou rejeter. 1. Cliquez sur **Refine with AI**. 2. Décrivez la modification. La portée du chat se limite aux modifications de la marque — il ne répondra pas aux questions générales ni ne réécrira du contenu en dehors du profil de marque. 3. Consultez le brouillon proposé dans la vue principale. Adapty Mail met en évidence les sections modifiées. 4. Cliquez sur **Save** dans la bannière de brouillon pour appliquer, ou sur **Discard** pour conserver la marque enregistrée. Exemples de prompts utiles : - « Rendre le ton plus ludique. » - « Ajouter la fonctionnalité mode hors ligne. » - « Renforcer la proposition de valeur unique. » - « Réécrire la description de l'audience pour le marché américain. » ## Ajouter des sources \{#add-more-sources\} La source du store constitue la base du profil. D'autres types de sources affinent des sections spécifiques — les pages de destination améliorent l'identité visuelle et le texte, les pages de conditions et de confidentialité améliorent les liens légaux, les profils sociaux améliorent les exemples de voix et la preuve sociale. Dans la vue marque, le panneau **Sources** liste toutes les sources et un formulaire **Add** en dessous. Choisissez un type, collez l'URL et cliquez sur **Add**. - **App Store** : `https://apps.apple.com/...` - **Google Play** : `https://play.google.com/store/apps/details?id=...` - **Landing page** : votre site marketing, par exemple `https://yourapp.com`. - **Terms / Privacy** : un lien direct vers vos conditions ou votre page de confidentialité. - **Social profile** : URL Twitter, Instagram, TikTok, YouTube, Facebook ou LinkedIn. Une seule source par type. Le sélecteur désactive un type dès qu'une source de ce type est en cours de traitement ou terminée. Pour remplacer une source, supprimez la marque et recommencez l'intégration — les sources individuelles ne peuvent pas être supprimées. ## Configurer depuis zéro \{#set-up-from-scratch\} Si votre projet n'a pas encore de marque (cas typique pour les inscriptions standalone à Adapty Mail), la page **Brand** s'ouvre sur un écran de configuration. La source du store — App Store ou Google Play — constitue la fondation ; d'autres types de sources peuvent être ajoutés ensuite. 1. Choisissez le store (**App Store** ou **Google Play**) et collez l'URL de la fiche. 2. Cliquez sur **Build my brand**. Adapty Mail récupère la page, analyse les avis et déduit votre voix de marque. Le traitement prend généralement moins d'une minute. 3. Une fois le traitement terminé, la vue marque s'ouvre avec les 13 sections remplies. Si une source échoue (URL invalide, page inaccessible, erreur de parsing), l'écran affiche le message d'erreur et un bouton **Try again**. Corrigez l'URL et soumettez à nouveau. ## Utilisation de la marque \{#where-the-brand-is-used\} La marque est utilisée par toutes les fonctionnalités en aval qui ont besoin de savoir à quoi ressemble et comment sonne votre app : - **Génération d'e-mails** : le texte, le ton, les visuels, le bloc expéditeur et les images hero lisent tous depuis la marque. Voir [Créer une campagne](mail-create-campaign). - **Éditeur de paywall web** : la marque est un prérequis pour la génération de paywall — sans `brand_saved`, la génération est bloquée. Voir [Configurer le checkout](mail-checkout). - **Onboarding** : l'étape **Set up brand** dans la liste de contrôle d'onboarding passe à terminé dès qu'une marque existe. ## Supprimer une marque \{#delete-a-brand\} L'action **Delete brand** se trouve dans la **Danger zone** en bas de la vue marque. 1. Cliquez sur **Delete** dans la section Danger zone. 2. Confirmez dans la boîte de dialogue. La suppression efface le profil de marque et toutes les sources. L'opération est irréversible — pour récupérer, collez une URL App Store ou Google Play sur l'écran de démarrage et recommencez l'intégration depuis zéro. :::warning Les campagnes existantes conservent le snapshot de marque avec lequel elles ont été générées, mais les nouvelles campagnes et générations de paywall sont bloquées jusqu'à ce que vous recommenciez l'intégration d'une marque. ::: ## Limitations \{#limitations\} - **Une seule marque par projet** : chaque projet Adapty Mail possède une seule marque. Pour cibler une app différente, créez un nouveau projet. - **Une seule source par type** : une marque peut avoir au maximum une source App Store, une source Google Play, une page de destination, une source conditions/confidentialité et un profil social. - **Pas de suppression individuelle de source** : les sources individuelles ne peuvent pas être supprimées depuis l'interface. Utilisez **Delete brand** si une source doit être remplacée. - **Modifications suspendues pendant le traitement** : les modifications de section, les enregistrements via le chat d'affinage et la suppression de la marque sont tous bloqués tant qu'une source est à l'état `pending` ou `processing`. - **Les sources échouées restent listées** : une source à l'état `failed` reste visible dans le panneau avec son message d'erreur. Soumettez à nouveau le même type pour réessayer — l'entrée échouée est remplacée lorsqu'une nouvelle planification réussit. --- # File: mail-sending-domain --- --- title: "Configurer votre domaine d'envoi pour Adapty Mail" description: "Ajoutez des enregistrements DNS, vérifiez votre domaine et comprenez le warm-up pour qu'Adapty Mail puisse envoyer en votre nom." --- Adapty Mail envoie vos campagnes depuis votre propre domaine — et non depuis une adresse partagée — ce qui vous permet de garder la maîtrise de votre réputation d'expéditeur. La configuration se fait une seule fois, et toutes vos campagnes utilisent le même domaine vérifié. Pour les étapes essentielles, consultez la section domaine dans [Débuter avec Adapty Mail](mail-get-started#2-set-up-your-sending-domain). Cet article couvre la configuration complète, le fonctionnement de la vérification et le comportement automatique de warm-up. ## Prérequis \{#requirements\} - **Domaine apex** : renseignez votre domaine racine (par exemple `yourapp.com`), pas un sous-domaine. Les entrées comme `app.yourapp.com` sont rejetées lors de la validation. - **Enregistrements NS actifs** : le domaine doit être résolvable. Adapty Mail effectue une résolution DNS lors de la configuration et refuse les domaines sans enregistrements NS valides. - **Un domaine par projet Adapty** : un domaine ne peut pas être partagé entre plusieurs projets. Si le domaine est déjà enregistré dans un projet — qu'il vous appartienne ou non — la configuration échoue. ## Configurer votre domaine d'envoi \{#set-up-your-sending-domain\} L'assistant de configuration comporte trois écrans : saisir le domaine, confirmer les sous-domaines générés, puis ajouter les enregistrements DNS. Tout se passe dans **Settings → Email Domains**. 1. **Saisissez votre domaine.** Tapez votre domaine apex dans le champ **Domain** et cliquez sur **Preview**. Adapty Mail valide le format (ASCII, deux labels, sans tirets en début ou fin, TLD de 2 caractères minimum) et vérifie que le DNS est résolvable. 2. **Confirmez les sous-domaines.** Adapty Mail génère deux sous-domaines d'envoi avec des préfixes fixes — `mail.yourapp.com` et `email.yourapp.com` — chacun avec sa propre identité SES. Il crée également un sous-domaine Mail-From sous chacun d'eux (`hello.mail.yourapp.com` et `hello.email.yourapp.com`). Vérifiez-les puis cliquez sur **Confirm**. 3. **Ajoutez les enregistrements DNS.** Le dernier écran liste tous les enregistrements à ajouter — 10 au total, 5 par sous-domaine d'envoi, plus un enregistrement DMARC optionnel sur le domaine racine. Utilisez **Download CSV** pour exporter la liste complète, ou copiez les enregistrements un par un dans votre bureau d'enregistrement. Cliquez sur **Done** une fois les enregistrements en place. <Details> <summary>Référence des enregistrements DNS</summary> Pour chaque sous-domaine d'envoi (`mail.yourapp.com` et `email.yourapp.com`), ajoutez : **DKIM — 3 enregistrements CNAME.** Signatures cryptographiques prouvant que l'e-mail n'a pas été altéré en transit. | Champ | Format | | ------ | ----------------------------------- | | Type | CNAME | | Nom | `{token}._domainkey.{subdomain}` | | Valeur | `{token}.dkim.amazonses.com` | **Mail-From — 1 enregistrement MX.** Gère les bounces. | Champ | Format | | -------- | -------------------------------------------------------------- | | Type | MX | | Nom | `hello.{subdomain}` (par exemple, `hello.mail.yourapp.com`) | | Priorité | `10` | | Valeur | `feedback-smtp.{region}.amazonses.com` | **SPF — 1 enregistrement TXT.** Autorise Adapty à envoyer en votre nom. | Champ | Format | | ------ | -------------------------------------- | | Type | TXT | | Nom | `hello.{subdomain}` | | Valeur | `"v=spf1 include:amazonses.com ~all"` | Sur votre domaine racine, ajoutez l'enregistrement DMARC optionnel : | Champ | Format | | ------ | --------------------- | | Type | TXT | | Nom | `_dmarc.{domain}` | | Valeur | `v=DMARC1; p=reject` | Les tokens, la région et toutes les autres valeurs sont fournis par AWS SES lors de la configuration. Copiez-les toujours depuis l'écran des enregistrements DNS dans Adapty Mail, et non depuis cette référence. </Details> ## Fonctionnement de la vérification \{#how-verification-works\} Une fois les enregistrements DNS en place, Adapty Mail interroge le DNS automatiquement, et vous pouvez également déclencher des vérifications manuellement. - **Interrogation automatique** : elle démarre 5 minutes après votre soumission, puis l'intervalle double à chaque tour — 10 min, 20 min, 40 min — avant de plafonner à 60 min. Elle se poursuit jusqu'à ce que les enregistrements soient trouvés ou que la fenêtre de 7 jours se ferme. - **Vérification manuelle** : cliquez sur **Check Verification** pour forcer une vérification immédiate. Un délai de 60 secondes s'applique entre deux vérifications manuelles — si vous l'activez trop vite, le message *"Verification check is on cooldown."* s'affiche. - **États de statut** : le DKIM et le Mail-From de chaque sous-domaine sont suivis indépendamment avec les statuts **Pending**, **Success** ou **Failed**. Un domaine est considéré entièrement vérifié uniquement lorsque les quatre statuts affichent **Success**. - **Délai de 7 jours** : si la vérification ne se termine pas dans les 7 jours, l'identité est marquée **Failed**. Vos enregistrements DNS restent dans votre bureau d'enregistrement — saisissez à nouveau le domaine dans **Settings → Email Domains** pour démarrer une nouvelle fenêtre. - **Après la vérification** : si vous supprimez ou modifiez des enregistrements DNS par la suite, AWS SES finit par dégrader l'identité. Conservez les enregistrements en place aussi longtemps que vous souhaitez envoyer. - **Propagation DNS** : elle prend généralement quelques minutes, mais peut aller jusqu'à 48 heures dans de rares cas. ## Warm-up du domaine \{#domain-warm-up\} Les nouveaux domaines n'ont aucune réputation auprès des fournisseurs de messagerie comme Gmail ou Yahoo, et des envois à volume élevé depuis un domaine tout neuf risquent d'atterrir dans les spams. Adapty Mail gère le warm-up automatiquement en augmentant progressivement votre limite d'envoi quotidienne sur 14 paliers. Aucune configuration n'est nécessaire. ### Fonctionnement des paliers \{#how-tiers-work\} Votre domaine démarre au **Palier 1** (200 envois/jour) et avance automatiquement tant que les métriques de délivrabilité restent saines. Si les taux de bounce augmentent ou que les taux de plaintes grimpent, la progression est suspendue et peut reculer jusqu'à ce que la réputation se rétablisse. | Palier | Limite quotidienne | | ------ | ------------------ | | 1 | 200 | | 2 | 400 | | 3 | 800 | | 4 | 1 500 | | 5 | 2 500 | | 6 | 4 000 | | 7 | 6 000 | | 8 | 8 000 | | 9 | 10 000 | | 10 | 13 000 | | 11 | 16 000 | | 12 | 20 000 | | 13 | 25 000 | | 14 | 30 000 | Votre palier actuel et votre limite quotidienne sont affichés dans **Settings → Email Domains**. ### Impact sur le lancement selon la taille de l'audience \{#impact-on-launch-by-audience-size\} | Taille de l'audience | Effet au lancement | | --------------------- | ----------------------------------------------- | | Moins de 200 contacts | Toute l'audience est atteinte dès le premier jour | | 200 à 2 000 contacts | La livraison s'étale sur plusieurs jours | | Plus de 2 000 contacts | La livraison s'étale sur 1 à 2 semaines | :::tip Lancez votre première campagne dès que la vérification DNS est terminée. Plus vous commencez à envoyer tôt, plus vite votre domaine progresse dans les paliers et atteint sa capacité quotidienne maximale. ::: ## Limitations \{#limitations\} - **Un domaine par projet** : vous ne pouvez avoir qu'un seul domaine d'envoi par projet Adapty. Pour passer à un autre domaine, contactez le support — le tableau de bord ne propose pas d'action « changer de domaine ». - **Unicité inter-projets** : un domaine déjà enregistré dans un autre projet ne peut pas être réutilisé. Si vous voyez *"Domain is already registered to another project"*, choisissez un domaine différent ou contactez le support. - **Les domaines vérifiés ne peuvent pas être supprimés** : une fois qu'un sous-domaine atteint le statut **Success**, le tableau de bord bloque la suppression. Les domaines en attente peuvent être supprimés, mais vous devrez tout de même retirer manuellement les enregistrements DNS de votre bureau d'enregistrement. - **Préfixes de sous-domaines fixes** : `mail.`, `email.`, et le préfixe Mail-From `hello.` sont codés en dur — ils ne peuvent pas être personnalisés. Si ces sous-domaines sont déjà utilisés dans votre DNS, la configuration entrera en conflit. - **Domaines apex uniquement** : les entrées de sous-domaines, les points finaux et les noms d'hôte à un seul label sont rejetés. - **Pas de domaines internationalisés** : Punycode et IDN ne sont pas pris en charge. Le domaine doit être en ASCII uniquement. ## Dépannage \{#troubleshooting\} | Problème | Solution | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | "Enter a valid domain (e.g. example.com)" | Vérifiez la saisie : domaine apex uniquement, ASCII uniquement, TLD de 2 caractères minimum, sans tirets en début ou fin. | | "Domain does not have valid DNS records" | Le domaine apex lui-même doit être résolvable. Vérifiez que vos enregistrements NS sont actifs avant de réessayer. | | "Domain is already registered to another project" | Choisissez un autre domaine, ou contactez le support si vous pensez que l'enregistrement est une erreur. | | "Verification check is on cooldown" | Attendez 60 secondes entre deux vérifications manuelles. L'interrogation automatique se poursuit en arrière-plan. | | Vérification bloquée sur Pending | Vérifiez que les enregistrements DNS correspondent exactement — sans points finaux, cibles CNAME correctes. Le DNS peut prendre jusqu'à 48 heures à se propager. | | "Cannot delete domain: one or more identities have been successfully verified" | Un domaine vérifié ne peut pas être retiré du tableau de bord. Contactez le support pour obtenir de l'aide. | | E-mails classés en spam | Vérifiez que votre enregistrement DMARC est publié. Les nouveaux domaines ont besoin d'un temps de warm-up — consultez [Warm-up du domaine](#domain-warm-up). | | Taux de bounce élevé | Assurez-vous que votre liste d'audience contient des adresses valides et ayant donné leur consentement. Les bounces ralentissent ou suspendent la progression dans les paliers. | --- # File: mail-checkout --- --- title: "Configurer le paiement pour Adapty Mail" description: "Créez un paywall web et connectez un prestataire de paiement pour offrir à vos campagnes e-mail un paiement en ligne personnalisé." --- Chaque e-mail envoyé par Adapty Mail contient un lien de paiement unique pour le destinataire. En cliquant dessus, l'utilisateur accède à un tunnel de paiement web qui l'identifie par profil, lui présente votre offre et traite le paiement. Les tunnels de paiement se trouvent dans **Web Paywalls** au sein d'Adapty Mail et sont modifiés dans le **web paywall builder** intégré. ## Prérequis \{#requirements\} - Un prestataire de paiement web avec vos produits d'abonnement configurés. **Generate with AI** prend uniquement en charge Stripe et se connecte dans le builder. **Use your own hosted paywall** accepte n'importe quel prestataire — Stripe, Paddle, PayPal ou autre — puisque le paiement est géré de votre côté. Vous n'avez pas besoin d'un compte séparé pour le web paywall builder. Il est intégré à Adapty Mail : un espace de travail est provisionné automatiquement lors de votre première connexion, et vous êtes connecté à l'éditeur avec vos identifiants Adapty. Cela est indépendant de tout paywall web que vous pourriez avoir configuré sur la page paywall du tableau de bord Adapty principal — les paywalls web d'Adapty Mail sont des entités distinctes, gérées entièrement depuis Adapty Mail. ## Configurer votre tunnel de paiement \{#set-up-your-checkout-funnel\} Dans Adapty Mail, accédez à **Web Paywalls → Create**. Deux options s'offrent à vous : - **Generate with AI** : le web paywall builder intégré à Adapty Mail génère le tunnel pour vous. Stripe uniquement — pour Paddle ou PayPal, utilisez la seconde option. - **Use your own hosted paywall** : intégrez un paywall que vous hébergez déjà, quel que soit le prestataire de paiement. ### Générer avec l'IA \{#generate-with-ai\} La page de création affiche un panneau **Prerequisites** en haut avec des boutons d'action intégrés qui vous guident à travers chaque précondition — préparation de la marque, connexion au builder, connexion Stripe, produits et une étape finale de révision et publication. Suivez les étapes ; le panneau se rafraîchit à mesure que chaque étape est complétée. Lorsque les prérequis sont au vert, cliquez sur **Generate** pour ouvrir la boîte de dialogue de génération. Deux choix à faire : - **Environment** : choisissez **Production** ou **Sandbox**. Sandbox utilise vos produits Stripe en mode test et est la valeur par défaut sécurisée pour les environnements de développement et locaux — son compte est isolé de la production, donc les transactions de test n'affectent jamais les données en direct. - **Plans** : choisissez jusqu'à **3 plans Stripe**. Chaque plan est une combinaison produit + prix. Le paywall présente ces éléments comme les offres au moment du paiement. Si vous choisissez moins de 3 plans, le paywall n'affiche que les plans sélectionnés. Cliquez sur **Generate** pour lancer la génération. Une fois terminé, ouvrez l'éditeur dans le builder pour vérifier le résultat et publier. Ensuite, cliquez sur **Save**. :::important Le paywall doit être publié avant de pouvoir traiter le trafic de paiement. Les paywalls non publiés renvoient une erreur lorsque les utilisateurs cliquent sur les liens de paiement dans les e-mails. ::: Pour les détails du prestataire de paiement dans le builder (comptes Stripe, mode test ou live, configuration des produits), consultez [Configuration du paywall web](web-paywall-configuration). ### Utiliser votre propre paywall hébergé \{#use-your-own-hosted-paywall\} 1. Sur la page de création, sélectionnez **Enter URL manually**. 2. Collez l'URL de votre paywall hébergé. Elle doit inclure les espaces réservés `{email}` et `{external_profile_id}` en tant que paramètres de requête — Adapty Mail les remplace par les données de chaque destinataire afin que la page sache qui est le visiteur. Exemple : ``` https://example.com/paywall?email={email}&profile={external_profile_id} ``` 3. Enregistrez. Cette option fonctionne avec n'importe quel prestataire de paiement — Adapty Mail ne gère que la redirection et la substitution des paramètres ; le paiement et la personnalisation se font entièrement de votre côté. ## À quoi ressemble le paiement \{#what-the-checkout-looks-like\} Lorsqu'un utilisateur clique sur un lien de paiement, il accède à la **Main conversion page**. Après avoir tenté un paiement, il voit soit **Payment success**, soit **Payment failed** — une seule est affichée par tentative. **Main conversion page** Une présentation commerciale pleine page. L'IA génère le texte et les images pour chaque section : | Section | Ce que l'IA génère | |---|---| | Headline | Titre accrocheur axé sur les bénéfices | | Subheadline | Proposition de valeur complémentaire | | Offer badge | Badge d'urgence (sans prix inventés — utilise un langage promotionnel vague) | | CTA button | Texte orienté action, 2 à 5 mots | | Benefits | 3 à 6 cartes de bénéfices avec emoji et texte | | Features | 3 à 8 descriptions de fonctionnalités avec titre et sous-titre | | Plans | Titre de sélection du plan et texte du minuteur d'offre | | Social proof | Texte de preuve communautaire et 3 à 5 avis d'utilisateurs réalistes | | FAQ | 3 à 6 questions et réponses courantes | | Guarantee | Texte de garantie satisfait ou remboursé | **Payment success** Un message de félicitations avec les prochaines étapes et une image générée par l'IA. **Payment failed** Un message convivial invitant l'utilisateur à réessayer. L'état du paiement est conservé. ## Comment fonctionne la personnalisation \{#how-personalization-works\} Chaque e-mail contient une URL de paiement unique avec le `customer_user_id` et l'adresse e-mail du destinataire intégrés en tant que paramètres : ``` https://your-funnel.com/?cid={{customer_user_id}}&email={{email}} ``` Adapty génère ces URLs automatiquement lors de l'envoi de chaque e-mail — aucune configuration dans le web paywall builder n'est requise. Lorsque l'utilisateur clique, le builder lit les paramètres pour l'identifier. Lorsqu'un achat est finalisé, Adapty associe le revenu à l'e-mail spécifique qui a déclenché la conversion. Ces données apparaissent dans [Analytiques des campagnes](mail-analytics). ## Résolution des problèmes \{#troubleshooting\} | Problème | Solution | |---|---| | Le lien de paiement ne s'ouvre pas | Vérifiez que le paywall est publié dans le web paywall builder | | L'utilisateur n'est pas identifié au moment du paiement | Confirmez que `Adapty.identify()` a été appelé avec le bon identifiant utilisateur avant l'envoi de l'e-mail | | L'achat n'est pas attribué à l'e-mail | Vérifiez que le paramètre `cid` est présent dans l'URL de paiement — contactez le support si les paramètres sont manquants | --- # File: mail-email-campaigns --- --- title: "Campagnes email dans Adapty Mail" description: "Concevez des séquences multi-emails, choisissez le bon ton et ciblez les bons utilisateurs." --- Une campagne dans Adapty Mail est une séquence multi-emails complète — textes, design, images principales et délais — générée pour votre application en une seule passe. Une campagne seule n'envoie rien : elle est enregistrée comme **brouillon** et ne commence à être diffusée qu'une fois rattachée à un [flow](mail-create-flow), qui la lie à un déclencheur et une audience. Utilisez les guides ci-dessous pour créer des campagnes, choisir le bon ton et cibler les bons utilisateurs. <CustomDocCardList ids={['mail-create-campaign', 'mail-suppression']} /> --- # File: mail-create-campaign --- --- title: "Create a campaign in Adapty Mail" description: "Generate a complete email sequence from your app's store metadata and refine it before attaching to a flow." --- Adapty Mail génère une séquence d'e-mails complète — textes, design, images hero, lignes d'objet et délais — à partir des métadonnées de votre app dans le store. Aucune rédaction ni conception graphique requise. La campagne est sauvegardée en tant que brouillon ; elle ne commence à être envoyée qu'une fois que vous l'attachez à un [flow](mail-create-flow). ## Avant de commencer \{#before-you-start\} - **Paywall web enregistré** : chaque campagne doit être liée à un paywall web. Le backend rejette les campagnes sans paywall. Consultez [Créer un paywall web](mail-get-started#3-create-a-web-paywall) si vous n'en avez pas encore. - **Profil de marque** : l'IA utilise votre profil de marque pour définir le contenu, le ton et les visuels de la séquence. Configurez-le dans Adapty Mail sous **Brand** si ce n'est pas encore fait — consultez [Brand](mail-brand). ## 1. Générer la séquence \{#1-generate-the-sequence\} 1. Dans Adapty Mail, accédez à **Campaigns** et cliquez sur **Create**. 2. Définissez le nom de la campagne. 3. Dans le menu déroulant **Web paywall**, sélectionnez le paywall web vers lequel vous souhaitez que les e-mails renvoient. 4. Cliquez sur **Generate emails**. 5. Remplissez le formulaire de génération : - **Tone** : Choisissez dans la liste. Les options sont générées spécifiquement pour la catégorie de votre application — une autre application verra des options différentes. Votre choix influence les lignes d'objet, les titres, le corps du texte et les CTA de chaque e-mail ; il n'affecte pas la mise en page ni les images hero. - **Language** : Choisissez la langue des e-mails. - **Custom prompt** (facultatif) : Instructions libres jusqu'à 2 000 caractères. Utilisez-le pour mentionner une promo, une occasion, une nuance d'audience, des points à inclure obligatoirement, ou des indications de ton supplémentaires que les préréglages ne couvrent pas. - **Number of emails** : Par défaut, l'IA détermine le nombre d'e-mails selon les bonnes pratiques et le contexte de votre application. Pour le définir vous-même, cliquez sur **Set number manually** et choisissez une valeur (**1–15**, par défaut **4**). Une fois que vous cliquez sur **Generate**, le ton est verrouillé pour cette campagne. Pour essayer un autre ton, créez une nouvelle campagne — chaque génération peut produire une combinaison d'options différente. 6. Cliquez sur **Generate**. La génération prend généralement quelques minutes. Le backend expire après 5 minutes s'il ne peut pas terminer — réessayez si c'est le cas. ## 2. Révision et affinement \{#2-review-and-refine\} Après la génération, la séquence complète s'affiche dans un aperçu. Pour chaque e-mail, vous pouvez voir : - **Variantes de ligne d'objet** : Trois options d'objet par e-mail. Adapty Mail les teste à la livraison et continue d'envoyer celle qui obtient les meilleurs résultats — voir [test A/B](mail-ab-testing). - **Titre, corps de texte et CTA** : Le bloc de contenu principal. - **Image hero** : Une image générée en accord avec le contenu de l'e-mail et votre marque. - **Mise en page et délai** : La disposition de l'e-mail et le délai après lequel il est envoyé par rapport au précédent. L'en-tête de prévisualisation comporte un **bouton de thème** (Auto, Clair, Sombre) — des boutons icônes en haut à droite du volet de prévisualisation. Il contrôle uniquement le rendu de la prévisualisation ; le contenu généré est identique dans tous les modes. Utilisez-le pour vérifier l'apparence de chaque e-mail selon chaque schéma de couleurs sans avoir à regénérer. Vous pouvez : - **Régénérer des emails individuels** : l'IA réécrit le contenu et génère une nouvelle image principale pour un seul email. La position, le timing et le système de design global (couleurs, typographie, mode sombre) restent inchangés — seul l'email ciblé est modifié. - **Modifier le HTML directement** : un éditeur de code HTML s'ouvre pour un contrôle fin sur tout ce que l'IA n'a pas bien rendu. :::note Les e-mails s'adaptent automatiquement. Les mises en page multi-colonnes se réduisent à une seule colonne sur les écrans de moins de 620 px, et chaque disposition est testée sur Gmail (web et mobile), Apple Mail (macOS et iOS), Outlook desktop, Yahoo Mail et Samsung Mail — en mode clair et en mode sombre. ::: ## 3. Enregistrer en tant que brouillon \{#3-save-as-a-draft\} Cliquez sur **Create** pour enregistrer la campagne en tant que brouillon. Aucun e-mail n'est encore envoyé — l'éditeur de campagne ne dispose pas d'action « publier » ou « lancer » distincte. Le statut d'une campagne reflète si elle est associée à un flow actif : - **draft** : Non associée à un flow. - **live** : Associée à un flow et acheminant actuellement les utilisateurs. - **inactive** : Était associée, mais le wrapper de test A/B du flow a pris fin. - **archived** : Supprimée du tableau de bord. :::important Un brouillon de campagne n'envoie jamais rien par lui-même. Pour commencer à envoyer des e-mails, vous devez soit : - Attachez la campagne directement à un [flow](mail-create-flow), ou - Incluez-la dans un [test A/B](mail-ab-testing) et attachez le test A/B à un flow. Tant que vous ne faites ni l'un ni l'autre, la campagne reste en `draft` et aucun destinataire n'est atteint. ::: --- # File: mail-suppression --- --- title: "Désabonnement et suppression dans Adapty Mail" description: "Comment Adapty Mail cesse d'envoyer des e-mails aux utilisateurs — via le désabonnement, les bounces SES, les plaintes et le mécanisme de condition d'arrêt." --- Adapty Mail cesse d'envoyer des e-mails à un utilisateur dans deux cas distincts : - **Suppression** : L'utilisateur est exclu de tous les envois futurs dans ce projet (désabonné, bounce, plainte, rejet ou limitation de débit). - **Condition d'arrêt** : La séquence en cours de l'utilisateur est annulée parce qu'il a converti. Il n'est pas supprimé et reste éligible aux autres campagnes. Ces deux mécanismes sont propres à chaque projet. Une suppression dans un projet Adapty n'affecte pas les autres. ## Désabonnement \{#unsubscribe\} Chaque e-mail envoyé par Adapty Mail contient un lien de désabonnement dans le pied de page. 1. L'utilisateur clique sur le lien. Adapty Mail ouvre une page de confirmation. 2. L'utilisateur confirme. Le backend marque le profil avec `suppression_reason = 'unsubscribe'`, annule la séquence restante et exclut le profil des envois futurs dans le projet. Le token dans l'URL de désabonnement encode le `profile_id` et le `scheduled_email_id`, donc aucune connexion n'est requise. :::note Adapty Mail envoie également l'en-tête `List-Unsubscribe: <URL>, <mailto:>` accompagné de `List-Unsubscribe-Post: List-Unsubscribe=One-Click`. Gmail et Yahoo l'exigent pour les expéditeurs en masse (RFC 8058). Les clients qui prennent en charge cet en-tête proposent un bouton de désabonnement en un clic directement depuis la boîte de réception — sans page de confirmation. ::: ## Suppression automatique \{#automatic-suppression\} Adapty Mail écoute les événements de livraison AWS SES via SNS et supprime l'utilisateur immédiatement dans l'un des cas suivants : | Événement | Code de raison | Signification | | --------- | -------------- | ------------------------------------------------------------------------------------------ | | Bounce | `bounce` | L'adresse e-mail est invalide, la boîte aux lettres est pleine ou le domaine n'existe pas. | | Plainte | `complaint` | L'utilisateur a marqué l'e-mail comme spam. | | Rejet | `reject` | SES a rejeté le message avant l'envoi. | | Limitation | `throttle` | Le débit d'envoi a dépassé les limites de sécurité du domaine. | Pour chaque événement, le résultat est le même : l'utilisateur est ajouté à la liste de suppression, la séquence restante est annulée et il est exclu des envois futurs dans le projet. :::important Adapty Mail ne fait **pas** la distinction entre les hard bounces et les soft bounces. Tout bounce — y compris les situations temporaires comme une boîte aux lettres pleine — supprime l'utilisateur immédiatement. Il n'y a pas de fenêtre de nouvelle tentative. ::: ## Condition d'arrêt \{#stop-condition\} Lorsqu'un utilisateur convertit en cours de séquence, Adapty Mail annule ses e-mails restants avec la raison `stop_condition`. La conversion signifie que l'état de son abonnement atteint **Subscribed**, ou que l'état de son achat unique atteint **Purchased**. La condition d'arrêt est différente de la suppression : - **Suppression** : Exclut l'utilisateur de tous les envois futurs dans le projet. - **Condition d'arrêt** : Annule uniquement la séquence en cours. L'utilisateur reste éligible aux autres campagnes — par exemple, un flow de renouvellement ou de reconquête ciblant les abonnés actifs. Les annulations par condition d'arrêt apparaissent aux côtés des suppressions dans les analyses de campagne. ## Gérer la suppression \{#managing-suppression\} Adapty Mail ne dispose pas d'interface dans le tableau de bord pour consulter ou retirer les utilisateurs supprimés. Pour annuler la suppression d'un profil — par exemple, quelqu'un qui a accidentellement marqué un e-mail de test comme spam — contactez le support Adapty. ## Ce qu'Adapty Mail gère pour la conformité \{#what-adapty-mail-handles-for-compliance\} Adapty Mail inclut : - **Lien de désabonnement** : Inclus dans le pied de page de chaque e-mail, traité immédiatement à la confirmation de l'utilisateur. - **En-têtes List-Unsubscribe** : Envoyés avec chaque e-mail pour un désabonnement en un clic depuis la boîte de réception (RFC 8058). - **Suppression automatique** : Déclenchée lors des événements SES de bounce, plainte, rejet et limitation de débit. Éléments dont vous êtes responsable : - **Adresse postale physique** : CAN-SPAM en exige une dans le pied de page de l'e-mail. Adapty Mail ne l'injecte pas — ajoutez-la dans la conception de votre campagne. - **Consentement explicite à l'opt-in** : Collectez-le avant de transmettre l'adresse e-mail d'un utilisateur à Adapty. Voir [Collecter les e-mails des utilisateurs](mail-collect-emails). - **Demandes d'effacement RGPD** : Adapty Mail n'expose pas de point de terminaison « supprimer mes données ». Contactez le support Adapty si un utilisateur invoque son droit à l'effacement. --- # File: mail-flows --- --- title: "Flows dans Adapty Mail" description: "Comment les flows acheminent les campagnes vers les bons utilisateurs au bon moment — déclencheurs, segments et règles de priorité." --- <CustomDocCardList ids={['mail-create-flow']} /> Un **flow** transforme une campagne sauvegardée en envois planifiés. Il associe un événement déclencheur (l'état d'abonnement d'un utilisateur) à un segment (les utilisateurs concernés) et à la campagne qu'ils reçoivent. Adapty Mail évalue chaque flow dès qu'un événement correspondant se produit — pas de polling, pas de cron, pas de lancement manuel. ## Déclencheurs \{#triggers\} Adapty Mail propose cinq déclencheurs fixes, chacun avec sa propre vue dans **Flows** : - **Never purchased** : Utilisateurs qui se sont inscrits mais n'ont pas encore effectué d'achat. Objectif : activation et première conversion. Les utilisateurs en période d'essai ne sont pas inclus ici — démarrer un essai compte comme un abonnement actif. - **Renewal cancelled** : Utilisateurs qui ont désactivé le renouvellement automatique mais dont l'abonnement est toujours actif. Couvre aussi bien les abonnés payants que les utilisateurs en essai qui ont annulé avant la conversion. C'est la meilleure fenêtre pour les retenir — ils ont encore accès. Séparez les audiences payantes et en essai via des filtres de segment si les messages doivent différer. - **Billing issue** : Paiement échoué — carte refusée ou expirée, ou délai de grâce après un renouvellement manqué. Objectif : récupération urgente et utile, pas une relance commerciale. Récupérez-les rapidement — ils voulaient déjà payer. - **Expired** : L'abonnement a expiré et l'accès est révoqué. Couvre les expirations d'abonnements payants et les essais terminés sans conversion. Objectif : les reconquérir. Les filtres de segment permettent d'adapter le contenu selon que l'essai ou l'abonnement payant a expiré. - **Refunded** : Utilisateurs ayant demandé un remboursement après achat. Objectif : comprendre ce qui n'a pas fonctionné et proposer une option mieux adaptée. Le ton doit rester humble et curieux, pas une relance agressive. Les déclencheurs ne sont pas configurables — il n'est pas possible d'en créer de nouveaux ni d'étendre la liste. ## Le segment All Users \{#the-all-users-segment\} Adapty Mail inclut un segment intégré **All Users** sans aucun filtre — tous les utilisateurs du projet y sont éligibles. Il est surtout utile dans les flows comme ligne fourre-tout, servant les utilisateurs non correspondants à un segment plus spécifique placé au-dessus. All Users ne peut pas être modifié ni supprimé. Consultez [Segments](mail-segments) pour plus de détails. ## Priorité \{#priority\} Chaque vue de déclencheur contient une liste de lignes **segment → campagne** (ou segment → test A/B), classées par priorité. Quand un utilisateur atteint le déclencheur, Adapty Mail : 1. Parcourt les lignes de haut en bas. 2. Envoie la campagne de la première ligne dont le segment correspond. 3. S'arrête. Les lignes suivantes ne sont pas évaluées pour cet utilisateur. L'ordre compte. Un segment large placé au-dessus d'un segment plus précis absorbe tous les utilisateurs qui auraient autrement correspondu à la ligne plus précise. Pour réorganiser, faites glisser la poignée à gauche de n'importe quelle ligne — le backend réattribue les numéros de priorité 1, 2, 3… selon l'ordre enregistré. :::important La ligne **All Users**, si elle est présente, doit être en dernier (priorité la plus basse). Le backend rejette les sauvegardes où All Users n'est pas en dernière position — sinon, elle absorberait tous les utilisateurs avant que les segments plus spécifiques aient la possibilité de correspondre. ::: ## Types de contenu \{#content-types\} Une ligne peut délivrer soit une campagne unique, soit un test A/B : - **Campaign** : Envoie une campagne à tous les utilisateurs qui correspondent au segment. - **A/B Test** : Regroupe deux campagnes ou plus avec des pondérations configurables, répartit aléatoirement les utilisateurs entre elles et suit les métriques par variante. Voir [Tests A/B](mail-ab-testing). ## Cycle de vie \{#lifecycle\} Les lignes de flow n'ont pas d'état brouillon. Une ligne est active dès que vous la sauvegardez — à partir de ce moment, les utilisateurs qui atteignent le déclencheur et correspondent au segment sont acheminés vers sa campagne. - **Créer une ligne** : La livraison commence immédiatement à la sauvegarde. - **Modifier une ligne** : Le changement s'applique aux utilisateurs qui atteignent le déclencheur à partir de ce moment. Les utilisateurs déjà en cours de séquence continuent avec la configuration précédente. - **Supprimer une ligne** : Les nouveaux utilisateurs cessent d'entrer dans la séquence. Les utilisateurs déjà en cours de séquence peuvent continuer à recevoir leurs e-mails planifiés — il n'y a pas d'annulation automatique. Les lignes de test A/B suivent leur propre cycle de vie (**brouillon → actif → terminé**) contrôlé indépendamment de la ligne elle-même. Voir [Tests A/B](mail-ab-testing). --- # File: mail-create-flow --- --- title: "Créer et gérer les lignes d'un flow dans Adapty Mail" description: "Ajoutez, réorganisez, modifiez et supprimez des lignes dans un flow pour router vos campagnes vers vos utilisateurs." --- Chaque [flow](mail-flows) est une liste prioritaire de lignes **segment → campagne** dans une vue de déclencheur fixe. Ce guide explique comment ajouter, réorganiser, modifier et supprimer ces lignes. Pour les concepts liés aux déclencheurs, priorités et types de contenu, consultez [Flows](mail-flows). ## Ajouter une ligne \{#add-a-row\} 1. Dans Adapty Mail, accédez à **Flows** et ouvrez le déclencheur que vous souhaitez configurer. 2. Cliquez sur **Create** pour ouvrir la boîte de dialogue. 3. Dans la boîte de dialogue : - **Segment** : choisissez un segment, ou **All Users** pour cibler tout le monde. - **Content type** : **Campaign** pour une campagne unique, ou **A/B Test** pour en comparer plusieurs — voir [Tests A/B](mail-ab-testing). - **Campaign** : sélectionnez la campagne à envoyer. 4. Cliquez sur **Save**. La ligne est active immédiatement. Les utilisateurs qui déclenchent l'événement et correspondent au segment commencent à recevoir la campagne à partir de ce moment. ## Réorganiser les lignes \{#reorder-rows\} Faites glisser la poignée à gauche d'une ligne pour modifier sa priorité. Adapty Mail attribue automatiquement `priority: 1, 2, 3…` en fonction de l'ordre enregistré. Une ligne **All Users** doit toujours rester en dernière position — la faire glisser au-dessus d'une autre ligne est bloqué à l'enregistrement. ## Modifier une ligne \{#edit-a-row\} Cliquez sur **Change content** sur une ligne pour rouvrir la boîte de dialogue avec ses valeurs actuelles pré-remplies. Vous pouvez modifier le segment, le type de contenu et la campagne, puis cliquer sur **Save** pour appliquer. Une ligne utilisant un test A/B ne peut être modifiée que lorsque le test est à l'état **draft**. Une fois le test lancé, son contenu est verrouillé jusqu'à ce que vous le terminiez. ## Supprimer une ligne \{#delete-a-row\} Ouvrez le menu d'actions de la ligne et cliquez sur **Delete**. Il n'y a pas de boîte de dialogue de confirmation — la ligne est supprimée immédiatement. - **Lignes de campagne** : peuvent être supprimées à tout moment. - **Lignes avec un test A/B actif** : ne peuvent pas être supprimées. Terminez d'abord le test via **Finish A/B test**, puis supprimez la ligne. :::note Supprimer une ligne empêche de nouveaux utilisateurs d'entrer dans la séquence. Les utilisateurs déjà en cours de séquence peuvent continuer à recevoir leurs e-mails planifiés — il n'y a pas d'annulation automatique. ::: --- # File: mail-segments --- --- title: "Segments dans Adapty Mail" description: "Créez des tranches d'audience réutilisables basées sur les données de profil et d'achat pour cibler les flows et les tests A/B." --- Un **segment** est une tranche d'audience réutilisable. Vous le définissez une fois — dans **Segments** — et vous le référencez depuis les flows et les tests A/B. Les segments sont des définitions de filtres, pas des instantanés : ils sont évalués à la demande lorsqu'un déclencheur de flow s'active, donc l'appartenance reflète toujours les données de profil les plus récentes. ## Créer un segment \{#create-a-segment\} 1. Dans Adapty Mail, accédez à **Segments** et cliquez sur **+ Create**. La page de création s'ouvre avec le titre **New Segment**. 2. Donnez au segment un **Name** (obligatoire) et une **Description** optionnelle. 3. Sous **Filters**, cliquez sur **Add filter** pour chaque [règle](#available-filter-fields) souhaitée. Chaque filtre devient une carte réductible intitulée **Filter 1**, **Filter 2**, etc. 4. Pour chaque filtre, choisissez un champ, un opérateur, puis saisissez la valeur de comparaison. 5. Enregistrez le segment. :::important Les filtres sont combinés avec **AND** — un utilisateur doit correspondre à chaque filtre pour faire partie du segment. La logique OR et les groupes imbriqués ne sont pas pris en charge. Chaque champ ne peut apparaître qu'une seule fois par segment ; pour comparer le même champ sur plusieurs valeurs, répartissez la logique dans des segments distincts. ::: ## Importer un segment depuis Adapty \{#import-a-segment-from-adapty\} Au lieu de construire un segment à partir de filtres, vous pouvez importer un segment d'audience existant depuis le tableau de bord Adapty principal. 1. Sur la page **Segments**, cliquez sur **Import**. 2. Consultez la liste. Les **Importable segments** affichent une case à cocher et leurs conditions de filtre. Les segments qui **ne peuvent pas être importés** sont grisés avec la raison spécifique, par exemple un champ non pris en charge (comme les données d'attribution Apple Ads), un opérateur non pris en charge, ou un état d'abonnement sans équivalent dans Adapty Mail. 3. Cochez les segments souhaités et cliquez sur **Import**. :::important L'importation crée une copie indépendante des filtres du segment au moment de l'importation — elle n'est pas maintenue en synchronisation avec le segment Adapty d'origine, et importer le même segment à nouveau crée une copie distincte à chaque fois, car Adapty Mail ne détecte pas les doublons. ::: Les segments importés démarrent à l'état **Draft**, comme les segments créés manuellement, vous pouvez donc modifier leurs filtres immédiatement. ## Champs de filtre disponibles \{#available-filter-fields\} | Groupe | Champ | Type | | --------------- | -------------------------- | ------- | | Profil | Email | String | | Profil | Age | Integer | | Profil | Country | String | | Profil | External profile ID | String | | Profil | Created at | Date | | État d'achat | Total revenue (USD) | Decimal | | État d'achat | Subscription state | Enum | | État d'achat | Subscription purchased at | Date | | État d'achat | Subscription expires at | Date | | État d'achat | One-time purchase state | Enum | | État d'achat | One-time purchased at | Date | **Valeurs de Subscription state** : Never purchased, Subscribed, Auto-renew off, Billing issue, Grace period, Expired, Refunded. **Valeurs de One-time purchase state** : Never purchased, Purchased, Refunded. Opérateurs disponibles par type de champ : - **String** : equals, not equals, is set, is not set. - **Number** : equals, not equals, less than, greater than, less than or equal, greater than or equal, between, is set, is not set. - **Date** : equals, not equals, before, after, on or before, on or after, between, is set, is not set. ## Le segment système All Users \{#the-all-users-system-segment\} Adapty Mail est livré avec un segment intégré **All Users** sans aucun filtre — chaque utilisateur du projet en fait partie. Vous ne pouvez ni le modifier ni le supprimer. Utilisé dans un flow, il joue le rôle de ligne fourre-tout en bas de liste (voir [Flows](mail-flows) pour la règle de priorité). ## Cycle de vie \{#lifecycle\} L'état d'un segment est calculé en fonction de son utilisation : - **Draft** : Créé, non attaché à un flow ou un test A/B. - **Live** : Attaché à un flow ou un test A/B actif. - **Inactive** : Était attaché, mais le test A/B est terminé ou la ligne du flow a été supprimée. - **Archived** : Supprimé de façon logicielle et masqué de la liste principale. La page Segments dispose d'un filtre d'état dans la barre d'outils pour affiner la liste sur l'un de ces états. ## Modifier et supprimer un segment \{#edit-and-delete-a-segment\} - **Name et description** : Toujours modifiables. - **Filtres d'un segment Draft** : Entièrement modifiables. - **Filtres d'un segment Live** : Verrouillés. Une fois qu'un segment est référencé par une ligne de flow active ou un test A/B, les filtres passent en lecture seule. Vous pouvez uniquement le renommer ou mettre à jour la description. Pour modifier le ciblage, créez un nouveau segment et remplacez la ligne du flow. - **Delete** : Supprime le segment de façon logicielle. Les segments Live ne peuvent pas être supprimés — retirez-les du flow (ou terminez le test A/B) d'abord. ## Limitations \{#limitations\} - **Pas de logique OR, pas d'imbrication** : Les filtres se combinent uniquement avec AND. - **Un seul champ par segment** : Un segment ne peut pas avoir deux filtres sur le même champ (par exemple, deux vérifications de pays). - **Pas d'aperçu de taille** : L'éditeur n'indique pas combien d'utilisateurs correspondent actuellement aux filtres. - **Filtres verrouillés une fois actifs** : Les segments actifs sont en lecture seule, sauf pour le nom et la description. --- # File: mail-profiles --- --- title: "Profils dans Adapty Mail" description: "Consultez chaque client de votre projet — ses attributs, son état d'achat, son engagement par email et l'intégralité de son parcours d'activité." --- Un **profil** correspond à un client dans votre projet. La page **Profiles** liste toutes les personnes connues d'Adapty Mail et affiche pour chacune l'état de ses achats, son engagement par email et l'intégralité de son parcours d'activité. Les profils arrivent automatiquement : à partir des emails collectés par le SDK Adapty, ou des données que vous envoyez via l'API Adapty Mail. :::tip Pour regrouper des profils en audiences réutilisables pour les flows et les tests A/B, consultez [Segments](mail-segments). ::: ## Comment les profils arrivent dans Adapty Mail \{#how-profiles-get-into-adapty-mail\} Adapty Mail crée les profils automatiquement à partir de deux sources : - **SDK Adapty** : le SDK collecte les emails et les achats depuis votre application. Voir [Collecter les emails des utilisateurs](mail-collect-emails). - **API Adapty Mail** : votre backend envoie les profils et les transactions en server-to-server. Voir [Envoyer des données via l'API](mail-send-data-via-api). Adapty Mail associe chaque email, clic et achat à un profil via son `external_profile_id` stable. La page Profiles est en lecture seule. Vous pouvez consulter les profils et les désabonner, mais vous ne pouvez pas les créer, les modifier ni les supprimer. L'application source ou l'API est propriétaire de ces données. ## La liste des profils \{#the-profiles-list\} La liste affiche une ligne par profil, du plus récent au plus ancien. Utilisez le champ de recherche pour trouver un profil par email, identifiant de profil ou identifiant de profil externe. | Colonne | Affiche | | --- | --- | | Profile | L'email du client et la campagne qui lui a envoyé le plus d'emails. | | Status | L'état d'achat du profil. Voir [Statut du profil](#profile-status). | | Country | Le pays du client. | | Open rate | Ratio ouvertures / envois sur tous les emails. Un tiret signifie qu'aucun email n'a encore été envoyé. | | LTV | Valeur vie client — revenu total généré par ce profil toutes sources confondues. | | Joined | Date à laquelle le profil est entré pour la première fois dans Adapty Mail. | | Last activity | Dernière interaction du profil avec un email : envoi, ouverture ou clic. | :::important **Joined** est la date à laquelle le profil est entré pour la première fois dans Adapty Mail, utilisée comme date « client depuis ». Il s'agit de la date d'ingestion, et non de la date d'inscription d'origine dans votre application. ::: ### Statut du profil \{#profile-status\} La colonne **Status** indique l'état d'achat du profil — où en est le client vis-à-vis de ses abonnements et achats uniques. | Statut | Signification | | --- | --- | | Never purchased | Le profil n'a encore rien acheté. | | Purchased | Le profil a effectué un achat unique. | | Active subscriber | Le profil a un abonnement actif. | | Cancelling | Le renouvellement automatique est désactivé ; l'accès est maintenu jusqu'à la fin de la période en cours. | | Billing issue | Un paiement de renouvellement a échoué. | | Grace period | Le paiement a échoué, mais l'accès est maintenu pendant le délai de grâce du store. | | Churned | L'abonnement a expiré et l'accès a pris fin. | | Refunded | Un achat a été remboursé. | :::note Le statut d'achat est indépendant du statut d'abonnement aux emails. Un profil peut être **Active subscriber** tout en étant **Unsubscribed** de vos emails, ou **Churned** tout en restant **Subscribed**. Le statut email apparaît sur la page du profil et détermine si Adapty Mail peut lui envoyer des messages. ::: ## Détails d'un profil \{#profile-details\} Cliquez sur un profil pour ouvrir sa page de détail. L'en-tête affiche l'email, le pays, la plateforme et la date « client depuis ». Il présente également trois badges de statut : le statut d'achat, le taux d'ouverture et si le profil est **Subscribed** ou **Unsubscribed**. Cinq métriques d'engagement apparaissent en haut : - **Sent** : emails envoyés au profil. - **Delivered** : emails acceptés par le fournisseur de messagerie. - **Opened** : emails ouverts par le profil. - **Clicked** : emails dans lesquels le profil a cliqué sur un lien. - **Revenue** : deux chiffres — le revenu attribué et la valeur vie client. :::note Le **revenu attribué** est le revenu généré par vos emails : les achats effectués par le profil après avoir interagi avec une campagne. La **valeur vie client (LTV)** est le revenu total du profil toutes sources confondues, que l'email ait joué un rôle ou non. L'en-tête affiche d'abord le revenu attribué, puis la LTV. ::: La carte **Profile** liste les attributs du client : - **Platform** : la plateforme de l'appareil du client, comme iOS ou Android. - **Country** : le pays du client. - **Store country** : le pays du compte App Store ou Google Play du client. - **Gender** : le genre du client, si connu. - **Age** : l'âge du client, si une date de naissance a été fournie. - **Profile ID** : l'identifiant interne du profil dans Adapty Mail. - **External ID** : l'`external_profile_id` provenant de votre application ou de votre backend. - **Custom attributes** : toutes les paires clé-valeur que vous avez envoyées avec le profil. ### État des achats \{#purchase-state\} La carte **Purchase state** affiche le revenu et l'historique des achats du profil. La valeur vie client apparaît en haut, suivie de deux sections au maximum : - **Subscription** : prix, store, date de début, date de renouvellement ou d'expiration, et identifiant du produit pour l'abonnement du profil. - **One-time purchase** : prix, store, date d'achat et identifiant du produit pour le dernier achat unique. Si le profil n'a encore rien acheté, la carte affiche **No purchase yet**. La carte **Segments** liste tous les segments auxquels le profil correspond actuellement, ou **Not in any segment** si aucun ne s'applique. L'appartenance est évaluée en temps réel et reflète donc toujours les dernières données du profil. Voir [Segments](mail-segments) pour savoir comment les créer. ## Le parcours d'activité \{#the-activity-journey\} La section **Journey** est une chronologie de tout ce qui s'est passé pour le profil. Elle commence par **Profile created**, puis entremêle deux types d'événements : - **Événements email** : chaque email envoyé au profil, avec son activité de livraison, d'ouverture et de clic. Développez un email pour voir les liens sur lesquels le profil a cliqué et tout achat que l'email a généré. - **Événements de transaction** : jalons liés à l'abonnement et aux achats uniques, comme les démarrages, les renouvellements, les annulations, les problèmes de facturation, les expirations et les remboursements. Les événements de transaction correspondent aux libellés suivants dans le parcours : | `event_type` | Libellé dans le parcours | | --- | --- | | `subscription_started` | Subscription started | | `subscription_renewed` | Subscription renewed | | `subscription_renewal_cancelled` | Renewal cancelled | | `subscription_renewal_reactivated` | Renewal resumed | | `billing_issue_detected` | Billing issue | | `entered_grace_period` | Entered grace period | | `subscription_expired` | Subscription expired | | `subscription_refunded` | Subscription refunded | | `non_subscription_purchase` | One-time purchase | | `non_subscription_purchase_refunded` | Purchase refunded | Ces événements arrivent dans Adapty Mail automatiquement via le SDK Adapty, ou vous pouvez les envoyer vous-même via l'API. Voir [Envoyer des événements de transaction](mail-send-data-via-api#send-transaction-events) pour la référence des événements. ## Désabonner un profil \{#unsubscribe-a-profile\} Pour arrêter d'envoyer des emails à un profil, ouvrez sa page, cliquez sur **...** et sélectionnez **Unsubscribe**. Adapty Mail marque le profil comme désabonné et l'ajoute à votre liste de suppression, de sorte que les campagnes et les flows l'ignorent. L'action est idempotente : un profil déjà désabonné reste désabonné. Pour une vue d'ensemble de la suppression et de la façon dont les profils se désabonnent eux-mêmes, voir [Désabonnement et suppression](mail-suppression). --- # File: mail-ab-testing --- --- title: "Tests A/B dans Adapty Mail" description: "Comparez des campagnes email complètes entre elles en attachant un test A/B à un flow." --- Un test A/B dans Adapty Mail compare deux campagnes email complètes ou plus entre elles. Chaque variante est une campagne complète et indépendante. Lorsqu'un utilisateur correspond au segment du test dans un [flow](mail-flows), Adapty Mail l'oriente vers l'une des variantes selon les pondérations configurées et suit les livraisons, l'engagement et le chiffre d'affaires par variante. ## Ce qu'est une variante \{#what-a-variation-is\} Chaque variante est une campagne complète. Les variantes peuvent différer sur tout ce qui peut différer dans une campagne — le texte, les images principales, le ton, la longueur de la séquence ou les délais entre les emails. Le test A/B lui-même n'expose pas ces éléments comme des paramètres ; vous créez les campagnes séparément et les ajoutez en tant que variantes. ## Créer un test A/B \{#create-an-ab-test\} 1. Créez d'abord les campagnes dans **Campaigns**. Chaque variante a besoin de sa propre campagne. 2. Dans Adapty Mail, allez dans **A/B Tests** et cliquez sur **Create**. 3. Ajoutez chaque campagne en tant que variante et définissez son poids. Les poids doivent totaliser **100 %**. 4. Attribuez un segment pour contrôler les utilisateurs auxquels le test s'applique. 5. Enregistrez. Le test est sauvegardé comme **draft** et n'envoie rien pour l'instant. Pour le mettre en ligne, il doit être attaché à un flow. ## Lancer depuis un flow \{#launch-from-a-flow\} Les tests A/B ne peuvent pas être lancés depuis la page A/B Tests — le lancement et la fin se font dans une ligne de flow. 1. Dans Adapty Mail, allez dans **Flows** et ouvrez le déclencheur où vous souhaitez exécuter le test. 2. Cliquez sur **Create** sur une nouvelle ligne. Dans la boîte de dialogue, définissez **Content type** sur **A/B Test**, sélectionnez le test que vous avez enregistré, puis cliquez sur **Save**. 3. Sur la ligne, cliquez sur **Launch A/B test**. L'état du test passe de **draft** à **live** et les utilisateurs entrants qui correspondent au segment commencent à être orientés vers les variantes. Consultez [Créer un flow](mail-create-flow) pour en savoir plus sur les lignes de flow. ## Comment fonctionne le routage \{#how-routing-works\} Lorsqu'un utilisateur atteint le déclencheur du flow et correspond au segment du test A/B, Adapty Mail choisit une variante par sélection **aléatoire pondérée** — le poids de chaque variante détermine sa part du tirage. Le routage n'est pas déterministe par utilisateur. ## Lire les résultats \{#read-results\} Sur la page A/B Tests, chaque variante affiche ses compteurs bruts et les taux calculés : - **Delivery** : Envois, Livraisons, Rebonds. - **Engagement** : Ouvertures, Clics, Désabonnements. - **Revenue** : Achats, Chiffre d'affaires. Consultez [Analytics des campagnes](mail-analytics) pour comprendre ce que chaque métrique comptabilise et comment le chiffre d'affaires est attribué. ## Terminer le test \{#finish-the-test\} Comme le lancement, la fin du test se fait depuis la ligne de flow, et non depuis la page A/B Tests. 1. Ouvrez la ligne de flow où le test est en cours. 2. Cliquez sur **Finish A/B test**. 3. Dans la boîte de dialogue **Finish A/B test**, choisissez la campagne gagnante dans le menu déroulant **Replace with campaign** — ou laissez-le vide pour supprimer entièrement le segment du flow. 4. Confirmez. :::note Les utilisateurs qui sont déjà en cours de séquence dans une variante — gagnante ou perdante — continuent de recevoir leurs emails planifiés. Ils ne sont pas basculés vers le gagnant. ::: ## Cycle de vie \{#lifecycle\} Un test A/B passe par quatre états : - **Draft** : Créé, pas encore attaché à une ligne de flow active. - **Live** : Attaché et lancé ; oriente les utilisateurs entrants. - **Finished** : Arrêté via **Finish A/B test**. - **Archived** : Supprimé de la liste de manière réversible. --- # File: mail-analytics --- --- title: "Analytics dans Adapty Mail" description: "Analysez les performances de vos campagnes par campagne, segment, variante A/B, message ou déclencheur — et visualisez livraison, engagement et revenus côte à côte." --- La page **Analytics** affiche les performances de vos campagnes selon cinq dimensions : campagne, segment, variante A/B, message et déclencheur. Elle associe les métriques de livraison aux revenus attribués à chaque e-mail, ce qui vous permet de comparer des variantes, d'identifier les segments les plus performants et de repérer où se concentrent les revenus. La page comporte un graphique en haut et un tableau de détail en bas. Cliquez sur n'importe quelle ligne pour explorer une entité spécifique. ## Choisir une période \{#pick-a-time-range\} La barre d'outils en haut de la page contrôle la fenêtre temporelle et la façon dont elle est découpée : - **Date range** : Présélections (7 / 14 / 30 / 90 derniers jours, ce mois-ci, le mois dernier, les 12 derniers mois, depuis le début de l'année) ou un sélecteur **Custom range**. Par défaut, les 30 derniers jours. - **Granularity** : Découpages **Daily**, **Weekly** ou **Monthly**. La granularité s'ajuste automatiquement quand la période s'allonge — **Daily** bascule vers **Weekly** au-delà de 92 jours, et les deux basculent vers **Monthly** au-delà de 366 jours. - **Chart style** : **Line**, **Area** ou **Bar**. Si la page affiche un avertissement « range too wide », réduisez la période, choisissez une granularité plus grossière ou appliquez des filtres. ## Grouper, décomposer, filtrer \{#group-break-down-filter\} Trois contrôles sous la barre d'outils définissent ce qu'affichent le graphique et le tableau : - **Group by** : La dimension qui divise le jeu de données en lignes. Les options sont **Campaigns**, **Segments**, **A/B variants** et **Triggers**. Avec **No grouping**, la page regroupe tout en une seule ligne agrégée **All**. - **Breakdown** : Une seconde dimension qui divise chaque ligne en sous-lignes. Lorsque **Group by** et **Breakdown** sont tous deux définis, chaque ligne du tableau peut être développée pour afficher ses sous-groupes. Le Breakdown peut être n'importe quelle dimension — y compris **Messages** — sauf celle déjà utilisée comme **Group by**. - **Add filter** : Restreint le jeu de données à des campagnes, segments, variantes A/B ou déclencheurs spécifiques. Les filtres s'appliquent au graphique et au tableau. :::note **Messages** est disponible comme breakdown mais pas comme **Group by** de premier niveau ni comme filtre. Pour analyser des messages individuels, groupez par **Campaigns** avec un breakdown **Messages**, puis développez la ligne de la campagne ou ouvrez un message depuis le détail. ::: ## Lire le graphique \{#read-the-chart\} Le graphique affiche les métriques sélectionnées sur la période choisie. - **Metric category** : Basculez entre **Email actions** (Sent, Delivered, Opened, Clicked, Bounced, Unsubscribed, Converted) et **Revenue**. - **Metric pills** : Choisissez les métriques à tracer. En mode agrégé (sans regroupement), vous pouvez tracer plusieurs métriques sur le même graphique. Avec un regroupement activé, le graphique trace une seule métrique — une ligne par groupe — pour que les groupes restent visuellement distincts. - **Legend** : Lorsqu'un regroupement est actif, la légende à droite liste chaque groupe et vous permet d'activer ou de désactiver une série. Les cases à cocher de visibilité dans le tableau des métriques en bas contrôlent également quelles lignes apparaissent sur le graphique. ## Lire le tableau des métriques \{#read-the-metrics-table\} Sous le graphique, le tableau des métriques affiche une ligne par groupe. Une ligne récapitulative en haut agrège toutes les autres lignes du tableau. - **Colonnes triables** : Cliquez sur n'importe quel en-tête de colonne pour trier par Name, Sent, Delivered, Delivery rate, Opened, Open rate, Clicked, Click rate, Converted, Revenue, Bounced ou Unsubscribed. - **Case à cocher de visibilité** : Activez ou désactivez l'affichage d'une ligne sur le graphique. - **Développer une ligne** : Lorsqu'un **Breakdown** est défini, le chevron à gauche de chaque ligne permet de la développer pour afficher ses sous-groupes. - **Ouvrir le détail** : Cliquez sur le nom d'une ligne pour ouvrir la vue détaillée de cette entité. Le détail affiche : - Le même graphique et sélecteur de métriques que la page principale, limités à une seule entité. - Huit cartes récapitulatives en bas : **Sent**, **Delivered** (avec le taux de livraison), **Opened** (avec le taux d'ouverture), **Clicked** (avec le taux de clic), **Bounced**, **Unsubscribed**, **Converted** et **Revenue**. La période et la granularité sont reprises depuis la page principale. Utilisez **Back** dans le fil d'Ariane pour revenir. ## Ce qui est suivi \{#whats-tracked\} :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: Chaque ligne — sur la page Analytics, dans le détail et dans les vues intégrées décrites ci-dessous — expose le même ensemble de comptages bruts : - **Sent** : E-mails envoyés à SES. - **Delivered** : Livraisons en boîte de réception confirmées par SES. - **Bounced** : Rebonds signalés par SES. Les rebonds permanents et temporaires ne sont pas distingués — les deux comptent comme un seul **Bounced**. - **Opened** : Chargements de pixel. La protection de confidentialité Mail d'Apple pré-charge les images sur iOS 15+ et gonfle ce comptage — privilégiez les clics et les revenus pour des signaux plus fiables. - **Clicked** : Clics sur les liens dans le corps de l'e-mail. - **Unsubscribed** : Désabonnements via le lien en pied de page ou l'en-tête `List-Unsubscribe`. - **Converted** : Profils uniques du groupe ayant réalisé un achat attribué dans la période. Les conversions sont regroupées par date d'achat — un clic en mars suivi d'un achat en avril est comptabilisé en avril. Un profil qui achète plusieurs fois n'est compté qu'une seule fois. - **Revenue** : Somme des revenus attribués (USD) sur les démarrages d'abonnement, les renouvellements et les achats uniques. ## Taux dérivés \{#derived-rates\} Chaque taux est calculé à partir des comptages bruts ci-dessus : | Taux | Formule | | ------------- | -------------------- | | Delivery rate | Delivered / Sent | | Open rate | Opened / Delivered | | Click rate | Clicked / Delivered | Le détail affiche les mêmes trois taux à côté de ses cartes récapitulatives. ## Attribution des revenus \{#revenue-attribution\} Les revenus sont attribués via le **dernier clic** sur un lien suivi : 1. Lorsqu'un destinataire clique sur un lien dans un e-mail, Adapty Mail enregistre le `scheduled_email_id` associé à ce profil dans un stockage temporaire. 2. Si un événement d'achat arrive ensuite sans attribution existante, Adapty Mail renseigne le `scheduled_email_id` stocké sur la transaction — à condition que l'horodatage de l'achat soit postérieur au clic. 3. Les achats sans clic suivi préalable restent non attribués. Le paramètre suivi est `scheduled_email_id`. L'URL de paiement transmet également l'identité du destinataire via les espaces réservés `{email}` et `{external_profile_id}` afin que le paywall web puisse personnaliser le flow — c'est un mécanisme distinct de l'attribution. Voir [Configurer le paiement](mail-checkout). ## Analytics intégrées dans les Flows et les tests A/B \{#inline-analytics-in-flows-and-ab-tests\} Les mêmes métriques apparaissent également en ligne à côté des lignes mesurées : - **Page Flows** : Chaque ligne de segment dans une vue de déclencheur affiche ses comptages de livraison, d'engagement et de revenus. - **Page A/B Tests** : Les variantes sont listées côte à côte avec le même ensemble de métriques, ce qui facilite la comparaison directe des variantes. Utilisez la page Analytics pour comparer plusieurs campagnes ou explorer une entité spécifique, et les vues intégrées lorsque vous travaillez déjà sur une ligne de flow ou un test A/B particulier. Les définitions des métriques, les taux dérivés et les règles d'attribution ci-dessus s'appliquent de façon identique dans ces trois vues. ## Limites \{#limitations\} - **Pas de distinction entre rebonds permanents et temporaires** : Chaque rebond — temporaire ou permanent — est regroupé dans un seul comptage **Bounced**. - **Cohérence différée, pas en temps réel** : Les comptages sont agrégés depuis des tables d'événements. Les événements récents apparaissent généralement en quelques minutes, mais sans garantie de streaming. - **La taille de la période est limitée** : Des périodes très larges combinées à une granularité fine peuvent dépasser la capacité de cellules du graphique. La page l'indique par un avertissement « range too wide » — réduisez la période, choisissez une granularité plus grossière ou appliquez des filtres. --- # File: configuration --- --- title: "Configurer une intégration tierce" description: "Apprenez à configurer les paramètres Adapty pour optimiser la gestion des abonnements." --- Grâce aux intégrations Adapty, vous pouvez transmettre facilement les événements d'abonnement et les données d'achat vers la plateforme ou le workflow de votre choix. Que vous cherchiez à analyser le comportement des utilisateurs, à améliorer l'engagement client ou à enrichir l'analyse produit de votre équipe marketing, Adapty peut transmettre sans effort les événements d'achats intégrés vers l'intégration de votre choix. Adapty suit automatiquement les achats intégrés et les événements d'abonnement tels que les essais, les conversions, les renouvellements et les résiliations. Ces [événements](events) sont automatiquement communiqués à vos intégrations. Cela vous permet d'interagir avec vos clients en fonction de leur étape actuelle et d'analyser les activités liées aux revenus dans votre application. ## Paramètres d'intégration \{#integration-settings\} <img src="/assets/shared/img/20bf659-CleanShot_2023-08-22_at_13.26.562x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Les intégrations proposent les options de configuration suivantes, qui s'appliquent à tous les événements envoyés via cette intégration : | Paramètre | Description | |:---------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Reporting Proceeds** | Choisissez comment les valeurs de revenus sont présentées : nettes des commissions de l'App Store et du Play Store, ou brutes (avant déduction). Cochez la case « Send sales as proceeds » pour afficher les ventes en tant que revenus nets après déduction des commissions de l'App Store / Play Store. | | **Send Trial Price** | Si cette case est cochée, Adapty transmettra le prix de l'abonnement pour l'événement Trial Started. | | **Exclude Historical Events** | Permet d'exclure les événements survenus avant que l'utilisateur ait installé l'application avec le SDK Adapty. Cela évite les doublons et garantit des rapports précis. Par exemple, si un utilisateur a activé un abonnement mensuel le 10 janvier et mis à jour l'application avec le SDK Adapty le 6 mars, Adapty ignorera les événements antérieurs au 6 mars et conservera les événements suivants. | | **Report User's Currency** | Choisissez si les ventes sont rapportées dans la devise de l'utilisateur ou en USD. | | **Send User Attributes** | Si vous souhaitez envoyer des attributs spécifiques à l'utilisateur, comme les préférences de langue, et que votre forfait OneSignal prend en charge plus de 10 tags, sélectionnez cette option. L'activer permet d'inclure des informations supplémentaires au-delà des 10 tags par défaut. Notez que dépasser les limites de tags peut entraîner des erreurs. | | **Send Attributions** | Activez cette option pour transmettre les informations d'attribution (par ex. l'attribution AppsFlyer) et recevoir les détails correspondants. | | **Send Play Store purchase token** | Activez cette option pour recevoir le token Play Store nécessaire à la revalidation de l'achat si besoin. Cela ajoutera le paramètre `play_store_purchase_token` à l'événement. | | **Delay events with future datetime** | **Pour AppsFlyer et les webhooks personnalisés uniquement** : lorsque cette option est activée, les événements de renouvellement et de conversion d'essai sont envoyés à la date à laquelle ils se produisent réellement. Lorsqu'elle est désactivée (par défaut), ces événements sont envoyés immédiatement lors de leur détection, même si la date est dans le futur. | | **Data residency** | **Pour Mixpanel et Amplitude uniquement** : sélectionnez la résidence des données pour déterminer où vos événements sont traités et stockés. | ## Configurer les événements \{#configure-the-events\} Sous les identifiants, trois groupes d'événements peuvent être envoyés à la plateforme d'intégration sélectionnée depuis Adapty. Activez ceux dont vous avez besoin. Il est important de noter que la personnalisation des noms d'événements est disponible pour certaines intégrations, tandis que pour d'autres, les noms d'événements sont fixes et ne peuvent pas être modifiés. De plus, avec certaines intégrations comme [Airbridge](airbridge#configure-events-and-tags) par exemple, vous avez la possibilité d'associer plusieurs noms d'événements à un seul événement Adapty. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/c79f5cd-screencapture-app-adapty-io-integrations-pushwoosh-2023-08-22-13_31_07.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Bien que nous recommandions d'utiliser les noms d'événements par défaut d'Adapty, vous êtes libre d'adapter les noms d'événements selon vos besoins spécifiques. --- # File: events --- --- title: "Événements à envoyer aux intégrations tierces" description: "Suivez les principaux événements d'abonnement grâce aux outils d'analyse d'Adapty." --- Apple et Google envoient les événements d'abonnement directement aux serveurs via les [Notifications du serveur App Store](enable-app-store-server-notifications) et les [Notifications en temps réel pour les développeurs (RTDN)](enable-real-time-developer-notifications-rtdn). En conséquence, les applications mobiles ne peuvent pas envoyer de manière fiable des événements aux systèmes d'analyse en temps réel. Par exemple, si un utilisateur souscrit un abonnement sans jamais rouvrir l'application, le développeur ne recevra aucune mise à jour du statut d'abonnement sans serveur. Adapty comble cette lacune en collectant les données d'abonnement et en les convertissant en événements lisibles. Ces événements d'intégration sont envoyés au format JSON. Bien que tous les événements partagent la même structure, leurs champs varient selon le type d'événement, le store et la configuration spécifique. Les champs exacts inclus dans chaque événement sont détaillés sur les pages d'intégration correspondantes. Pour savoir comment déterminer si un événement a bien été traité ou si un problème est survenu, consultez la page [Statuts des événements](event-statuses). ## Types d'événements \{#event-types\} La plupart des événements sont créés et envoyés à toutes les intégrations configurées si elles sont activées. Cependant, l'événement **Access level updated** ne se déclenche que si l'[intégration webhook](webhook) est configurée et que cet événement est activé. Cet événement apparaîtra dans le [Event Feed](https://app.adapty.io/event-feed) et sera également envoyé au webhook, mais ne sera pas partagé avec les autres intégrations. Si aucune intégration webhook n'est configurée ou si ce type d'événement n'est pas activé, l'événement **Access level updated** ne sera pas créé et n'apparaîtra pas dans le [Event Feed](https://app.adapty.io/event-feed). | Nom de l'événement | Description | |:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | Déclenché lorsqu'un utilisateur active un abonnement payant sans période d'essai, c'est-à-dire qu'il est facturé immédiatement. | | subscription_renewed | Se produit lors du renouvellement d'un abonnement et de la facturation de l'utilisateur. Cet événement débute à partir de la deuxième facturation, que l'abonnement soit avec ou sans essai. | | subscription_renewal_cancelled | Un utilisateur a désactivé le renouvellement automatique de son abonnement. Il conserve l'accès aux fonctionnalités premium jusqu'à la fin de la période d'abonnement payante. | | subscription_renewal_reactivated | Déclenché lorsqu'un utilisateur réactive le renouvellement automatique de son abonnement. | | subscription_expired | Déclenché lorsqu'un abonnement prend fin après une annulation. Par exemple, si un utilisateur annule son abonnement le 12 décembre mais qu'il reste actif jusqu'au 31 décembre, l'événement est enregistré le 31 décembre à l'expiration de l'abonnement. | | subscription_paused | Se produit lorsqu'un utilisateur active la [mise en pause de l'abonnement](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (Android uniquement). | | subscription_deferred | Déclenché lorsqu'un achat d'abonnement est [différé](https://adapty.io/glossary/subscription-purchase-deferral/), permettant aux utilisateurs de reporter le paiement tout en conservant l'accès aux fonctionnalités premium. Cette fonctionnalité est disponible via l'API Google Play Developer et peut être utilisée pour des essais gratuits ou pour les utilisateurs rencontrant des difficultés financières. | | non_subscription_purchase | Tout achat sans abonnement, tel qu'un accès à vie ou des produits consommables comme des pièces dans un jeu. | | trial_started | Déclenché lorsqu'un utilisateur active un abonnement d'essai. | | trial_converted | Se produit lorsqu'un essai se termine et que l'utilisateur est facturé (premier achat). Par exemple, si un utilisateur a un essai jusqu'au 14 janvier mais est facturé le 7 janvier, cet événement est enregistré le 7 janvier. | | trial_renewal_cancelled | Un utilisateur a désactivé le renouvellement automatique de son abonnement pendant la période d'essai. Il conserve l'accès aux fonctionnalités premium jusqu'à la fin de l'essai, mais ne sera pas facturé et ne démarrera pas d'abonnement. | | trial_renewal_reactivated | Se produit lorsqu'un utilisateur réactive le renouvellement automatique de son abonnement pendant la période d'essai. | | trial_expired | Déclenché lorsqu'un essai se termine sans conversion en abonnement. | | entered_grace_period | Se produit lorsqu'une tentative de paiement échoue et que l'utilisateur entre dans un délai de grâce (si activé). L'utilisateur conserve l'accès premium pendant cette période. | | billing_issue_detected | Déclenché lorsqu'un problème de facturation survient lors d'une tentative de débit (par exemple, solde de carte insuffisant). | | subscription_refunded | Déclenché lorsqu'un abonnement est remboursé (par exemple, par le support Apple). | | non_subscription_purchase_refunded | Déclenché lorsqu'un achat sans abonnement est remboursé. | | access_level_updated | Se produit lorsque le niveau d'accès d'un utilisateur est mis à jour. | Les événements ci-dessus couvrent entièrement l'état des utilisateurs en matière d'achats. Voici quelques exemples. ### Exemple 1 \{#example-1\} _L'utilisateur a activé un abonnement mensuel le 1er avril avec une période d'essai de 7 jours. Le 4e jour, il s'est désabonné._ Dans ce cas, les événements suivants seront envoyés : 1. `trial_started` le 1er avril 2. `trial_renewal_cancelled` le 4 avril 3. `trial_expired` le 7 avril ### Exemple 2 \{#example-2\} _L'utilisateur a activé un abonnement mensuel le 1er avril avec une période d'essai de 7 jours. Le 10e jour, il s'est désabonné._ Dans ce cas, les événements suivants seront envoyés : 1. `trial_started` le 1er avril 2. `trial_converted` le 7 avril 3. `subscription_renewal_cancelled` le 10 avril 4. `subscription_expired` le 1er mai Pour une description détaillée des événements déclenchés dans chaque scénario, consultez les [Flux d'événements](event-flows). --- # File: event-flows --- --- title: "Flux d'événements" description: "Découvrez les schémas détaillés des flux d'événements d'abonnement dans Adapty. Apprenez comment les événements d'abonnement sont générés et envoyés aux intégrations, pour suivre les moments clés du parcours de vos clients." --- Dans Adapty, vous recevrez divers événements d'abonnement tout au long du parcours d'un client dans votre application. Ces flux d'abonnement décrivent les scénarios les plus courants pour vous aider à comprendre les événements qu'Adapty génère lorsque les utilisateurs s'abonnent, annulent ou réactivent des abonnements. Gardez à l'esprit qu'Apple traite les paiements d'abonnement plusieurs heures avant la date de début ou de renouvellement effective. Dans les flux ci-dessous, nous représentons le début/renouvellement de l'abonnement et le débit comme ayant lieu simultanément pour simplifier les diagrammes. De plus, les événements liés à la même action se produisent simultanément et peuvent apparaître dans votre **Event Feed** dans n'importe quel ordre, qui peut différer de la séquence présentée dans nos diagrammes. ## Cycle de vie d'un abonnement \{#subscription-lifecycle\} ### Flux d'achat initial \{#initial-purchase-flow\} Ce flux se produit lorsqu'un client souscrit un abonnement pour la première fois sans essai. Dans ce cas, les événements suivants sont créés : - **Subscription started** - **Access level updated** pour accorder l'accès à l'utilisateur Lorsque la date de renouvellement de l'abonnement arrive, l'abonnement est renouvelé. Les événements suivants sont alors créés : - **Subscription renewal** pour démarrer une nouvelle période d'abonnement - **Access level updated** pour mettre à jour la date d'expiration de l'abonnement, prolongeant l'accès d'une période supplémentaire Les situations où le paiement échoue ou lorsque l'utilisateur annule le renouvellement sont décrites respectivement dans [Flux de résultat d'un problème de facturation](event-flows#billing-issue-outcome-flow) et [Flux d'annulation d'abonnement](event-flows#subscription-cancellation-flow). <img src="/assets/shared/img_webhook_flows/Initial_Purchase_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux d'annulation d'abonnement \{#subscription-cancellation-flow\} Lorsqu'un utilisateur annule son abonnement, les événements suivants sont créés : - **Subscription renewal canceled** pour indiquer que l'abonnement reste actif jusqu'à la fin de la période en cours, après quoi l'utilisateur perdra l'accès - L'événement **Access level updated** est créé pour désactiver le renouvellement automatique de l'accès Une fois l'abonnement terminé, l'événement **Subscription expired (churned)** est déclenché pour marquer la fin de l'abonnement. <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si un remboursement est approuvé, l'événement suivant remplace **Subscription expired (churned)** : - **Subscription refunded** pour mettre fin à l'abonnement et fournir les détails du remboursement <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow_with_a_Refund.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour Stripe, un abonnement peut être annulé immédiatement, sans attendre la fin de la période restante. Dans ce cas, tous les événements sont créés simultanément : - **Subscription renewal cancelled** - **Subscription expired (churned)** - **Access Level updated** pour supprimer l'accès de l'utilisateur Si un remboursement est approuvé, un événement **Subscription refunded** est également déclenché au moment de son approbation. <img src="/assets/shared/img_webhook_flows/Subscription_Immediate_Cancellation_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux de réactivation d'abonnement \{#subscription-reactivation-flow\} Si un utilisateur annule un abonnement, celui-ci expire, puis l'utilisateur rachète le même abonnement plus tard, un événement **Subscription renewed** sera créé. Même s'il y a une interruption d'accès, Adapty traite cela comme une seule chaîne de transactions, liée par le `vendor_original_transaction_id`. Ainsi, le rachat est considéré comme un renouvellement. Les événements **Access level updated** seront créés deux fois : - à la fin de l'abonnement pour révoquer l'accès de l'utilisateur - lors du rachat de l'abonnement pour accorder l'accès <img src="/assets/shared/img_webhook_flows/Subscription_Rejoin_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux de mise en pause d'abonnement (Android uniquement) \{#subscription-pause-flow-android-only\} Ce flux s'applique lorsqu'un utilisateur met en pause puis reprend un abonnement sur Android. La mise en pause d'un abonnement a des effets différés. Si un utilisateur met en pause un abonnement avant sa date de renouvellement, l'abonnement reste actif et l'utilisateur conserve l'accès payant pour le reste de la période de facturation. 1. Lorsque l'utilisateur met en pause un abonnement, l'événement **Subscription paused (Android only)** est déclenché. 2. À la fin de la période d'abonnement, Adapty déclenche l'événement **Access level updated** pour révoquer l'accès de l'utilisateur. 3. Lorsque l'utilisateur reprend l'abonnement, les événements suivants sont déclenchés : - **Subscription renewed** - **Access level updated** pour rétablir l'accès de l'utilisateur Ces abonnements appartiendront à la même chaîne de transactions, liée par le même **vendor_original_transaction_id**. <img src="/assets/shared/img_webhook_flows/Subscription_Paused_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Flux d'essai \{#trial-flows\} Si vous utilisez des essais dans votre application, vous recevrez des événements supplémentaires liés aux essais. ### Flux d'essai avec conversion réussie \{#trial-with-successful-conversion-flow\} Le flux le plus courant se produit lorsqu'un utilisateur démarre un essai, fournit une carte bancaire et convertit avec succès vers un abonnement standard à la fin de la période d'essai. Dans ce cas, les événements suivants sont créés au moment du démarrage de l'essai : - **Trial started** pour marquer le début de l'essai - **Access level updated** pour accorder l'accès L'événement **Trial converted** est créé lorsque l'abonnement standard démarre. <img src="/assets/shared/img_webhook_flows/Trial_Flow_with_Successful_Conversion.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux d'essai sans conversion réussie \{#trial-without-successful-conversion-flow\} Si un utilisateur annule l'essai avant qu'il ne se convertisse en abonnement, les événements suivants sont créés au moment de l'annulation : - **Trial renewal cancelled** pour désactiver la conversion automatique de l'essai en abonnement - **Access level updated** pour désactiver le renouvellement de l'accès L'utilisateur conservera l'accès jusqu'à la fin de l'essai, moment auquel l'événement **Trial expired** est créé pour marquer la fin de l'essai. <img src="/assets/shared/img_webhook_flows/Trial_Flow_without_Successful_Conversion.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux de réactivation d'abonnement après expiration d'essai \{#subscription-reactivation-after-expired-trial-flow\} Si un essai expire (en raison d'un problème de facturation ou d'une annulation) et que l'utilisateur souscrit ensuite un abonnement, les événements suivants sont créés : - **Access level updated** pour accorder l'accès à l'utilisateur - **Trial converted** Même avec un écart entre l'essai et l'abonnement, Adapty les relie via le `vendor_original_transaction_id`. Cette conversion est traitée comme faisant partie d'une chaîne de transactions continue, démarrant par un essai à prix zéro. C'est pourquoi l'événement **Trial converted** est créé plutôt que **Subscription started**. <img src="/assets/shared/img_webhook_flows/Subscription_Reactivation_Flow_after_Expired_Trial.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Changements de produit \{#product-changes\} Cette section couvre les ajustements apportés aux abonnements actifs, comme les mises à niveau, les rétrogradations ou les achats d'un produit d'un autre groupe. ### Flux de changement de produit immédiat \{#immediate-product-change-flow\} Après qu'un utilisateur change de produit, le changement peut être appliqué immédiatement dans le système avant la fin de l'abonnement (principalement en cas de mise à niveau ou de remplacement d'un produit). Dans ce cas, au moment du changement de produit : - Le niveau d'accès est modifié, et deux événements **Access level updated** sont créés : 1. pour supprimer l'accès au premier produit. 2. pour accorder l'accès au second produit. - L'ancien abonnement prend fin et un remboursement est effectué (l'événement **Subscription refunded** est créé avec `cancellation_reason` = `upgraded`). Notez qu'aucun événement **Subscription expired (churned)** n'est créé ; l'événement **Subscription refunded** le remplace. - Le nouvel abonnement démarre (l'événement **Subscription started** est créé pour le nouveau produit). <img src="/assets/shared/img_webhook_flows/Immediate_Product_Change_Flow_Upgrade.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si un utilisateur rétrograde son abonnement, le premier abonnement durera jusqu'à la fin de la période payée, puis sera remplacé par un nouvel abonnement de niveau inférieur. Dans ce cas, seul l'événement **Access level updated** pour désactiver le renouvellement automatique de l'accès sera créé immédiatement. Tous les autres événements seront créés au moment du remplacement effectif de l'abonnement : - Un autre événement **Access level updated** est créé pour accorder l'accès au second produit. - L'événement **Subscription expired (churned)** est créé pour mettre fin à l'abonnement au premier produit. - L'événement **Subscription started** est créé pour démarrer un nouvel abonnement pour le nouveau produit. <img src="/assets/shared/img_webhook_flows/Delayed_Product_Change_Downgrade.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Flux de changement de produit différé \{#delayed-product-change-flow\} Il existe également un cas où un utilisateur change de produit au moment du renouvellement de l'abonnement. Ce cas est très similaire au précédent : un événement **Access level updated** sera créé immédiatement pour désactiver le renouvellement automatique de l'accès à l'ancien produit. Tous les autres événements seront créés au moment où l'utilisateur change d'abonnement et que le changement est appliqué dans le système : - Un autre événement **Access level updated** est créé pour accorder l'accès au second produit. - L'événement **Subscription expired (churned)** est créé pour mettre fin à l'abonnement au premier produit. - L'événement **Subscription started** est créé pour démarrer un nouvel abonnement pour le nouveau produit. <img src="/assets/shared/img_webhook_flows/Product_Change_on_Renewal_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Flux de résultat d'un problème de facturation \{#billing-issue-outcome-flow\} Si les tentatives de conversion d'un essai ou de renouvellement d'un abonnement échouent en raison d'un problème de facturation, la suite dépend de si un délai de grâce est activé ou non. Avec un délai de grâce, si le paiement réussit, l'essai est converti ou l'abonnement est renouvelé. S'il échoue, le store continuera à tenter de débiter l'utilisateur pour l'abonnement ; en cas d'échec persistant, le store mettra fin à l'essai ou à l'abonnement. Ainsi, au moment du problème de facturation, les événements suivants sont créés dans Adapty : - **Billing issue detected** - **Entered grace period** (si le délai de grâce est activé) - **Access level updated** pour fournir l'accès jusqu'à la fin du délai de grâce Si le paiement réussit ultérieurement, Adapty enregistre un événement **Trial converted** ou **Subscription renewed**, et l'utilisateur ne perd pas l'accès. Si le paiement échoue définitivement et que le store annule l'abonnement, Adapty génère ces événements : - **Trial expired** ou **Subscription expired (churned)** avec `cancellation_reason: billing_error` - **Access level updated** pour révoquer l'accès de l'utilisateur <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_with_Grace_Period.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Sans délai de grâce, la période de nouvelle tentative de facturation (pendant laquelle le store continue de tenter de débiter l'utilisateur) démarre immédiatement. Si le paiement n'aboutit jamais avant la fin de la période de nouvelle tentative, le flux est identique : les mêmes événements sont créés lorsque le store met fin automatiquement à l'abonnement : - Événement **Trial expired** ou **Subscription expired (churned)** avec un `cancellation_reason` de `billing_error` - **Access level updated** pour révoquer l'accès de l'utilisateur <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_without_Grace_Period.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Flux de partage d'achats entre comptes utilisateurs \{#sharing-purchases-across-user-accounts-flows\} Lorsqu'un <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration), [Android](android-identifying-users#setting-customer-user-id-on-configuration), [React Native](react-native-identifying-users#setting-customer-user-id-on-configuration), [Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration), et [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> tente de restaurer ou d'étendre un abonnement déjà associé à un autre <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration), [Android](android-identifying-users#setting-customer-user-id-on-configuration), [React Native](react-native-identifying-users#setting-customer-user-id-on-configuration), [Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration), et [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip>, le paramètre **Sharing paid access between user accounts** d'Adapty contrôle la gestion de l'accès. Le flux variera selon l'option sélectionnée. :::note Pour les transactions Apple Family Sharing (`in_app_ownership_type=FAMILY_SHARED`), seul l'événement **Access level updated** se déclenche — les événements d'abonnement par produit ci-dessous ne se déclenchent pas. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. ::: :::note Si un utilisateur appuie sur **Restore Purchases** mais dispose déjà d'un accès sur le même profil, la restauration n'a aucun effet et aucun événement webhook n'est déclenché. Les événements de cette section ne se déclenchent que lorsque l'accès est effectivement transféré entre profils. ::: Pour avoir un aperçu rapide des événements déclenchés lorsqu'un second profil revendique un abonnement existant, utilisez cette matrice. Les sections suivantes présentent le payload JSON complet pour chaque flux. | Événement | Activé (par défaut) | Transférer l'accès au nouvel utilisateur | Désactivé | | --- | --- | --- | --- | | Nouveau profil : **Access level updated** (`is_active=true`) | Se déclenche | Se déclenche | Ne se déclenche pas | | Ancien profil : **Access level updated** (`is_active=false`) | Ne se déclenche pas — les deux profils conservent l'accès | Se déclenche lorsque le nouvel appareil identifié propage la transaction | Ne se déclenche pas — le profil d'origine conserve l'accès | | Champ `profiles_sharing_access_level` sur le nouvel événement | Répertorie les autres profils qui partagent le niveau d'accès | `null` | Non applicable — aucun événement ne se déclenche | Les renouvellements, remboursements et expirations sur un abonnement transféré continuent de déclencher les événements `subscription_renewed`, `subscription_refunded` et `subscription_expired` sur le profil qui détient actuellement le niveau d'accès. L'événement de transfert lui-même n'émet pas d'événement `subscription_started`, car aucune nouvelle transaction n'est enregistrée — seule l'attribution change. Pour les détails par mode, consultez [Référence pratique](sharing-paid-access-between-user-accounts#practical-reference). ### Flux de transfert d'accès vers un nouvel utilisateur \{#transfer-access-to-new-user-flow\} L'option recommandée est de transférer le niveau d'accès au nouvel utilisateur. Cela préserve l'historique des transactions de l'utilisateur d'origine pour des analyses cohérentes. Seuls 2 événements **Access level updated** seront créés : 1. pour supprimer l'accès du premier utilisateur 2. pour accorder l'accès au second utilisateur <img src="/assets/shared/img_webhook_flows/Transfer_Access_to_New_User_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Voici un détail des champs relatifs à l'attribution et au transfert du niveau d'accès dans les événements générés dans ce scénario : - **Utilisateur A : Access level updated (envoyé lorsque l'utilisateur A souscrit un abonnement dans l'application)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": null } ``` - **Utilisateur A : Access level updated (envoyé lorsque l'application est réinstallée et que l'utilisateur B se connecte, révoquant l'accès de l'utilisateur A)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": false, }, "profiles_sharing_access_level": null } ``` - **Utilisateur B : Access level updated (envoyé lorsque l'utilisateur B se connecte et que l'accès lui est accordé)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000001", "customer_user_id": UserB, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": null } ``` ### Flux de partage d'accès entre utilisateurs \{#shared-access-between-users-flow\} Cette option permet à plusieurs utilisateurs de partager le même niveau d'accès si leur appareil est connecté au même identifiant Apple/Google. C'est utile lorsqu'un utilisateur réinstalle l'application et se connecte avec une adresse e-mail différente — il conservera quand même l'accès à son achat précédent. Avec cette option, plusieurs utilisateurs identifiés peuvent partager le même niveau d'accès. Pendant le partage du niveau d'accès, toutes les transactions sont enregistrées sous le <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration), [Android](android-identifying-users#setting-customer-user-id-on-configuration), [React Native](react-native-identifying-users#setting-customer-user-id-on-configuration), [Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration), et [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> d'origine pour maintenir un historique complet des transactions et des analyses. Par conséquent, un seul événement sera créé : **Access level updated** pour accorder l'accès au second utilisateur. <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Voici un détail des champs relatifs à l'attribution et au partage du niveau d'accès dans les événements générés dans ce scénario : **Utilisateur B : Access level updated (envoyé lorsque l'utilisateur B se connecte et que l'accès lui est accordé)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": [ { "profile_id": "00000000-0000-0000-0000-000000000001, "customer_user_id": UserB } ] } ``` ### Flux sans partage d'accès entre utilisateurs \{#access-not-shared-between-users-flow\} Avec cette option, seul le premier profil utilisateur à recevoir le niveau d'accès le conserve de façon permanente. C'est idéal si les achats doivent être liés à un seul <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration), [Android](android-identifying-users#setting-customer-user-id-on-configuration), [React Native](react-native-identifying-users#setting-customer-user-id-on-configuration), [Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration), et [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip>. <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Disabled_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: event-statuses --- --- title: "Statuts des événements d'intégration" description: "" --- Adapty détermine la délivrabilité en fonction du code de statut HTTP, considérant toute réponse en dehors de la plage `200-399` comme un échec. Vous pouvez suivre le statut des événements d'intégration dans l'**Event List** au sein de l'Adapty Dashboard. Le système affiche les statuts pour toutes les intégrations activées, qu'un type d'événement spécifique soit activé ou non pour une intégration donnée. - Noir : l'événement a été envoyé avec succès. - <span style={{ color: 'grey' }}>Gris :</span> le type d'événement est désactivé pour cette intégration. - <span style={{ color: 'red' }}>Rouge :</span> un problème affecte l'intégration et nécessite votre attention. Pour plus de détails sur les événements en échec, survolez le nom de l'intégration pour afficher une infobulle avec les informations d'erreur spécifiques. <img src="/assets/shared/img/event-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> L'**Event Feed** affiche les données des deux dernières semaines pour optimiser les performances. Cette limitation améliore la vitesse de chargement des pages, ce qui permet aux utilisateurs de parcourir et d'analyser les événements plus facilement. --- # File: attribution-integration --- --- title: "Intégration de l'attribution" description: "Intégrez Adapty avec des outils d'attribution pour suivre l'acquisition d'utilisateurs et la LTV." --- Adapty peut échanger des informations avec des services tiers pour attribuer les événements d'abonnement à des campagnes marketing spécifiques. Cet échange vous permet de : * Découvrir quelles stratégies marketing génèrent le plus de revenus * Filtrer les [graphiques d'abonnements](charts) Adapty par attribution * Utiliser les fonctionnalités d'un service tiers pour analyser les données d'abonnements Adapty Vous pouvez le configurer de deux façons : * [L'attribution intégrée](#integrated-attribution) nécessite une configuration minimale et permet à Adapty d'échanger des données avec 9 plateformes populaires. * [L'attribution manuelle](#manual-attribution) vous oblige à récupérer vous-même les données d'attribution depuis les API de services tiers avant de pouvoir les envoyer à Adapty. :::tip Activez [Adapty Attribution](user-acquisition) pour une vue complète de l'économie de votre application. Adapty Attribution est un tableau de bord web facile à configurer qui consolide les données de différentes sources pour identifier les stratégies d'acquisition d'utilisateurs efficaces. ::: :::warning Gardez vos données propres : évitez la duplication d'événements et les conflits d'attribution. Suivez les conseils de la section **[Éviter les problèmes de données](#prevent-data-issues)** pour vous assurer qu'une nouvelle source de données ne pollue pas vos analyses. ::: ## Attribution intégrée \{#integrated-attribution\} Adapty propose une intégration d'attribution clé en main avec 9 services populaires. Ces plateformes peuvent automatiquement recevoir les [données d'abonnements](events) d'Adapty, traiter chaque achat et répondre avec une attribution appropriée. Chaque plateforme a un fonctionnement différent, mais les étapes sont similairement simples : 1. **Configurez le partage automatique des données.** Autorisez Adapty à communiquer avec la plateforme de votre choix. 2. **Intégrez le SDK Adapty.** Certaines plateformes nécessitent du code supplémentaire pour définir les données d'attribution. 3. **Désactivez les autres services de partage d'événements et sources d'attribution** pour éviter la [duplication d'événements](#avoid-event-duplication) et les [conflits de données](#select-a-single-attribution-source). Consultez le guide spécifique à chaque plateforme pour un aperçu détaillé de l'intégration : - [Adjust](adjust) - [Airbridge](airbridge) - [Apple Search Ads](apple-search-ads) - [AppsFlyer](appsflyer) - [Asapty](asapty) - [Branch](branch) - [Facebook Ads](facebook-ads) - [Singular](singular) - [Tenjin](tenjin) :::note Si vous souhaitez qu'Adapty étende cette liste, [créez une demande de fonctionnalité](https://adapty.featurebase.app/en?b=6979f233ebd3cffd4f425ba0) et exprimez votre intérêt pour un service particulier. ::: ## Attribution manuelle \{#manual-attribution\} Si Adapty ne propose pas d'[attribution intégrée](#integrated-attribution) avec le service de votre choix, vous devez écrire votre propre code pour échanger des données avec la source d'attribution. 1. **Récupérez les données depuis le service d'attribution**. Utilisez l'API du service pour demander les données d'attribution. 2. **Créez un dictionnaire avec les données d'attribution reçues.** Le dictionnaire peut contenir les clés suivantes : - `status` (`organic`, `non-organic` ou `unknown`) - `channel` - `campaign` - `ad_group` - `ad_set` - `creative` :::important * Toutes les clés sont optionnelles. * Adapty ignore les clés qui ne figurent pas dans la liste. * La valeur de chaque clé peut comporter jusqu'à 50 caractères. ::: **Exemple** : ```swift showLineNumbers title="Swift" let attribution = [ "status": "non_organic", "channel": "Google Ads", "campaign": "Christmas Sale", "ad_group": "ad group 1", "ad_set": "ad set 1", "creative": "creative id 1" ] ``` 3. **Définissez les données d'attribution** : Transmettez le dictionnaire d'attribution à la méthode `updateAttribution`. Une fois la valeur d'attribution définie, elle ne peut plus être remplacée : ```swift showLineNumbers title="Swift" Adapty.updateAttribution(attribution, source: "custom") { error in if error == nil { // successful attribution update } } ``` **Paramètres :** - `attribution` (requis) : dictionnaire contenant les données d'attribution. - `source` (requis) : source d'attribution. Définissez-la sur `.custom` si votre fournisseur d'attribution ne prend pas en charge l'[attribution intégrée](#integrated-attribution). 4. **Désactivez les autres services de partage d'événements et sources d'attribution** pour éviter la [duplication d'événements](#avoid-event-duplication) et les [conflits de données](#select-a-single-attribution-source). ## Éviter les problèmes de données \{#prevent-data-issues\} ### Choisir une seule source d'attribution \{#select-a-single-attribution-source\} N'activez pas l'intégration d'attribution avec plusieurs plateformes simultanément. Adapty ne peut accepter qu'une seule source d'attribution à la fois, et une fois qu'il enregistre la valeur d'attribution, il ne peut plus la remplacer. Si vous activez plusieurs sources d'attribution, Adapty sélectionnera la source avec le plus de données — pas nécessairement les meilleures. Par exemple, l'[attribution Apple Search Ads](apple-search-ads) non organique aura toujours la priorité sur iOS. Pour désactiver l'attribution Apple Search Ads, ouvrez l'onglet [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) et désactivez le bouton **Receive Apple Search Ads attribution**. ### Éviter la duplication d'événements \{#avoid-event-duplication\} Si vous utilisez Adapty pour partager des données d'abonnements en temps réel avec vos services d'attribution, **vous devez désactiver** les autres services qui remplissent le même rôle. Si vous avez connecté votre compte Facebook à AppsFlyer, Adjust ou Branch, vos événements seront automatiquement transmis à ces services, sauf si vous vous y opposez. Les événements en double peuvent fausser vos analyses et rendre l'interprétation des données difficile. Une fois la configuration du partage d'événements Adapty terminée, désactivez les fonctionnalités de transfert d'événements tiers. --- # File: adjust --- --- title: "Adjust" description: "Connectez Adjust à Adapty pour un meilleur suivi des abonnements et des analyses." --- [Adjust](https://www.adjust.com/) est l'une des principales plateformes MMP (Mobile Measurement Partner) qui collecte et présente les données issues des campagnes marketing, aidant ainsi les entreprises à suivre leurs performances publicitaires. Adapty fournit un ensemble complet de données vous permettant de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et communiquer avec eux de façon ciblée et efficace. Cette intégration vous permet donc de suivre les événements d'abonnement dans Adjust et d'analyser précisément les revenus générés par vos campagnes. L'intégration entre Adapty et Adjust fonctionne de deux manières principales. 1. **Adapty reçoit les données d'attribution depuis Adjust** Une fois l'intégration Adjust configurée, Adapty commencera à recevoir les données d'attribution depuis Adjust. Vous pouvez consulter ces données directement sur la page du profil utilisateur. <img src="/assets/shared/img/98769d9-CleanShot_2023-08-11_at_14.39.182x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Adapty envoie les événements d'abonnement à Adjust** Adapty peut envoyer tous les événements d'abonnement configurés dans votre intégration vers Adjust. Vous pourrez ainsi suivre ces événements dans le tableau de bord Adjust, ce qui est particulièrement utile pour évaluer l'efficacité de vos campagnes publicitaires. ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Adjust \{#connect-adapty-to-adjust\} 1. Ouvrez l'Adapty Dashboard et accédez à [Integrations > Adjust](https://app.adapty.io/integrations/adjust). 2. Activez le bouton en haut de la page. 3. Remplissez les champs et saisissez vos identifiants d'accès. <img src="/assets/shared/img/5064125-CleanShot_2023-08-11_at_14.43.382x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Si vous avez activé l'autorisation OAuth sur la plateforme Adjust, vous devez obligatoirement fournir un **OAuth Token** lors du processus d'intégration pour vos applications iOS et Android. 4. Ensuite, renseignez les **app tokens** de vos applications iOS et Android. Ouvrez votre tableau de bord Adjust pour retrouver vos applications. <img src="/assets/shared/img/adjust-apps.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Vous pouvez avoir des applications Adjust différentes pour iOS et Android — c'est pourquoi Adapty propose deux sections indépendantes. Si vous n'avez qu'une seule application Adjust, saisissez simplement les mêmes informations dans les deux sections. ::: 5. Sélectionnez votre application dans la liste et copiez l'**App Token**. Collez-le dans le champ correspondant sur l'Adapty Dashboard. <img src="/assets/shared/img/adjust-token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Configurer les événements et les tags \{#configure-events-and-tags\} Adjust fonctionne un peu différemment des autres plateformes. Vous devez créer manuellement des événements dans le tableau de bord Adjust, récupérer leurs tokens, puis les copier-coller dans les événements correspondants dans Adapty. La première étape consiste donc à trouver les tokens d'événement pour tous les événements que vous souhaitez qu'Adapty envoie. Pour ce faire : 1. Dans le tableau de bord Adjust, ouvrez votre application et accédez à l'onglet **Events**. <img src="/assets/shared/img/adjust-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. Copiez le token de l'événement et collez-le dans Adapty. Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer depuis Adapty vers Adjust. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/adjust-event-token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty enverra les événements d'abonnement à Adjust via une intégration serveur à serveur, vous permettant de les visualiser dans votre tableau de bord Adjust et de les associer à vos campagnes d'acquisition. :::important Tenez compte des points suivants : - Adjust ne prend pas en charge les événements de plus de 58 jours. Si un événement date de plus de 58 jours, Adapty l'enverra quand même à Adjust, mais la date et l'heure de l'événement seront remplacées par l'horodatage actuel. - Adjust ne prend pas en charge l'IPv6. Si vous désactivez la collecte d'IP dans le SDK via **App settings** ou lors de l'activation du SDK, seule une IP backend en IPv6 pourrait être envoyée, ce qui peut faire échouer le suivi — gardez la collecte d'IP du SDK activée pour garantir l'utilisation de l'IPv4. ::: ### Connecter votre application à Adjust \{#connect-your-app-to-adjust\} Une fois les étapes ci-dessus effectuées, ajoutez les deux méthodes suivantes à votre application pour établir la communication entre votre application et Adjust : 1. **Pour envoyer les données d'abonnement à Adjust** : transmettez l'identifiant appareil Adjust à la méthode SDK `setIntegrationIdentifier()` 2. **Pour recevoir les données d'attribution depuis Adjust** : mettez à jour les données d'attribution avec la méthode SDK `updateAttribution()` Pour Adjust version 5.0 ou ultérieure, utilisez l'exemple suivant : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers class AdjustModuleImplementation { func updateAdjustAdid() { Adjust.adid { adid in guard let adid else { return } // Adapty SDK 4.x Adapty.setIntegrationIdentifier(.adjustDeviceId(adid)) // Adapty SDK 3.x Adapty.setIntegrationIdentifier(key: "adjust_device_id", value: adid) } } func updateAdjustAttribution() { Adjust.attribution { attribution in guard let attribution = attribution?.dictionary() else { return } // Adapty SDK 4.x Adapty.updateAttribution(attribution, source: .adjust) // Adapty SDK 3.x Adapty.updateAttribution(attribution, source: "adjust") } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adjust.getAdid { adid -> if (adid == null) return@getAdid Adapty.setIntegrationIdentifier("adjust_device_id", adid) { error -> if (error != null) { // handle the error } } } Adjust.getAttribution { attribution -> if (attribution == null) return@getAttribution Adapty.updateAttribution(attribution, "adjust") { error -> // handle the error } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adjust.getAdid(adid -> { if (adid == null) return; Adapty.setIntegrationIdentifier("adjust_device_id", adid, error -> { if (error != null) { // handle the error } }); }); Adjust.getAttribution(attribution -> { if (attribution == null) return; Adapty.updateAttribution(attribution, "adjust", error -> { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers 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); }); ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers try { final adid = await Adjust.getAdid(); if (adid == null) { // handle the error } await Adapty().setIntegrationIdentifier( key: "adjust_device_id", value: adid, ); final attributionData = await Adjust.getAttribution(); var attribution = Map<String, String>(); if (attributionData.trackerToken != null) attribution['trackerToken'] = attributionData.trackerToken!; if (attributionData.trackerName != null) attribution['trackerName'] = attributionData.trackerName!; if (attributionData.network != null) attribution['network'] = attributionData.network!; if (attributionData.adgroup != null) attribution['adgroup'] = attributionData.adgroup!; if (attributionData.creative != null) attribution['creative'] = attributionData.creative!; if (attributionData.clickLabel != null) attribution['clickLabel'] = attributionData.clickLabel!; if (attributionData.costType != null) attribution['costType'] = attributionData.costType!; if (attributionData.costAmount != null) attribution['costAmount'] = attributionData.costAmount!.toString(); if (attributionData.costCurrency != null) attribution['costCurrency'] = attributionData.costCurrency!; if (attributionData.fbInstallReferrer != null) attribution['fbInstallReferrer'] = attributionData.fbInstallReferrer!; await Adapty().updateAttribution(attribution, source: "adjust"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers // 1. To update ADID Adjust.GetAdid((adid) => { if (adid == null) { // handle the error return; } Adapty.SetIntegrationIdentifier("adjust_device_id", adid, (error) => { if (error != null) { // handle the error return; } }); }); // 2. To update Attribution // in your adjust configuration scope: adjustConfig.AttributionChangedDelegate = AttributionChangedCallback; public void AttributionChangedCallback(AdjustAttribution attributionData) { var attribution = new Dictionary<string, string>(); if (attributionData.TrackerToken != null) attribution["trackerToken"] = attributionData.TrackerToken; if (attributionData.TrackerName != null) attribution["trackerName"] = attributionData.TrackerName; if (attributionData.Network != null) attribution["network"] = attributionData.Network; if (attributionData.Adgroup != null) attribution["adgroup"] = attributionData.Adgroup; if (attributionData.Creative != null) attribution["creative"] = attributionData.Creative; if (attributionData.ClickLabel != null) attribution["clickLabel"] = attributionData.ClickLabel; if (attributionData.CostType != null) attribution["costType"] = attributionData.CostType; if (attributionData.CostAmount != null) attribution["costAmount"] = attributionData.CostAmount.ToString(); if (attributionData.CostCurrency != null) attribution["costCurrency"] = attributionData.CostCurrency; if (attributionData.FbInstallReferrer != null) attribution["fbInstallReferrer"] = attributionData.FbInstallReferrer; // you will probably need to install Newtonsoft.Json package, if not yet var attributionJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(attribution); Adapty.UpdateAttribution(attributionJsonString, "adjust", (error) => { if (error != null) { // handle the error } }); } ``` </TabItem> </Tabs> ## Structure d'un événement \{#event-structure\} Adapty envoie les événements sélectionnés à Adjust selon la configuration définie dans la section **Events names** de la [**page d'intégration Adjust**](https://app.adapty.io/integrations/adjust). Chaque événement est structuré comme suit : ```json { "event_token": "EVENT_TOKEN_FROM_CONFIG", "app_token": "APP_TOKEN_FROM_CONFIG", "s2s": 1, "environment": "production", "created_at_unix": 1709294400, "currency": "USD", "revenue": 9.99, "customer_user_id": "user_12345", "external_device_id": "user_12345", "ip_address": "192.168.100.1", "user_agent": "Mozilla/5.0 (Linux; Android 14; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36", "android_id": "875646c2-4a56-4211-8931-168532479006", "gps_adid": "875646c2-4a56-4211-8931-168532479006", "callback_params": "{\"integration_event_id\":\"550e8400-e29b-41d4-a716-446655440000\",\"customer_user_id\":\"user_12345\",\"vendor_product_id\":\"com.example.app.yearly.premium\",\"transaction_id\":\"GPA.3312-4512-1100-55923\",\"original_transaction_id\":\"GPA.3312-4512-1100-55923\",\"store\":\"play_store\",\"store_country\":\"US\",\"price_usd\":9.99,\"proceeds_usd\":8.49,\"price_local\":9.99,\"proceeds_local\":8.49,\"net_revenue_usd\":8.49,\"net_revenue_local\":8.49,\"tax_amount_usd\":0.0,\"tax_amount_local\":0.0,\"consecutive_payments\":3,\"rate_after_first_year\":false}", "partner_params": "{\"integration_event_id\":\"550e8400-e29b-41d4-a716-446655440000\",\"customer_user_id\":\"user_12345\",\"vendor_product_id\":\"com.example.app.yearly.premium\",\"transaction_id\":\"GPA.3312-4512-1100-55923\",\"original_transaction_id\":\"GPA.3312-4512-1100-55923\",\"store\":\"play_store\",\"store_country\":\"US\",\"price_usd\":9.99,\"proceeds_usd\":8.49,\"price_local\":9.99,\"proceeds_local\":8.49,\"net_revenue_usd\":8.49,\"net_revenue_local\":8.49,\"tax_amount_usd\":0.0,\"tax_amount_local\":0.0,\"consecutive_payments\":3,\"rate_after_first_year\":false}" } ``` Où | Paramètre | Type | Description | |:---------------------|:--------|:---------------------------------------------------------------------------------------------------------------------------------------------| | `app_token` | String | Le token d'application Adjust issu de vos paramètres d'intégration. | | `event_token` | String | Le token d'événement Adjust associé à l'événement Adapty spécifique. | | `s2s` | Integer | Indicateur d'événement serveur à serveur. | | `environment` | String | `sandbox` ou `production`. | | `created_at_unix` | Integer | Horodatage de l'événement en secondes. | | `currency` | String | Code de devise (ex. : "USD") pour la transaction. Inclus uniquement si le revenu dépasse 0,001, car Adjust exige que le revenu et la devise soient envoyés ensemble. | | `revenue` | Float | Montant du revenu de la transaction. Inclus uniquement si la valeur dépasse 0,001. Les événements de remboursement sont envoyés sans propriétés de revenu, car Adjust ne prend pas en charge les valeurs de revenu négatives. | | `customer_user_id` | String | L'identifiant utilisateur client (Customer User ID). | | `external_device_id` | String | Identique à `customer_user_id`. | | `ip_address` | String | Adresse IP de l'utilisateur (IPv4 uniquement). | | `user_agent` | String | Chaîne User Agent de l'appareil. | | `adid` | String | Identifiant appareil Adjust (si connu). | | `android_id` | String | **Android uniquement**. Google Advertising ID. | | `gps_adid` | String | **Android uniquement**. Google Advertising ID. | | `idfa` | String | **iOS uniquement**. ID for Advertisers. | | `idfv` | String | **iOS uniquement**. ID for Vendors. | | `callback_params` | String | Chaîne JSON contenant tous les [champs d'événement](webhook-event-types-and-fields#for-most-event-types) disponibles. Seuls les champs non nuls sont inclus. | | `partner_params` | String | Identique à `callback_params`. | ## Dépannage \{#troubleshooting\} ### Écart de revenus \{#revenue-discrepancy\} Un écart de revenus entre Adapty et Adjust peut survenir lorsque certains de vos utilisateurs n'ont pas encore mis à jour l'application vers une version intégrant le SDK Adapty. Pour garantir la cohérence des données, vous pouvez forcer vos utilisateurs à mettre à jour l'application vers une version incluant le SDK Adapty. --- # File: airbridge --- --- title: "Airbridge" description: "Connectez Adapty à Airbridge pour suivre les insights marketing et d'attribution." --- [Airbridge](https://www.airbridge.io/) propose une analyse intégrée des performances marketing pour les sites web et les applications mobiles, en consolidant les données collectées depuis plusieurs appareils, plateformes et canaux. Grâce au moteur de résolution d'identité d'Airbridge, vous pouvez combiner les données d'identité client éparpillées provenant des interactions web et app en une identité unifiée basée sur les personnes, ce qui permet une attribution plus précise. Adapty fournit un ensemble complet de données qui vous permet de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et utiliser ces informations pour communiquer avec eux de manière ciblée et efficace. L'intégration entre Adapty et Airbridge fonctionne de deux façons principales. 1. **Réception des données d'attribution depuis Airbridge** Une fois l'intégration Airbridge configurée, Adapty commence à recevoir les données d'attribution d'Airbridge. Vous pouvez facilement consulter ces données sur la page de l'utilisateur. 2. **Envoi des événements d'abonnement à Airbridge** Adapty peut envoyer tous les événements d'abonnement configurés dans votre intégration à Airbridge. Vous pouvez ainsi suivre ces événements dans le tableau de bord Airbridge. Cette intégration est utile pour évaluer l'efficacité de vos campagnes publicitaires. ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Airbridge \{#connect-adapty-to-airbridge\} Pour intégrer Airbridge, rendez-vous dans [Integrations > Airbridge](https://app.adapty.io/integrations/airbridge), activez le bouton (de off à on) et remplissez les champs. Commencez par renseigner les identifiants pour établir la connexion entre vos profils Airbridge et Adapty. Le nom de l'application Airbridge et le token API Airbridge sont obligatoires. <img src="/assets/shared/img/2b31d90-Untitled-1_1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Ces deux informations se trouvent dans votre tableau de bord Airbridge, dans la section [Third-party Integrations > Adapty](https://app.airbridge.io/app/testad/integrations/third-party/adapty). <img src="/assets/shared/img/5a2f627-Screenshot_2023-02-21_at_11.19.29_AM.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Le champ Adapty API token est prégénéré côté backend Adapty. Vous devez copier la valeur du token API Adapty et la coller dans le tableau de bord Airbridge, dans le champ Adapty Authorization Token. <img src="/assets/shared/img/ff422d1-CleanShot_2023-03-01_at_17.11.412x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Configurer les événements et les tags \{#configure-events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à Airbridge depuis Adapty. <img src="/assets/shared/img/eb4e3a9-CleanShot_2023-08-22_at_13.58.472x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Activez simplement ceux dont vous avez besoin. ### Connecter votre application à Airbridge \{#connect-your-app-to-airbridge\} Pour l'intégration, vous devez passer `airbridge_device_id` au profile builder et appeler `setIntegrationIdentifier` comme indiqué dans l'exemple ci-dessous : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "airbridge_device_id", value: AirBridge.deviceUUID() ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Airbridge.getDeviceInfo().getUUID(object: AirbridgeCallback.SimpleCallback<String>() { override fun onSuccess(result: String) { Adapty.setIntegrationIdentifier("airbridge_device_id", result) { error -> if (error != null) { // handle the error } } } override fun onFailure(throwable: Throwable) { } }) ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final deviceUUID = await Airbridge.state.deviceUUID; try { await Adapty().setIntegrationIdentifier( key: "airbridge_device_id", value: deviceUUID, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers try { const deviceId = await Airbridge.state.deviceUUID(); await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> Pour en savoir plus sur airbridgeDeviceId, consultez la [documentation Airbridge](https://help.airbridge.io/en/developers/airbridge-device-id-faq). Il peut s'écouler jusqu'à 24 heures avant qu'Adapty reçoive les données d'attribution Airbridge suite à un événement d'abonnement. Adapty les affichera immédiatement dans le tableau de bord. ## Structure des événements \{#event-structure\} Adapty envoie les événements sélectionnés à Airbridge tels que configurés dans la section **Events names** de la [**page d'intégration Airbridge**](https://app.adapty.io/integrations/airbridge). Chaque événement est structuré comme suit : ```json { "user": { "externalUserID": "user_12345", "externalUserEmail": "user@example.com", "attributes": { "is_premium": true } }, "device": { "deviceUUID": "550e8400-e29b-41d4-a716-446655440000", "deviceModel": "iPhone 14 Pro", "osName": "iOS", "osVersion": "17.0.1", "locale": "en-US", "timezone": "America/New_York", "ifa": "00000000-0000-0000-0000-000000000000", "ifv": "00000000-0000-0000-0000-000000000000" }, "app": { "packageName": "com.example.app", "version": "1.2.3" }, "eventUUID": "d4f6f1f4-96fb-4a31-bafd-599fef77be90", "eventTimestamp": 1709294400000, "eventData": { "goal": { "category": "airbridge.subscribe", "customAttributes": { "isTrialConverted": true }, "semanticAttributes": { "transactionID": "GPA.3383-4699-1373-07113", "totalValue": 9.99, "currency": "USD", "period": "P1M", "isRenewal": true, "renewalCount": 2, "products": [ { "productID": "yearly.premium.6999", "name": "yearly.premium.6999", "position": 1 } ] } } } } ``` Où : | Paramètre | Type | Description | |:---------------------------------------------|:--------|:-----------------------------------------------------------------------------------------| | `user` | Object | Informations sur l'utilisateur. | | `user.externalUserID` | String | L'identifiant utilisateur client (Customer User ID). | | `user.externalUserEmail` | String | L'adresse e-mail de l'utilisateur (si disponible). | | `user.attributes` | Object | Attributs personnalisés de l'utilisateur. | | `device` | Object | Informations sur l'appareil. | | `device.deviceUUID` | String | L'UUID de l'appareil Airbridge. | | `device.deviceModel` | String | Modèle de l'appareil (ex. : "iPhone 14 Pro"). | | `device.osName` | String | Nom du système d'exploitation (ex. : "iOS", "Android"). | | `device.osVersion` | String | Version du système d'exploitation. | | `device.ifa` | String | **iOS uniquement**. ID for Advertisers. | | `device.ifv` | String | **iOS uniquement**. ID for Vendors. | | `device.gaid` | String | **Android uniquement**. Google Advertising ID. | | `app` | Object | Informations sur l'application. | | `app.packageName` | String | Le nom de package / bundle ID de l'application. | | `app.version` | String | La version de l'application. | | `eventUUID` | String | Identifiant unique de l'événement dans Adapty. | | `eventTimestamp` | Long | Horodatage de l'événement en millisecondes. | | `eventData` | Object | Détails de l'événement. | | `eventData.goal.category` | String | La catégorie d'événement Airbridge (mappée depuis l'événement Adapty). | | `eventData.goal.semanticAttributes` | Object | Attributs d'événement standard. | | `...semanticAttributes.transactionID` | String | Identifiant de transaction du store. | | `...semanticAttributes.totalValue` | Float | Montant des revenus. | | `...semanticAttributes.currency` | String | Code de devise (ex. : "USD"). | | `...semanticAttributes.period` | String | Période d'abonnement au format de durée ISO 8601 (ex. : "P1M"). | | `...semanticAttributes.isRenewal` | Boolean | `true` s'il s'agit d'une transaction de renouvellement. | | `...semanticAttributes.renewalCount` | Integer | Nombre de renouvellements réussis. | | `...semanticAttributes.products` | Array | Liste des produits impliqués dans l'événement. | | `...semanticAttributes.products[].productID` | String | L'identifiant du produit dans le store (ex. : "yearly.premium.6999"). | | `...semanticAttributes.products[].name` | String | Identique à `productID`. | | `...semanticAttributes.products[].position` | Integer | La position du produit dans la liste (toujours 1). | --- # File: apple-search-ads --- --- title: "Apple Ads" description: "Intégrez Apple Ads avec Adapty pour optimiser les conversions d'abonnements." --- :::important L'intégration Apple Ads dans **App settings** est utilisée uniquement pour l'analyse de base et pour les intégrations SplitMetrics Acquire et Asapty. [Adapty Ads Manager](adapty-ads-manager) utilise une connexion distincte. Connectez votre compte Apple Ads dans [Adapty Ads Manager](adapty-ads-manager-get-started). ::: Adapty vous permet d'obtenir des données d'attribution depuis Apple Ads et d'analyser vos métriques avec une segmentation par campagne et par mot-clé. Adapty collecte automatiquement les données d'attribution pour Apple Ads via son SDK et le framework AdServices. Une fois l'intégration Apple Ads configurée, Adapty commencera à recevoir les données d'attribution d'Apple Ads. Vous pouvez consulter ces données directement sur la page des profils. <img src="/assets/shared/img/ba4a3e9-CleanShot_2023-08-21_at_15.14.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty au framework AdServices \{#connect-adapty-to-the-adservices-framework\} Apple Ads via [AdServices](https://developer.apple.com/documentation/adservices) nécessite une configuration dans l'Adapty Dashboard, et vous devrez également l'activer côté application. Pour configurer Apple Ads via le framework AdServices avec Adapty, suivez ces étapes : #### Étape 1 : Obtenir la clé publique \{#step-1-obtain-public-key\} Dans l'Adapty Dashboard, rendez-vous dans [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads) Repérez la clé publique pré-générée (Adapty génère une paire de clés pour vous) et copiez-la. <img src="/assets/shared/img/baa5998-CleanShot_2023-08-21_at_14.55.542x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Si vous utilisez un service alternatif ou votre propre solution pour l'attribution Apple Ads, vous pouvez importer votre propre clé privée. ::: #### Étape 2 : Configurer la gestion des utilisateurs sur Apple Ads \{#step-2-configure-user-management-on-apple-ads\} Dans votre [compte Apple Ads](https://ads.apple.com/app-store), accédez à la page **Settings > User Management**. Pour qu'Adapty puisse récupérer les données d'attribution, vous devez inviter un autre compte Apple ID et lui accorder un accès API Account Manager. Vous pouvez utiliser n'importe quel compte auquel vous avez accès ou en créer un nouveau à cet effet. L'essentiel est que vous puissiez vous connecter à Apple Ads avec cet Apple ID. <img src="/assets/shared/img/ec183b2-kdjsfldsfjkdsfdfd.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### Étape 3 : Générer les identifiants API \{#step-3-generate-api-credentials\} Connectez-vous ensuite au compte nouvellement ajouté dans Apple Ads. Dans l'interface Apple Ads, accédez à Settings -> API. Collez la clé publique copiée précédemment dans le champ prévu à cet effet. Générez de nouveaux identifiants API. #### Étape 4 : Configurer Adapty avec les identifiants Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\} Copiez les champs Client ID, Team ID et Key ID depuis les paramètres Apple Ads. Dans l'Adapty Dashboard, collez ces identifiants dans les champs correspondants. <img src="/assets/shared/img/7356113-CleanShot_2023-08-21_at_15.08.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Connecter votre application au réseau AdServices \{#connect-your-app-to-the-adservices-network\} Une fois que vous avez terminé [la configuration du framework AdServices](#connect-adapty-to-the-adservices-framework), Adapty commence automatiquement à collecter les données d'attribution Apple Search Ad. Vous n'avez pas besoin d'ajouter de code SDK. Pour les applications iOS, ces données d'attribution auront **toujours** la priorité sur les données provenant d'autres sources. Si ce comportement n'est pas souhaité, *désactivez* l'attribution ASA en suivant les instructions ci-dessous. ## Désactiver l'intégration \{#disable-integration\} Pour désactiver l'attribution Apple Search Ads, ouvrez l'onglet [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) et désactivez le bouton **Receive Apple Search Ads attribution**. <img src="/assets/shared/img/asa-disable.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning Veuillez noter que la désactiver arrêtera complètement la réception des données analytiques ASA. Par conséquent, ASA ne sera plus utilisé dans les analyses ni envoyé aux intégrations. De plus, SplitMetrics Acquire et Asapty cesseront de fonctionner, car ils dépendent de l'attribution ASA pour fonctionner correctement. L'attribution reçue avant cette modification ne sera pas affectée. ::: ## Téléverser vos propres clés \{#uploading-your-own-keys\} :::note Facultatif Ces étapes ne sont pas nécessaires pour l'attribution Apple Ads, uniquement pour travailler avec d'autres services comme Asapty ou votre propre solution. ::: Vous pouvez utiliser votre propre paire de clés publique-privée si vous faites appel à d'autres services ou à votre propre solution pour l'attribution ASA. ### Étape 1 \{#step-1\} Générez une clé privée dans le Terminal ```text showLineNumbers title="Text" openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem ``` Importez-la dans Adapty Settings -> Apple Ads (bouton Upload private key) ### Étape 2 Générez la clé publique dans le Terminal ```text showLineNumbers title="Text" openssl ec -in private-key.pem -pubout -out public-key.pem ``` Vous pouvez utiliser cette clé publique dans les paramètres Apple Ads de votre compte avec le rôle API Account Manager. Vous pouvez ainsi utiliser les valeurs Client ID, Team ID et Key ID générées pour Adapty et d'autres services. --- # File: appsflyer --- --- title: "AppsFlyer" description: "Intégrez AppsFlyer avec Adapty pour un suivi avancé de l'attribution mobile." --- [AppsFlyer](https://www.appsflyer.com/) est une plateforme de référence pour l'attribution mobile et l'analyse marketing. Il s'agit d'un service tiers qui collecte et organise les données des campagnes marketing, permettant aux entreprises de mesurer les performances de leurs campagnes en un seul endroit. Adapty fournit un ensemble complet de données pour suivre les [événements d'abonnement](events) des stores en un seul endroit. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et utiliser ces informations pour leur communiquer de façon ciblée et efficace. Cette intégration vous permet ainsi de suivre les événements d'abonnement dans AppsFlyer et d'analyser précisément les revenus générés par vos campagnes. L'intégration entre Adapty et AppsFlyer fonctionne de deux manières principales. 1. **Réception des données d'attribution depuis AppsFlyer** Une fois que vous avez [configuré l'envoi de l'attribution AppsFlyer à Adapty dans le code de votre app](appsflyer#connect-your-app-to-appsflyer), Adapty commence à recevoir les données d'attribution d'AppsFlyer. Vous pouvez consulter ces données directement sur la page du profil utilisateur. <img src="/assets/shared/img/c2991f6-CleanShot_2023-08-04_at_16.29.202x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Envoi des événements d'abonnement à AppsFlyer** Adapty peut envoyer tous les événements d'abonnement configurés dans votre intégration à AppsFlyer. Vous pourrez ainsi suivre ces événements depuis le tableau de bord AppsFlyer, ce qui est utile pour évaluer l'efficacité de vos campagnes publicitaires. ## Configuration \{#set-up-configuration\} ### Connecter Adapty à AppsFlyer \{#connect-adapty-to-appsflyer\} Pour configurer l'intégration avec AppsFlyer : 1. Ouvrez [**Integrations** -> **AppsFlyer**](https://app.adapty.io/integrations/appsflyer) dans l'Adapty Dashboard. 2. Activez le toggle pour activer l'intégration. 3. L'étape suivante consiste à renseigner les identifiants. Pour iOS, trouvez l'App ID en copiant l'**Apple ID** depuis App Store Connect (ouvrez la page de votre app dans [App Store Connect](https://appstoreconnect.apple.com/), accédez à la page **App Information** dans la section **General**, puis trouvez l'**Apple ID** en bas à gauche de l'écran). <img src="/assets/shared/img/43a5cc6-apple_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3.2. Collez l'**Apple ID** copié dans le champ **iOS App ID** de l'Adapty Dashboard. <img src="/assets/shared/img/61bff5a-appsflyer_iOS_app_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning Si vous utilisez AppsFlyer API 2, vous devez passer à l'API 3, car la version précédente sera bientôt dépréciée par AppsFlyer. Pour ce faire, dans la liste **AppsFlyer S2S API**, sélectionnez **API 3**. ::: 5. Pour iOS et Android, ouvrez le [site AppsFlyer](https://www.appsflyer.com/home) et connectez-vous. 6. Cliquez sur **Your account name** -> **Security Center** dans le coin supérieur droit du tableau de bord. <img src="/assets/shared/img/1c18c50-appsflyer_security_center.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Dans la fenêtre **Manage your account security**, cliquez sur le bouton **Manage your AppsFlyer API and S2S tokens**. 8. Si vous disposez déjà d'un token S2S, passez directement à l'étape 12. Sinon, cliquez sur le bouton **New token**. <img src="/assets/shared/img/7934920-appsflyer_new_token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Dans la fenêtre **New token**, saisissez le nom du token. Ce nom est uniquement pour votre référence. 10. Choisissez **S2S** dans la liste **Choose type**. 11. Cliquez sur le bouton **Create new token** pour enregistrer le nouveau token. 12. Dans la fenêtre **Tokens**, copiez le token S2S. 13. Dans l'Adapty Dashboard, collez la clé S2S copiée dans les champs **Dev key for iOS** et **Dev key for Android**. <img src="/assets/shared/img/a7d1c31-appsflyer_dev_keys.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 14. Cliquez sur le bouton **Save** pour enregistrer les modifications. :::info AppsFlyer ne dispose pas de mode Sandbox pour l'intégration server-to-server. Vous devez donc utiliser une application/un compte différent dans AppsFlyer pour la Dev Key Sandbox. Si vous souhaitez envoyer des événements sandbox à la même app, utilisez simplement la même clé pour la production et le sandbox. ::: Adapty mappe certains événements sur les [événements standard](https://support.appsflyer.com/hc/en-us/articles/115005544169-Rich-in-app-events-for-Android-and-iOS#event-types) d'AppsFlyer par défaut. Avec cette configuration, AppsFlyer peut ensuite transmettre les événements à chaque réseau publicitaire que vous utilisez sans configuration supplémentaire. À noter également qu'AppsFlyer ne prend pas en charge les événements de plus de 26 heures. Ainsi, si un événement date de plus de 26 heures, Adapty l'enverra quand même à AppsFlyer, mais la date et l'heure de l'événement seront remplacées par l'horodatage actuel. ### Configurer les événements et les tags \{#configure-events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à AppsFlyer depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/1b0c777-CleanShot_2023-08-11_at_14.56.362x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty, mais vous pouvez les modifier selon vos besoins. Adapty enverra les événements d'abonnement à AppsFlyer via une intégration server-to-server, vous permettant de voir tous les événements d'abonnement dans votre tableau de bord AppsFlyer et de les associer à vos campagnes d'acquisition. ### Connecter votre app à AppsFlyer \{#connect-your-app-to-appsflyer\} Une fois les étapes ci-dessus effectuées, appelez la méthode `updateAttribution` pour enregistrer les données d'attribution, et utilisez `Adapty.setIntegrationIdentifier()` pour définir l'identifiant d'intégration. Initialisez le SDK AppsFlyer et attendez le callback de son UID avant d'identifier les utilisateurs dans Adapty. Sinon, l'`appsflyer_id` atterrit sur un profil Adapty anonyme temporaire créé lors de l'activation et n'est pas toujours transféré vers le profil identifié. Dans ce cas, le transfert des revenus AppsFlyer échoue silencieusement. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers class YourAppsFlyerLibDelegateImplementation { // Find your implementation of AppsFlyerLibDelegate // and update onConversionDataSuccess method: func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) { let uid = AppsFlyerLib.shared().getAppsFlyerUID() // Adapty SDK 4.x Adapty.setIntegrationIdentifier(.appsflyerId(uid)) Adapty.updateAttribution(conversionInfo, source: .appsflyer) // Adapty SDK 3.x Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) Adapty.updateAttribution(conversionInfo, source: "appsflyer") } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers val conversionListener: AppsFlyerConversionListener = object : AppsFlyerConversionListener { override fun onConversionDataSuccess(conversionData: Map<String, Any>) { val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(context) Adapty.setIntegrationIdentifier("appsflyer_id", uid) { error -> if (error != null) { // handle the error } } Adapty.updateAttribution(conversionData, "appsflyer") { error -> if (error != null) { //handle the error } } } } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers appsFlyer.onInstallConversionData(installData => { appsFlyer.getAppsFlyerUID((error, networkUserId) => { if (error) { // handle the error } try { adapty.updateAttribution(installData, AttributionSource.AppsFlyer, networkUserId); } catch (error) { // handle the error } }); }); // ... appsFlyer.initSdk(/*...*/); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers AppsflyerSdk appsflyerSdk = AppsflyerSdk(<YOUR_OPTIONS>); appsflyerSdk.onInstallConversionData((data) async { try { final appsFlyerUID = await appsFlyerSdk.getAppsFlyerUID(); await Adapty().setIntegrationIdentifier( key: "appsflyer_id", value: appsFlyerUID, ); await Adapty().updateAttribution(data, source: "appsflyer"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } }); appsflyerSdk.initSdk( registerConversionDataCallback: true, registerOnAppOpenAttributionCallback: true, registerOnDeepLinkingCallback: true, ); ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; using AppsFlyerSDK; // before SDK initialization AppsFlyer.getConversionData(this.name); // in your IAppsFlyerConversionData void onConversionDataSuccess(string conversionData) { string appsFlyerId = AppsFlyer.getAppsFlyerId(); Adapty.SetIntegrationIdentifier( "appsflyer_id", appsFlyerId, (error) => { // handle the error }); Adapty.UpdateAttribution( conversionData, "appsflyer", (error) => { // handle the error }); } ``` </TabItem> </Tabs> ## Structure des événements \{#event-structure\} Adapty envoie les événements sélectionnés à AppsFlyer via une requête POST avec un corps JSON vers : - API v2 : `https://api2.appsflyer.com/inappevent/{app_id}` - API v3 : `https://api3.appsflyer.com/inappevent/{app_id}` (recommandé) Chaque événement est structuré comme suit : ```json { "appsflyer_id": "1699887556000-6192770", "eventName": "subscription_renewed", "eventTime": "2024-03-01 12:00:00", "eventValue": "{\"af_content_id\":\"yearly.premium.6999\",\"af_order_id\":\"GPA.3383-4699-1373-07113\",\"store_country\":\"US\",\"profile_country\":\"US\",\"af_content_type\":\"in_app\",\"af_revenue\":\"9.9900\",\"af_currency\":\"USD\",\"af_quantity\":\"1\"}", "os": "17.0.1", "bundleIdentifier": "com.example.app", "customer_user_id": "user_12345", "eventCurrency": "USD", "ip": "192.168.100.1", "advertising_id": "00000000-0000-0000-0000-000000000000", "idfa": "00000000-0000-0000-0000-000000000000", "idfv": "00000000-0000-0000-0000-000000000000", "att": "3" } ``` Où : | Paramètre | Type | Description | |:-------------------|:-------|:-----------------------------------------------------------------------------------------------| | `appsflyer_id` | String | L'identifiant AppsFlyer (collecté via le SDK). | | `eventName` | String | Le nom de l'événement AppsFlyer (mappé depuis l'événement Adapty). | | `eventTime` | String | Date et heure de l'événement (UTC, format `YYYY-MM-DD HH:MM:SS`). | | `eventValue` | String | Chaîne JSON contenant les détails de l'événement (voir ci-dessous). | | `os` | String | Version du système d'exploitation. | | `bundleIdentifier` | String | L'identifiant bundle / nom de package de l'application. | | `customer_user_id` | String | L'identifiant utilisateur client (Customer User ID). | | `eventCurrency` | String | Code de devise (ex. : "USD"). | | `ip` | String | Adresse IP de l'utilisateur. | | `advertising_id` | String | **Android uniquement**. Google Advertising ID. | | `idfa` | String | **iOS uniquement**. ID for Advertisers. | | `idfv` | String | **iOS uniquement**. ID for Vendors. | | `att` | String | **iOS uniquement**. Statut App Tracking Transparency (ex. : "3" pour autorisé). | Le paramètre `eventValue` est une chaîne encodée en JSON contenant les champs suivants : | Paramètre | Type | Description | |:------------------|:-------|:--------------------------------------------------------------| | `af_content_id` | String | L'identifiant du produit dans le store. | | `af_order_id` | String | L'identifiant de transaction d'origine. | | `store_country` | String | Code pays de l'utilisateur dans le store. | | `profile_country` | String | Code pays basé sur l'IP de l'utilisateur. | | `af_content_type` | String | Toujours `in_app` si un revenu est présent. | | `af_revenue` | String | Montant du revenu formaté à 4 décimales. | | `af_currency` | String | Code de devise. | | `af_quantity` | String | Toujours `1` si un revenu est présent. | ## Dépannage \{#troubleshooting\} ### Écart de revenus \{#revenue-discrepancy\} Si vous constatez un écart de revenus entre Adapty et AppsFlyer, cela peut être dû au fait que certains de vos utilisateurs n'utilisent pas la version de l'app qui intègre le SDK Adapty. Pour garantir la cohérence des données, vous pouvez forcer vos utilisateurs à mettre à jour l'app vers une version incluant le SDK Adapty. ### Données d'intégration manquantes \{#missing-integration-data\} Si l'envoi d'événements échoue, c'est généralement en raison de données d'intégration manquantes. Vérifiez les points suivants pour résoudre ce problème : - Le SDK AppsFlyer est installé dans votre app. - Vous appelez bien la méthode `getAppsFlyerUID`. ### Échec d'authentification \{#authentication-failure\} Si vous obtenez l'erreur `Failed to authenticate` dans la console, cela peut être dû à une incompatibilité entre la version d'AppsFlyer et la version des identifiants. Consultez le [guide de migration](switch-from-appsflyer-s2s-api-2-to-3) ou remplacez les identifiants par des identifiants valides depuis [cette page](https://hq1.appsflyer.com/security-center/api-tokens). --- # File: switch-from-appsflyer-s2s-api-2-to-3 --- --- title: "Passer de l'API S2S AppsFlyer 2 à 3" description: "Passez de l'API S2S AppsFlyer 2 à 3 dans Adapty." --- Selon les [nouveautés officielles d'AppsFlyer](https://support.appsflyer.com/hc/en-us/articles/20509378973457-Bulletin-Upgrading-the-AppsFlyer-S2S-API), afin d'offrir une expérience plus sécurisée pour l'utilisation de l'API et de réduire la fraude, AppsFlyer a mis à niveau son API serveur à serveur (S2S) pour les événements in-app. L'endpoint existant sera déprécié à l'avenir et nous vous recommandons de commencer à planifier la transition. Adapty prend en charge l'API S2S AppsFlyer 3 et vous permet de passer de l'API 2 en toute simplicité. Notez que cette transition est à sens unique : vous ne pourrez pas revenir à l'API 2 une fois le changement effectué. Pour passer de l'API S2S AppsFlyer 2 à 3 : 1. Ouvrez le [site AppsFlyer](https://www.appsflyer.com/home) et connectez-vous. 2. Cliquez sur **Your account name** -> **Security Center** dans le coin supérieur gauche du tableau de bord. <img src="/assets/shared/img/be299ea-appsflyer_security_center.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Manage your account security**, cliquez sur le bouton **Manage your AppsFlyer API and S2S tokens**. 4. Si vous n'avez pas de token S2S, cliquez sur le bouton **New token**. Si vous en avez déjà un, passez directement à l'étape 8. <img src="/assets/shared/img/7934920-appsflyer_new_token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Dans la fenêtre **New token**, saisissez le nom du token. Ce nom est uniquement à titre de référence. 6. Choisissez **S2S** dans la liste **Choose type**. 7. N'oubliez pas de cliquer sur le bouton **Create new token** pour enregistrer le nouveau token. 8. Dans la fenêtre **Tokens**, copiez le token S2S. <img src="/assets/shared/img/d014c25-appsflyer_tokens.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Ouvrez [**Integrations** -> **AppsFlyer**](https://app.adapty.io/integrations/appsflyer) dans l'Adapty Dashboard. 10. Dans le champ **AppsFlyer S2S API**, sélectionnez **API 3**. <img src="/assets/shared/img/c0b3e72-appsflyer_switch_API.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 11. Collez la clé S2S copiée dans les champs **Dev key for iOS** et **Dev key for Android**. 12. Cliquez sur le bouton **Save** pour confirmer le changement. À ce moment-là, votre intégration bascule instantanément vers l'API S2S AppsFlyer 3 et vos nouveaux événements seront envoyés à la nouvelle URL : `https://api3.appsflyer.com/inappevent`. --- # File: asapty --- --- title: "Asapty" description: "Découvrez Asapty et son rôle dans l'écosystème d'abonnement d'Adapty." --- L'intégration [Asapty](https://asapty.com/) vous permet d'optimiser vos campagnes Search Ads. Adapty envoie les événements d'abonnement à Asapty, ce qui vous permet d'y créer des tableaux de bord personnalisés basés sur l'attribution Apple Search Ads. Cette intégration spécifique n'ajoute pas de données d'attribution à Adapty, car nous disposons déjà de tout ce dont nous avons besoin directement via [ASA](apple-search-ads). ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Asapty \{#connect-adapty-to-asapty\} Pour intégrer Asapty, accédez à [Integrations > Asapty](https://app.adapty.io/integrations/asapty) dans l'Adapty Dashboard et renseignez la valeur du champ Asapty ID. <img src="/assets/shared/img/895de2b-CleanShot_2023-08-14_at_18.57.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> L'Asapty ID se trouve dans la section Settings > General de votre compte Asapty. ### Configurer les événements et les tags \{#configure-events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à Asapty depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/58ddf41-CleanShot_2023-08-15_at_15.11.072x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Asapty. Vous pouvez toutefois les modifier selon vos besoins. ### Connecter votre application à Asapty \{#connect-your-app-to-asapty\} Une fois les étapes ci-dessus effectuées, Adapty reçoit automatiquement les données d'attribution d'Asapty. Il n'est pas nécessaire de demander explicitement ces données dans le code de votre application. Pour une meilleure précision des données d'attribution, configurez Asapty pour qu'il transmette le `customerUserId` avec les données de chaque événement. ## Structure des événements Asapty \{#asapty-event-structure\} Adapty envoie les événements à Asapty via une requête GET utilisant des paramètres de requête. Chaque URL d'événement ressemble à ceci : ``` https://asapty.com/_api/mmpEvents/?source=adapty&asaptyid=a1b2c3d4&keywordid=12345&adgroupid=67890&campaignid=11223&conversiondate=1709294400000&event_name=subscription_renewed&install_time=1709100000&app_name=MyApp&json=%7B%22af_revenue%22%3A%229.99%22%2C%22af_currency%22%3A%22USD%22...%7D ``` Paramètres de requête : | Paramètre | Type | Description | |:-----------------|:-------|:-----------------------------------------------------| | `source` | String | Toujours "adapty". | | `asaptyid` | String | L'Asapty ID issu de vos identifiants. | | `keywordid` | String | ID du mot-clé Apple Search Ads (si disponible). | | `adgroupid` | String | ID du groupe d'annonces Apple Search Ads (si disponible). | | `campaignid` | String | ID de la campagne Apple Search Ads (si disponible). | | `conversiondate` | Long | Horodatage de l'événement en **millisecondes**. | | `event_name` | String | Le nom de l'événement (mappé depuis l'événement Adapty). | | `install_time` | Long | Horodatage de l'installation en secondes. | | `app_name` | String | Le titre de l'application dans Adapty (si disponible). | | `json` | String | Chaîne JSON encodée en URL contenant les détails de l'événement (voir ci-dessous). | Le paramètre `json` est une chaîne JSON encodée en URL contenant les champs suivants : | Paramètre | Type | Description | |:--------------------------|:-------|:---------------------------------------------| | `af_revenue` | String | Montant des revenus sous forme de chaîne. | | `af_currency` | String | Code de devise (ex. : "USD"). | | `transaction_id` | String | ID de transaction du store. | | `original_transaction_id` | String | ID de transaction d'origine du store. | | `purchase_date` | Long | Horodatage de l'achat en millisecondes. | | `original_purchase_date` | Long | Horodatage de l'achat d'origine en millisecondes. | | `environment` | String | `Production` ou `Sandbox`. | | `vendor_product_id` | String | L'ID du produit dans le store. | | `profile_country` | String | Code pays basé sur l'adresse IP de l'utilisateur. | | `store_country` | String | Code pays du store de l'utilisateur. | ## Résolution des problèmes \{#troubleshooting\} - Assurez-vous d'avoir configuré [Apple Search Ads](apple-search-ads) dans Adapty et d'avoir [téléversé vos identifiants](https://app.adapty.io/settings/apple-search-ads) — sans cela, Asapty ne fonctionnera pas. - Seuls les profils avec une attribution ASA détaillée et non organique transmettront leurs événements à Asapty. Vous verrez le message « The user profile is missing the required integration data. » si l'attribution est insuffisante. - Les profils créés avant la configuration des intégrations ne pourront pas transmettre leurs événements à Asapty. - Si l'intégration avec Adapty ne fonctionne pas malgré une configuration correcte, vérifiez que le bouton **Receive Apple Search Ads attribution in Adapty** est activé dans l'onglet [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads). --- # File: branch --- --- title: "Branch" description: "Intégrez Branch avec Adapty pour suivre les deep links et les conversions d'applications." --- [Branch](https://www.branch.io/) permet aux entreprises d'atteindre leurs utilisateurs, d'interagir avec eux et d'évaluer les résultats sur différents appareils, canaux et plateformes. C'est une plateforme facile à utiliser, conçue pour augmenter les revenus mobiles grâce à des liens spécialisés qui fonctionnent parfaitement sur tous les appareils, canaux et plateformes. Adapty fournit un ensemble complet de données qui vous permet de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et utiliser ces informations pour communiquer avec eux de manière ciblée et efficace. L'intégration entre Adapty et Branch fonctionne de deux manières principales. 1. **Réception des données d'attribution depuis Branch** Une fois l'intégration Branch configurée, Adapty commencera à recevoir des données d'attribution de Branch. Vous pouvez accéder à ces données et les consulter facilement sur la page du profil utilisateur. <img src="/assets/shared/img/49f4aa7-CleanShot_2023-08-11_at_17.36.072x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Envoi des événements d'abonnement à Branch** Adapty peut envoyer tous les événements d'abonnement configurés dans votre intégration à Branch. Vous pourrez ainsi suivre ces événements dans le tableau de bord Branch et les associer à vos campagnes d'acquisition. ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Branch \{#connect-adapty-to-branch\} Pour intégrer Branch, rendez-vous dans [Integrations > Branch](https://app.adapty.io/integrations/branch) dans l'Adapty Dashboard, activez le bouton et renseignez les champs. <img src="/assets/shared/img/817a051-CleanShot_2023-08-11_at_15.54.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour obtenir la valeur du **Branch Key**, ouvrez vos [Account Settings](https://dashboard.branch.io/account-settings/profile) Branch et trouvez le champ **Branch Key**. Utilisez-le pour le champ **Key test** (pour Sandbox) ou **Key live** (pour Production) dans l'Adapty Dashboard. Dans Branch, basculez entre les environnements Live et Tests pour récupérer la clé appropriée. <img src="/assets/shared/img/130e58b-CleanShot_2023-08-11_at_15.24.162x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Configurer les événements et les tags \{#configure-events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à Branch depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). Vous pouvez envoyer un événement avec les Proceeds \(après la commission Apple/Google\) ou uniquement le chiffre d'affaires. Vous pouvez également cocher une case pour les rapports dans la devise de l'utilisateur. <img src="/assets/shared/img/a645cf8-CleanShot_2023-08-11_at_15.18.282x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty. Vous pouvez toutefois les personnaliser selon vos besoins. Adapty enverra les événements d'abonnement à Branch via une intégration serveur à serveur, ce qui vous permettra de consulter tous les événements d'abonnement dans votre tableau de bord Branch et de les associer à vos campagnes d'acquisition. ### Connecter votre application à Branch \{#connect-your-app-to-branch\} 1. Appelez la méthode SDK `.setIntegrationIdentifier()` pour initialiser la connexion. Vous pouvez passer votre Branch Identity ID au paramètre `customerUserId`. :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.branchId(<BRANCH_IDENTITY_ID>)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "branch_id", value: <BRANCH_IDENTITY_ID> ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // login and update attribution and identifier Branch.getAutoInstance(this) .setIdentity("YOUR_USER_ID") { referringParams, error -> referringParams?.let { data -> Adapty.updateAttribution(data, "branch") { error -> if (error != null) { //handle the error } } } } // logout Branch.getAutoInstance(context).logout() ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers import 'package:flutter_branch_sdk/flutter_branch_sdk.dart'; FlutterBranchSdk.setIdentity('YOUR_USER_ID'); ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers Branch.setIdentity("your user id"); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers import branch from 'react-native-branch'; branch.setIdentity('YOUR_USER_ID'); ``` </TabItem> </Tabs> 2. Utilisez la méthode `.updateAttribution()` pour enregistrer les données d'attribution. Si vous n'avez pas renseigné l'identifiant utilisateur Branch à l'étape précédente, passez-le au paramètre `networkUserId` ici. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers class YourBranchImplementation { func initializeBranch() { // Pass the attribution you receive from the initializing method of Branch iOS SDK to Adapty. Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in if let data { // Adapty SDK 4.x Adapty.updateAttribution(data, source: .branch) // Adapty SDK 3.x Adapty.updateAttribution(data, source: "branch") } } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers //everything is in the above snippet for Android ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers try { await Adapty().setIntegrationIdentifier( key: "branch_id", value: <BRANCH_IDENTITY_ID>, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; Branch.initSession(delegate(Dictionary<string, object> parameters, string error) { string attributionString = JsonUtility.ToJson(parameters); Adapty.UpdateAttribution( attributionString, "branch", (error) => { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import branch from 'react-native-branch'; branch.subscribe({ enComplete: ({ params, }) => { adapty.updateAttribution(params, "branch"); }, }); ``` </TabItem> </Tabs> ## Structure des événements \{#event-structure\} Adapty envoie les événements sélectionnés à Branch tels que configurés dans la section **Events names** de la [**page d'intégration Branch**](https://app.adapty.io/integrations/branch). Chaque événement est structuré comme suit : ```json { "branch_key": "key_live_kaFuWw8WvY7n1ss7...", "name": "PURCHASE", "user_data": { "os": "iOS", "developer_identity": "user_12345", "country": "US", "ip": "192.168.100.1", "idfa": "00000000-0000-0000-0000-000000000000", "idfv": "00000000-0000-0000-0000-000000000000", "aaid": "00000000-0000-0000-0000-000000000000" }, "event_data": { "transaction_id": "GPA.3383-4699-1373-07113", "revenue": 9.99, "currency": "USD" }, "custom_data": { "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383-4699-1373-07113", "store": "play_store", "environment": "production" } } ``` Où : | Paramètre | Type | Description | |:-------------------------------|:-------|:-------------------------------------------------------------------------------------------------------------------------------| | `branch_key` | String | Votre Branch Key. | | `name` | String | Le nom de l'événement Branch (mappé depuis l'événement Adapty, par ex. "PURCHASE"). | | `user_data` | Object | Informations sur l'utilisateur. | | `user_data.os` | String | "Android" ou "iOS". | | `user_data.developer_identity` | String | Le Customer User ID de l'utilisateur. | | `user_data.country` | String | Code pays basé sur l'adresse IP de l'utilisateur. | | `user_data.ip` | String | Adresse IP de l'utilisateur. | | `user_data.idfa` | String | **iOS uniquement**. ID for Advertisers. | | `user_data.idfv` | String | **iOS uniquement**. ID for Vendors. | | `user_data.aaid` | String | **Android uniquement**. Google Advertising ID. | | `event_data` | Object | Métriques standard de l'événement (présentes uniquement pour PURCHASE et les événements similaires). | | `event_data.transaction_id` | String | ID de transaction du store. | | `event_data.revenue` | Float | Montant du chiffre d'affaires. | | `event_data.currency` | String | Code devise (par ex. "USD"). | | `custom_data` | Object | Attributs détaillés de l'événement (contient tous les [champs d'événement](webhook-event-types-and-fields#for-most-event-types) disponibles). | --- # File: facebook-ads --- --- title: "Facebook Ads" description: "Intégrez Facebook Ads avec Adapty pour un marketing d'abonnement efficace." --- Grâce à l'intégration Facebook Ads, vous pouvez facilement consulter les statistiques de votre application dans Meta Analytics. Adapty envoie des événements à Meta Ads Manager, ce qui vous permet de créer des audiences similaires basées sur les abonnements pour de meilleurs retours. Vous pouvez ainsi voir précisément combien d'argent vos publicités génèrent grâce aux abonnements. L'intégration entre Adapty et Facebook Ads fonctionne de la façon suivante : Adapty envoie tous les événements d'abonnement configurés dans votre intégration à Facebook Ads. Cette intégration est utile pour évaluer l'efficacité de vos campagnes publicitaires. ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Facebook Ads \{#connect-adapty-to-facebook-ads\} Pour intégrer Facebook Ads et analyser les métriques de votre application, vous pouvez configurer l'intégration avec Meta Analytics. En envoyant des événements à Meta Ads Manager, vous pouvez créer des audiences similaires basées sur des événements d'abonnement comme les renouvellements. Pour configurer cette intégration, rendez-vous dans [Integrations > Facebook Ads](https://app.adapty.io/integrations/facebookanalytics) dans l'Adapty Dashboard et renseignez les identifiants requis. :::note Veuillez noter que l'intégration Facebook Ads fonctionne uniquement sur iOS 14.5+ pour les utilisateurs ayant donné leur consentement ATT. ::: <img src="/assets/shared/img/fd84ddf-CleanShot_2023-08-15_at_15.45.442x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. Pour trouver l'App ID, ouvrez la page de votre application dans [App Store Connect](https://appstoreconnect.apple.com/), accédez à la page **App Information** dans la section **General**, et repérez **Apple ID** en bas à gauche de l'écran. 2. Vous avez besoin d'une application sur la plateforme [Meta for Developers](https://developers.facebook.com/). Connectez-vous à votre application, puis accédez aux paramètres avancés. Vous trouverez l'**App ID** dans l'en-tête. <img src="/assets/shared/img/4b326c4-001563-August-23-4tO3JVso.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Désactivez le suivi côté client dans la configuration de votre SDK Meta pour éviter le double comptage des revenus dans Meta Ads Manager. Vous trouverez ce paramètre dans votre Meta Developer Console sous **App Settings > Advanced Settings**. Réglez **Log in-app events automatically** sur « No ». Cela garantit que les événements de revenus ne sont suivis que via l'intégration Adapty. Pour suivre les événements d'installation et d'utilisation, vous devrez activer le SDK Meta dans votre code. Vous trouverez les détails d'implémentation dans la documentation du SDK Meta pour votre plateforme : - [iOS SDK](https://developers.facebook.com/docs/ios/getting-started) - [Android SDK](https://developers.facebook.com/docs/android/getting-started) - [Unity SDK](https://developers.facebook.com/docs/unity/getting-started/canvas) <img src="/assets/shared/img/c4eb8eb-001565-August-23-483KKBbC.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez également utiliser cette intégration avec des applications Android. Si vous configurez le SDK Android dans **App Settings**, il suffit de renseigner le **Facebook App ID**. ### Configurer les événements et les tags \{#configure-events-and-tags\} Notez que l'intégration Facebook Ads s'adresse spécifiquement aux entreprises utilisant Meta pour leurs campagnes publicitaires et souhaitant les optimiser en fonction du comportement des utilisateurs. Elle prend en charge les événements standard de Meta à des fins d'optimisation. Par conséquent, la modification du nom des événements n'est pas disponible pour l'intégration Meta Ads. Adapty mappe efficacement vos événements utilisateur vers les événements Meta correspondants pour une analyse précise. | Événement Adapty | Événement Meta Ads | | :---------------------------- | :-------------------------- | | Subscription initial purchase | Subscribe | | Subscription renewed | Subscribe | | Subscription cancelled | CancelSubscription | | Trial started | StartTrial | | Trial converted | Subscribe | | Trial cancelled | CancelTrial | | Non subscription purchase | fb_mobile_purchase | | Billing issue detected | billing_issue_detected | | Entered grace period | entered_grace_period | | Auto renew off | auto_renew_off | | Auto renew on | auto_renew_on | | Auto renew off subscription | auto_renew_off_subscription | | Auto renew on subscription | auto_renew_on_subscription | StartTrial, Subscribe et CancelSubscription sont des événements standard. <img src="/assets/shared/img/8a5df9d-CleanShot_2023-07-04_at_12.47.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour activer des événements spécifiques, activez simplement ceux dont vous avez besoin. Si plusieurs noms d'événements sont sélectionnés, Adapty regroupera les données de tous les événements choisis sous un seul nom d'événement Adapty. ### Connecter votre application à Facebook Ads \{#connect-your-app-to-facebook-ads\} Si vous suivez les étapes ci-dessus, Facebook recevra automatiquement les données d'abonnement depuis Adapty. Suite aux changements apportés à l'IDFA dans iOS 14.5, nous vous recommandons de demander le `facebookAnonymousId` de l'utilisateur auprès de Facebook. Ainsi, si l'IDFA de l'utilisateur est indisponible, l'intégration continuera de fonctionner. Suivez le <InlineTooltip tooltip="guide de définition des attributs utilisateur">[iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes) et [Unity](unity-setting-user-attributes)</InlineTooltip> pour définir ce paramètre. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "facebook_anonymous_id", value: AppEvents.shared.anonymousID ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier( "facebook_anonymous_id", AppEventsLogger.getAnonymousAppDeviceGUID(context) ) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers try { const anonymousId = await AppEventsLogger.getAnonymousID(); await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```text There is no official SDK for Flutter ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp anonymousID is not available in the official SDK https://github.com/facebook/facebook-sdk-for-unity/issues/676 ``` </TabItem> </Tabs> ## Structure des événements \{#event-structure\} Adapty envoie les événements à Facebook Ads (Meta) via l'API Graph. Chaque événement est structuré comme suit : ```json { "event": "CUSTOM_APP_EVENTS", "app_user_id": "user_12345", "advertiser_id": "00000000-0000-0000-0000-000000000000", "advertiser_tracking_enabled": 1, "application_tracking_enabled": 1, "custom_events": "[{\"_eventName\":\"Subscribe\",\"_logTime\":1709294400,\"fb_num_items\":1,\"fb_content_type\":\"in_app\",\"fb_content_id\":\"yearly.premium.6999\",\"fb_currency\":\"USD\",\"fb_order_id\":\"GPA.3383...\",\"fb_transaction_id\":\"GPA.3383...\",\"_valueToSum\":9.99}]", "extinfo": "[\"i2\",\"com.example.app\",\"1.0.0\",\"100\",\"17.0.1\",\"iPhone14,3\",\"en_US\",\"GMT+3\",\"\",0,0,0,0,0,0,\"GMT+3\"]", "anon_id": "facebook_anon_id_123" } ``` Où : | Paramètre | Type | Description | |:---|:---|:---| | `event` | String | Toujours « CUSTOM_APP_EVENTS ». | | `app_user_id` | String | L'identifiant utilisateur client de l'utilisateur. | | `advertiser_id` | String | IDFA (iOS) ou Advertising ID (Android). | | `advertiser_tracking_enabled` | Integer | `1` si le suivi est activé (ATT autorisé), `0` sinon. | | `application_tracking_enabled` | Integer | Toujours `1`. | | `custom_events` | String | Chaîne JSON encodée contenant des objets d'événements (voir ci-dessous). | | `extinfo` | String | Chaîne JSON encodée contenant les informations sur l'application et l'appareil (ex. : version, OS, langue). | | `anon_id` | String | ID anonyme Facebook (si disponible). | Le paramètre `custom_events` est un tableau JSON encodé d'objets contenant : | Paramètre | Type | Description | |:---|:---|:---| | `_eventName` | String | Le nom de l'événement Meta Ads (ex. : « Subscribe »). | | `_logTime` | Long | Horodatage de l'événement en secondes. | | `_valueToSum` | Float | Montant des revenus. | | `fb_content_id` | String | L'identifiant du produit dans le store. | | `fb_currency` | String | Code de devise (ex. : « USD »). | | `fb_order_id` | String | Identifiant de transaction d'origine. | | `fb_transaction_id` | String | Identifiant de transaction d'origine. | | `fb_content_type` | String | Toujours « in_app ». | | `fb_num_items` | Integer | Toujours 1 pour les événements d'achat. | --- # File: singular --- --- title: "Singular" description: "Intégrez Singular avec Adapty pour analyser vos données marketing et d'abonnement." --- [Singular](https://www.singular.net/) est l'une des principales plateformes MMP (Mobile Measurement Partner), qui collecte et présente les données issues des campagnes marketing. Elle permet aux entreprises de suivre les performances de leurs campagnes. Adapty fournit un ensemble complet de données qui vous permet de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit. Avec Adapty, vous visualisez facilement le comportement de vos abonnés, comprenez leurs préférences et utilisez ces informations pour communiquer avec eux de manière ciblée et efficace. Cette intégration vous permet donc de suivre les événements d'abonnement dans Singular et d'analyser précisément les revenus générés par vos campagnes. Adapty peut envoyer à Singular tous les événements d'abonnement configurés dans votre intégration. Vous pourrez ainsi suivre ces événements dans le tableau de bord Singular et évaluer précisément l'efficacité de vos campagnes publicitaires. ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Singular \{#connect-adapty-to-singular\} Pour configurer l'intégration avec Singular, rendez-vous dans [Integrations > Singular](https://app.adapty.io/integrations/singular) sur votre Adapty Dashboard, activez le bouton et renseignez les champs. Les identifiants suivants sont disponibles : - **Singular SDK Key** : Obligatoire. La clé SDK de production pour votre application Singular. - **Singular SDK Key (Sandbox)** : Facultatif. La clé SDK pour votre application Singular en sandbox. Si elle n'est pas renseignée, les événements sandbox ne seront pas envoyés à Singular. Ces deux clés se trouvent dans le tableau de bord Singular sous **Developer tools -> SDK Keys -> SDK Key (** pas le **SDK Secret)** : <img src="/assets/shared/img/4bc50d1-singular_sdk_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Sous les identifiants, trois groupes d'événements peuvent être envoyés à Singular depuis Adapty. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/e67de0c-singular_events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty. Vous pouvez toutefois les modifier selon vos besoins. Adapty enverra les événements d'abonnement à Singular via une intégration serveur à serveur, vous permettant de visualiser tous les événements d'abonnement dans votre tableau de bord Singular et de les associer à vos campagnes d'acquisition. :::warning Les profils créés avant la configuration des intégrations ne pourront pas envoyer leurs événements à Singular. ::: ### Connecter votre application à Singular \{#connect-your-app-to-singular\} L'intégration entre Adapty et Singular est de type serveur à serveur. Il n'est donc pas nécessaire d'ajouter de code supplémentaire à votre application. ## Structure des événements \{#event-structure\} Adapty envoie les événements à Singular via une requête GET avec des paramètres de requête. Chaque événement est structuré comme suit : ```json { "n": "subscription_renewed", "a": "singular_sdk_key_123", "p": "iOS", "i": "com.example.app", "ip": "192.168.100.1", "idfa": "00000000-0000-0000-0000-000000000000", "idfv": "00000000-0000-0000-0000-000000000000", "ve": "17.0.1", "att_authorization_status": 3, "custom_user_id": "user_12345", "utime": 1709294400, "amt": 9.99, "cur": "USD", "purchase_product_id": "yearly.premium.6999", "purchase_transaction_id": "GPA.3383...", "e": "{\"is_revenue_event\":true,\"amt\":9.99,\"cur\":\"USD\",\"purchase_product_id\":\"yearly.premium.6999\",\"purchase_transaction_id\":\"GPA.3383...\"}" } ``` Où : | Paramètre | Type | Description | |:---------------------------|:--------|:---------------------------------------------------------------| | `n` | String | Le nom de l'événement (mappé depuis l'événement Adapty). | | `a` | String | Votre clé SDK Singular. | | `p` | String | Plateforme (« iOS » ou « Android »). | | `i` | String | ID de l'application dans le store (Bundle ID). | | `ip` | String | Adresse IP de l'utilisateur. | | `idfa` | String | **iOS uniquement**. ID for Advertisers (en majuscules). | | `idfv` | String | **iOS uniquement**. ID for Vendors (en majuscules). | | `aifa` | String | **Android uniquement**. Google Advertising ID (en minuscules). | | `andi` | String | **Android uniquement**. Android ID (en minuscules). | | `asid` | String | **Android uniquement**. App Set ID (en minuscules). | | `ve` | String | Version du système d'exploitation. | | `att_authorization_status` | Integer | **iOS uniquement**. Statut ATT (ex. : `3` pour autorisé). | | `custom_user_id` | String | L'identifiant utilisateur client (Customer User ID). | | `utime` | Long | Horodatage UNIX de l'événement en secondes. | | `amt` | Float | Montant des revenus. | | `cur` | String | Code de devise (ex. : « USD »). | | `purchase_product_id` | String | L'identifiant du produit dans le store. | | `purchase_transaction_id` | String | Identifiant de transaction d'origine. | | `e` | String | Chaîne JSON contenant les détails de l'événement (voir ci-dessous). | Le paramètre `e` (données d'événement personnalisées) est une chaîne encodée en JSON contenant : | Paramètre | Type | Description | |:--------------------------|:--------|:----------------------------------------------------| | `is_revenue_event` | Boolean | `true` si l'événement contient des revenus. | | `amt` | Float | Montant des revenus. | | `cur` | String | Code de devise. | | `purchase_product_id` | String | L'identifiant du produit dans le store. | | `purchase_transaction_id` | String | Identifiant de transaction d'origine. | --- # File: tenjin --- --- title: "Intégration Tenjin" description: "" --- Tenjin est une plateforme d'attribution mobile et d'analytics pour les développeurs d'applications et les équipes marketing. Elle fournit des outils pour mesurer et optimiser les campagnes d'acquisition d'utilisateurs en offrant des informations détaillées sur les performances de l'application et le comportement des utilisateurs. Grâce à son approche transparente et flexible, Tenjin agrège les données des réseaux publicitaires et des stores d'applications, permettant aux équipes d'analyser le ROI, de suivre les conversions et de surveiller les métriques clés. En transmettant les [événements d'abonnement](events) à Tenjin, vous pouvez voir exactement d'où viennent les conversions et quelles campagnes génèrent le plus de valeur sur tous les canaux, plateformes et appareils. En pratique, les tableaux de bord Tenjin offrent des analytics avancées pour les campagnes marketing. En transmettant l'attribution de Tenjin à Adapty, vous enrichissez les analytics Adapty avec des critères de filtrage supplémentaires utilisables dans les analyses de cohortes et de conversions. Cette intégration fonctionne de deux manières principales : 1. **Réception des données d'attribution depuis Tenjin** Une fois intégrée, Adapty collecte les données d'attribution de Tenjin. Vous pouvez accéder à ces informations sur la page du profil de l'utilisateur dans l'Adapty Dashboard. 2. **Envoi des événements d'abonnement à Tenjin** Adapty envoie les événements d'achat à Tenjin en temps réel. Ces événements permettent d'évaluer l'efficacité de vos campagnes publicitaires directement dans le tableau de bord de Tenjin. | Caractéristique de l'intégration | Description | | -------------------------------- | ------------------------------------------------------------ | | Fréquence | Temps réel | | Direction des données | <p>Transmission bidirectionnelle :</p><ul><li> **Événements Adapty** : du serveur Adapty vers le serveur Tenjin</li><li> **Attribution Tenjin** : du SDK Tenjin vers le serveur Adapty</li></ul> | | Point d'intégration Adapty | <ul><li> SDK Tenjin et Adapty dans le code de l'application mobile</li><li> Serveur Adapty</li></ul> | ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty à Tenjin \{#connect-adapty-to-tenjin\} 1. Ouvrez la page [**Integrations** -> **Tenjin**](https://app.adapty.io/integrations/tenjin) dans l'Adapty Dashboard. 2. Activez le bouton pour activer l'intégration. <img src="/assets/shared/img/tenjin-toggle.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Connectez-vous au [Tenjin Dashboard](https://tenjin.com/). 4. Allez dans **Configuration** -> **Apps** dans le menu de navigation. <img src="/assets/shared/img/tenjin-apps.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Sélectionnez l'application pour votre plateforme (iOS ou Android) et accédez à l'onglet **App and SDK**. 6. Dans l'onglet **App and SDK**, cliquez sur **Copy** dans la colonne **SDK Key**. Si vous n'avez pas encore de clé SDK, cliquez sur le bouton **Generate SDK Key** pour en créer une. <img src="/assets/shared/img/tenjin-copy-sdk-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Revenez dans l'Adapty Dashboard et collez la clé SDK copiée dans le champ correspondant à votre plateforme : - Pour les applications iOS : collez dans le champ **iOS SDK Key** ou **iOS Sandbox SDK Key** - Pour les applications Android : collez dans le champ **Android SDK Key** ou **Android Sandbox SDK Key** :::info Tenjin ne dispose pas d'un mode Sandbox spécifique pour l'intégration server-to-server. Utilisez une application Tenjin distincte ou la même clé pour les événements de production et sandbox. ::: <img src="/assets/shared/img/tenjin-keys.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. Si vous avez des applications sur les deux plateformes, répétez les étapes 5 à 7 pour l'autre plateforme. 9. (facultatif) Ajustez la section **How the revenue data should be sent** si nécessaire. Pour une explication détaillée de ses paramètres, consultez la section [Paramètres d'intégration](configuration#integration-settings). 10. Cliquez sur **Save** pour finaliser la configuration. Adapty enverra désormais les événements d'achat à Tenjin et recevra les données d'attribution. Vous pouvez ajuster le partage des événements dans la section **Events names**. ### Configurer les événements et les tags \{#configure-events-and-tags\} Tenjin n'accepte que les événements d'achat et les événements **Trial started**. Dans la section **Events names**, sélectionnez les événements à partager avec Tenjin en fonction de vos objectifs de suivi. <img src="/assets/shared/img/tenjin-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Connecter votre application à Tenjin \{#connect-your-app-to-tenjin\} Utilisez la méthode SDK `Adapty.updateAttribution()` pour récupérer les données d'attribution depuis Tenjin et les transmettre à Adapty. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers func updateTenjinId() { guard let tenjinId = TenjinSDK.getAnalyticsInstallationId() else { return } do { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.tenjinAnalyticsInstallationId(tenjinId)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "tenjin_analytics_installation_id", value: tenjinId ) } catch { // handle the error } } func updateTenjinAttribution() { let instance = TenjinSDK.getInstance("<YOUR_TENJIN_API_TOKEN>") instance?.getAttributionInfo { info, _ in guard let info else { return } Task { do { // Adapty SDK 4.x try await Adapty.updateAttribution(info, source: .tenjin) // Adapty SDK 3.x try await Adapty.updateAttribution(info, source: "tenjin") } catch { // handle the error } } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", tenjinSdk.analyticsInstallationId) { error -> if (error != null) { // handle the error } } tenjinSdk.getAttributionInfo { attribution -> if (attribution == null) return@getAttributionInfo Adapty.updateAttribution(attribution, "tenjin") { error -> if (error != null) { // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", tenjinSdk.getAnalyticsInstallationId(), error -> { if (error != null) { // handle the error } }); tenjinSdk.getAttributionInfo(attribution -> { if (attribution == null) return; Adapty.updateAttribution(attribution, "tenjin", error -> { // handle the error }); }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers try { final tenjinId = await TenjinSDK.instance.getAnalyticsInstallationId(); if (tenjinId != null) { await Adapty().setIntegrationIdentifier( key: 'tenjin_analytics_installation_id', value: tenjinId, ); } final attribution = await TenjinSDK.instance.getAttributionInfo(); if (attribution != null) { await Adapty().updateAttribution(attribution, source: 'tenjin'); } } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; using System.Linq; BaseTenjin instance = Tenjin.getInstance("<SDK_KEY>"); var tenjinId = instance.GetAnalyticsInstallationId(); Adapty.SetIntegrationIdentifier( "tenjin_analytics_installation_id", tenjinId, (error) => { // handle the error }); instance.GetAttributionInfo((attribution) => { var dynamicAttribution = attribution.ToDictionary( kvp => kvp.Key, kvp => (dynamic)kvp.Value ); Adapty.UpdateAttribution( dynamicAttribution, "tenjin", (error) => { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... const posthog = usePostHog() // ... try { await adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", await Tenjin.getAnalyticsInstallationId()); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Structure des événements \{#event-structure\} Adapty envoie les événements sélectionnés à Tenjin tels que configurés dans la section **Events names** de la [**page d'intégration Tenjin**](https://app.adapty.io/integrations/tenjin). Chaque événement est structuré comme suit : ```json showLineNumbers title="Json" { "price": 99.0, "locale": "en-US", "country": "ME", "postcut": "false", "currency": "USD", "platform": "ios", "quantity": 1, "bundle_id": "com.adapty.adaptydemoapp", "ip_address": "127.0.0.1", "os_version": "18.1.1", "product_id": "month.premium.99", "app_version": "3.2.0", "sdk_version": "server", "device_model": "iPhone 13 Mini", "advertising_id": "00000000-0000-0000-0000-000000000000", "os_version_release": "18.1.1", "developer_device_id": "00000000-0000-0000-0000-000000000000", "analytics_installation_id": "00000000-0000-0000-0000-000000000000" } ``` Où | **Paramètre** | **Type** | **Description** | | ----------------------------- | ---------------- | ------------------------------------------------------------ | | **price** | Float | Le prix unitaire de l'article acheté dans l'unité standard de la devise (par exemple, USD est exprimé en dollars). | | **locale** | String | La locale de l'appareil. Pour Android : `Locale.getDefault().toString()`. Pour iOS : `[[NSLocale currentLocale] localeIdentifier]`. | | **country** | String | Le code pays ISO de la locale (par exemple, US pour les États-Unis). | | **postcut** | String (Boolean) | Indique si l'achat a été envoyé après la commission de la plateforme. 1 pour vrai, 0 pour faux. | | **currency** | String | Le code de devise ISO (par exemple, USD pour le dollar américain). | | **platform** | String | La plateforme de l'appareil (par exemple, ios, android, windows, amazon). | | **quantity** | Integer | Le nombre d'unités achetées. | | **bundle_id** | String | L'identifiant bundle de l'application (par exemple, `com.example.app`). | | **ip_address** | String (IPv4) | L'adresse IP de l'utilisateur. Utilisée pour déterminer le pays. | | **os_version** | String | La version du système d'exploitation de l'appareil. Pour Android : `String.valueOf(Build.VERSION.SDK_INT)`. Pour iOS : `[[UIDevice currentDevice] systemVersion]`. | | **product_id** | String | Identifiant unique du produit acheté. | | **app_version** | Float, Decimal | La version de l'application. Pour Android : `context.getPackageManager().getPackageInfo()`. Pour iOS : `[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]`. | | **sdk_version** | String | La version du SDK utilisée, toujours définie sur `server`. | | **device_model** | String | Le modèle de l'appareil. Pour Android : `Build.MODEL`. Pour iOS : `sysctl("hw.machine")`. | | **advertising_id** | UUID | L'identifiant publicitaire de l'appareil. Obligatoire pour Android. Pour iOS, il peut être vide ou composé de zéros. | | **os_version_release** | String | La version de publication du système d'exploitation. Pour Android : `String.valueOf(Build.VERSION.RELEASE)`. Pour iOS : `[[UIDevice currentDevice] systemVersion]`. | | **developer_device_id** | UUID | L'identifiant pour le fournisseur (iOS uniquement). | | **analytics_installation_id** | UUID | L'identifiant d'installation analytics. Pour plus de détails, consultez la documentation sur `https://docs.tenjin.com`. | --- # File: analytics-integration --- --- title: "Intégrations analytiques" description: "Intégrez des outils d'analyse avec Adapty pour suivre et optimiser les abonnements utilisateurs." --- Adapty envoie tous les [événements d'abonnement](events) aux services d'analyse, tels qu'[Amplitude](amplitude), [Mixpanel](mixpanel) et [AppMetrica](appmetrica). Vous pouvez également recevoir ces événements sur votre serveur via l'intégration [webhook](webhook). Le mieux dans tout ça, c'est que vous n'avez rien à faire : nous nous chargeons d'envoyer les événements à votre place. Configurez simplement l'intégration dans l'Adapty Dashboard. Adapty prend en charge l'intégration avec les services d'analyse tiers suivants : - [Amplitude](amplitude) - [AppMetrica](appmetrica) - [Firebase and Google Analytics](firebase-and-google-analytics) - [Mixpanel](mixpanel) - [PostHog](posthog) - [SplitMetrics Acquire](splitmetrics) :::note Votre outil d'analyse n'est pas dans la liste ? Faites-le nous savoir ! [Soumettez une demande de fonctionnalité](https://adapty.featurebase.app/en?b=6979f233ebd3cffd4f425ba0) et nous étudierons son ajout. ::: ## Propriétés des événements \{#event-properties\} Les événements webhook sont envoyés au format JSON. Tous les événements suivent la même structure, mais leurs champs varient selon le type d'événement, le store et votre configuration spécifique. :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: | Propriété | Type | Description | | ----------------------------- | ------------- | ------------------------------------------------------------ | | **profile_id** | uuid | Identifiant utilisateur Adapty. | | **currency** | str | Devise locale (USD par défaut). | | **price_usd** | float | Prix du produit avant commission Apple/Google. Chiffre d'affaires brut. | | **proceeds_usd** | float | Prix du produit après commission Apple/Google. Chiffre d'affaires net. | | **net_revenue_usd** | float | Revenu net (après commission Apple/Google et taxes) en USD. Peut être vide. | | **price_local** | float | Prix du produit avant commission Apple/Google en devise locale. Chiffre d'affaires brut. | | **proceeds_local** | float | Prix du produit après commission Apple/Google en devise locale. Chiffre d'affaires net. | | **transaction_id** | str | Identifiant unique d'une transaction, comme un achat ou un renouvellement. | | **original_transaction_id** | str | Identifiant de transaction de l'achat d'origine. | | **purchase_date** | ISO 8601 date | Date et heure de l'achat du produit. | | **original_purchase_date** | ISO 8601 date | Date et heure de l'achat d'origine. | | **environment** | str | Peut être _Sandbox_ ou _Production_. | | **vendor_product_id** | str | ID du produit sur l'Apple App Store, le Google Play Store ou Stripe. | | **base_plan_id** | str | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) sur le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) sur Stripe. | | **event_datetime** | ISO 8601 date | Date et heure de l'événement. | | **store** | str | Peut être _app_store_ ou _play_store_. | | **trial_duration** | str | Durée de la période d'essai en jours. Envoyée au format « {} days », par exemple « 7 days ». | | **cancellation_reason** | str | <p>Raison pour laquelle l'utilisateur a annulé un abonnement.</p><p></p><p>Valeurs possibles :</p><p>iOS & Android</p><p>_voluntarily_cancelled_, _billing_error_, _refund_</p><p>iOS</p><p>_price_increase_, _product_was_not_available_, _unknown_</p><p>Android</p><p>_new_subscription_replace_, _cancelled_by_developer_</p> | | **subscription_expires_at** | ISO 8601 date | Date d'expiration de l'abonnement. Généralement dans le futur. | | **consecutive_payments** | int | Nombre de périodes consécutives pendant lesquelles l'utilisateur est abonné sans interruption. Inclut la période actuelle. | | **rate_after_first_year** | bool | Booléen indiquant que l'abonnement bénéficie d'un taux de commission réduit (généralement 15 %) après un an de renouvellement continu. Les taux varient selon l'éligibilité au programme et le pays. Voir [Commission du store et taxes](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) pour plus de détails. | | **promotional_offer_id** | str | ID de l'offre promotionnelle, tel qu'indiqué dans la section Produits de l'Adapty Dashboard. | | **store_offer_category** | str | Peut être _introductory_ ou _promotional_. | | **store_offer_discount_type** | str | Peut être _free_trial_, _pay_as_you_go_ ou _pay_up_front_. | | **paywall_name** | str | Nom du paywall depuis lequel la transaction a été initiée. | | **paywall_revision** | int | Révision du paywall depuis lequel la transaction a été initiée. La valeur est définie à 1. | | **developer_id** | str | ID développeur (SDK) du placement depuis lequel la transaction a été initiée. | | **ab_test_name** | str | Nom du test A/B depuis lequel la transaction a été initiée. | | **ab_test_revision** | int | Révision du test A/B depuis lequel la transaction a été initiée. La valeur est définie à 1. | | **cohort_name** | str | Nom de l'audience à laquelle appartient le profil. | | **profile_event_id** | uuid | Identifiant unique de l'événement, utilisable pour la déduplication. | | **store_country** | str | Pays transmis par le store. | | **profile_ip_address** | str | Adresse IP du profil (IPv4 ou IPv6, avec préférence pour IPv4 si disponible). Mise à jour à chaque changement d'IP de l'appareil. | | **profile_country** | str | Déterminé par Adapty, à partir de l'IP du profil. | | **profile_total_revenue_usd** | float | Revenu total du profil, remboursements inclus. | | **variation_id** | uuid | Identifiant unique du paywall sur lequel l'achat a été effectué. | | **access_level_id** | str | ID du niveau d'accès payant. | | **is_active** | bool | Booléen indiquant si le niveau d'accès payant est actif pour le profil. | | **will_renew** | bool | Booléen indiquant si le niveau d'accès payant sera renouvelé. | | **is_refund** | bool | Booléen indiquant si la transaction a été remboursée. | | **is_lifetime** | bool | Booléen indiquant si le niveau d'accès payant est à vie. | | **is_in_grace_period** | bool | Booléen indiquant si le profil est en délai de grâce. | | **starts_at** | ISO 8601 date | Date et heure auxquelles le niveau d'accès payant commence pour l'utilisateur. | | **renewed_at** | ISO 8601 date | Date et heure auxquelles le niveau d'accès payant sera renouvelé. | | **expires_at** | ISO 8601 date | Date et heure auxquelles le niveau d'accès payant expirera. | | **activated_at** | ISO 8601 date | Date et heure auxquelles le niveau d'accès payant a été activé. | | **billing_issue_detected_at** | ISO 8601 date | Date et heure du problème de facturation. | | **profile_has_access_level** | Bool | Booléen indiquant si le profil dispose d'un niveau d'accès actif (webhook uniquement). | Chaque événement possède les propriétés suivantes : `transaction_id, original_transaction_id, purchase_date, original_purchase_date, environment, vendor_product_id, event_datetime, store`. En outre, certains événements ont des propriétés supplémentaires. Pour les événements `subscription_refunded` et `non_subscription_purchase_refunded`, les valeurs de `price_usd` et `proceeds_usd` doivent obligatoirement être fournies en tant que propriétés supplémentaires. | Nom de l'événement | Propriétés | | :---------------------------------- | :----------------------------------------------------------- | | **subscription\_initial\_purchase** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **subscription\_renewed** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **subscription\_cancelled** | cancellation\_reason, trial\_duration | | **trial\_started** | subscription\_expires\_at, trial\_duration | | **trial\_converted** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **trial\_cancelled** | cancellation\_reason, trial\_duration | | **non\_subscription\_purchase** | price\_usd, proceeds\_usd | | **billing\_issue\_detected** | subscription\_expires\_at, trial\_duration | | **entered\_grace\_period** | subscription\_expires\_at, trial\_duration | Exemple d'événement ```json title="Json" { "price_usd": 9.99, "proceeds_usd": 6.99, "transaction_id": "1000000628581600", "original_transaction_id": "1000000628581600", "purchase_date": "2020-02-18T18:40:22.000000+0000", "original_purchase_date": "2020-02-18T18:40:22.000000+0000", "environment": "Sandbox", "vendor_product_id": "premium", "event_datetime": "2020-02-18T18:40:22.000000+0000", "store": "app_store" } ``` Adapty envoie les événements à votre serveur et aux systèmes d'analyse tiers. La propriété **profile_ip_address** est synchronisée avec l'IP actuelle de l'appareil. À chaque fois que les serveurs Adapty reçoivent des informations du SDK, l'IP est mise à jour si elle diffère de celle enregistrée. ### Définir l'identifiant du profil \{#setting-the-profiles-identifier\} - Définissez l'identifiant du profil pour l'outil d'analyse sélectionné en utilisant les instructions pour <InlineTooltip tooltip="instructions pour définir les attributs utilisateur dans votre application">[iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes) et [Unity](unity-setting-user-attributes)</InlineTooltip>. :::warning Éviter les doublons N'oubliez pas de désactiver l'envoi d'événements d'abonnement depuis les appareils et votre serveur pour éviter les doublons. ::: ### Désactiver l'analyse externe pour un client spécifique \{#disabling-external-analytics-for-a-specific-customer\} Vous pouvez vouloir arrêter d'envoyer des événements analytiques pour un client spécifique. C'est utile si votre application propose une option de désactivation des services d'analyse. Pour désactiver l'analyse externe pour un client, utilisez la méthode `updateProfile()`. Créez un objet `AdaptyProfileParameters.Builder` et définissez la valeur correspondante. Lorsque l'analyse externe est bloquée, Adapty n'envoie plus aucun événement à aucune intégration pour cet utilisateur. Si vous souhaitez désactiver une intégration pour tous les utilisateurs de votre application, désactivez-la simplement dans l'Adapty Dashboard. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(analyticsDisabled: true) Adapty.updateProfile(parameters: builder.build()) ``` </TabItem> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers val parameters = AdaptyProfileParameters( analyticsDisabled = true ) Adapty.updateProfile(parameters) { error -> if (error == null) { // successful update } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers ] AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder() .withExternalAnalyticsDisabled(true); Adapty.updateProfile(builder.build()); ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setAnalyticsDisabled(true); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers var builder = new AdaptyProfileParameters.Builder() .SetAnalyticsDisabled(true); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers adapty.updateProfile({ analyticsDisabled: true }); ``` </TabItem> </Tabs> ### Désactiver la collecte des identifiants publicitaires \{#disable-collection-of-advertising-identifiers\} <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> Vous pouvez désactiver la collecte de l'IDFA en utilisant la propriété `idfaCollectionDisabled`. Assurez-vous de l'appeler avant la méthode `.activate()`. ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") // highlight-start .with(idfaCollectionDisabled: true) // set to `true` // highlight-end Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> Vous pouvez désactiver la collecte de l'AAID/GAID en utilisant la propriété `withAdIdCollectionDisabled` lors de l'activation du SDK Adapty : ```swift showLineNumbers override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` // highlight-end .build() ) } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> Vous pouvez désactiver la collecte de l'AAID/GAID en utilisant la propriété `withAdIdCollectionDisabled` lors de l'activation du SDK Adapty : ```swift showLineNumbers @Override public void onCreate() { super.onCreate(); Adapty.activate( applicationContext, new AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` // highlight-end .build() ); } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> Vous pouvez désactiver la collecte de l'IDFA avec la propriété `withAppleIdfaCollectionDisabled` et celle du Google/Android Advertising ID avec `withGoogleAdvertisingIdCollectionDisabled`. Définissez-les sur `true` lors de l'activation du SDK Adapty : ```dart showLineNumbers try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') // highlight-start ..withGoogleAdvertisingIdCollectionDisabled(true), // set to `true` ..withAppleIdfaCollectionDisabled(true), // set to `true` // highlight-end ); } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity" default> Vous pouvez désactiver la collecte de l'IDFA avec la propriété `SetIDFACollectionDisabled` lors de l'activation du SDK Adapty. La collecte de l'AAID/GAID ne peut pas être désactivée pour l'instant. ```dart showLineNumbers var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") // highlight-start .SetIDFACollectionDisabled(true); // set to `true` // highlight-end Adapty.Activate(builder.Build(), (error) => { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native" default> Vous pouvez également désactiver la collecte de l'IDFA avec la propriété `idfaCollectionDisabled` lors de l'activation du SDK Adapty, ou désactiver la collecte de l'AAID/GAID avec la propriété `adIdCollectionDisabled`. ```typescript showLineNumbers adapty.activate('PUBLIC_SDK_KEY', { // highlight-start ios: { idfaCollectionDisabled: true, // set to `true` }, android: { adIdCollectionDisabled: true, }, // highlight-end }); ``` </TabItem> </Tabs> --- # File: amplitude --- --- title: "Amplitude" description: "Intégrez Amplitude avec Adapty pour de meilleures informations sur le comportement des utilisateurs." --- [Amplitude](https://amplitude.com/) est un puissant service d'analyse mobile. Avec Adapty, vous pouvez facilement envoyer des événements à Amplitude, observer le comportement de vos utilisateurs et prendre des décisions éclairées. Adapty fournit un ensemble complet de données vous permettant de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit et de les envoyer vers votre compte Amplitude. Vous pouvez ainsi corréler le comportement de vos utilisateurs avec leur historique d'achats dans Amplitude, et orienter vos décisions produit. ### Comment configurer l'intégration Amplitude \{#how-to-set-up-amplitude-integration\} Dans Adapty, vous pouvez configurer des flows distincts pour les **événements de production** et les **événements de test** provenant de l'environnement sandbox Apple ou Stripe, ou d'un compte de test Google. - Pour les événements de production, saisissez les clés API **Production** depuis le tableau de bord Amplitude, avec une clé API unique pour chaque plateforme : iOS, Android et Stripe. - Pour les événements de test, utilisez les champs **Sandbox** selon vos besoins. Pour configurer l'intégration Amplitude : 1. Ouvrez [**Integrations** -> **Amplitude**](https://app.adapty.io/integrations/amplitude) dans votre Adapty Dashboard. <img src="/assets/shared/img/3b50552-CleanShot_2023-08-15_at_16.47.102x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Activez **Amplitude integration** pour l'activer. 3. Renseignez les champs de l'intégration : | Champ | Description | | ------------------------------------------ | ------------------------------------------------------------ | | **Amplitude iOS/ Android/ Stripe API key** | Saisissez la **clé API** Amplitude pour iOS/ Android/ Stripe dans Adapty. Retrouvez-la sous **Project settings** dans Amplitude. Pour obtenir de l'aide, consultez la [documentation Amplitude](https://amplitude.com/docs/apis/authentication). Commencez avec les clés **Sandbox** pour les tests, puis passez aux clés **Production** après des tests concluants. | <img src="/assets/shared/img/2297782-CleanShot_2023-08-15_at_16.53.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Paramètres optionnels pour personnaliser davantage : | Paramètre | Description | | --------------------------------------- | ------------------------------------------------------------ | | **How the revenue data should be sent** | Choisissez d'envoyer le revenu brut ou le revenu après taxes et commissions. Consultez [Commission des stores et taxes](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) pour plus de détails. | | **Exclude historical events** | Choisissez d'exclure les événements antérieurs à l'installation du SDK Adapty, afin d'éviter les doublons. Par exemple, si un utilisateur s'est abonné le 10 janvier mais a installé le SDK Adapty le 6 mars, Adapty n'enverra que les événements à partir du 6 mars. | | **Send User Attributes** | Sélectionnez cette option pour envoyer des attributs propres à l'utilisateur, comme ses préférences de langue. | | **Always populate user_id** | Adapty envoie automatiquement `device_id` en tant que `amplitudeDeviceId`. Pour `user_id`, ce paramètre définit le comportement : <ul><li>**ON** : envoie le `profile_id` Adapty si `amplitudeUserId` ou `customer_user_id` ne sont pas disponibles.</li><li>**OFF** : laisse `user_id` vide si aucun identifiant n'est disponible.</li></ul> | 5. Choisissez les événements que vous souhaitez recevoir et [associez leurs noms](amplitude#events-and-tags). 6. Cliquez sur **Save** pour confirmer vos modifications. Une fois que vous cliquez sur **Save**, Adapty commence à envoyer des événements à Amplitude. En plus des événements, Adapty envoie le [statut d'abonnement](subscription-status) et l'identifiant du produit d'abonnement aux [propriétés utilisateur Amplitude](https://amplitude.com/docs/data/user-properties-and-events). ### Événements et tags \{#events-and-tags\} Sous les identifiants de connexion, trois groupes d'événements peuvent être envoyés à Amplitude depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/da67694-CleanShot_2023-08-15_at_16.52.352x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty. Vous pouvez toutefois les modifier selon vos besoins. Adapty enverra les événements d'abonnement à Amplitude via une intégration serveur à serveur, vous permettant de visualiser tous les événements d'abonnement dans votre tableau de bord Amplitude. ### Configuration du SDK \{#sdk-configuration\} Utilisez la méthode `setIntegrationIdentifier()` pour définir le paramètre `amplitude_device_id`. Cette étape est indispensable pour configurer l'intégration. Si vous gérez l'inscription des utilisateurs, vous pouvez également transmettre `amplitude_user_id`. :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="Swift" label="iOS (Swift)" default> **Définir amplitudeDeviceId** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "amplitude_device_id", value: Amplitude.instance().deviceId ) } catch { // handle the error } ``` **Définir amplitudeUserId** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "amplitude_user_id", value: "YOUR_AMPLITUDE_USER_ID" ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> **Définir amplitudeDeviceId** ```kotlin showLineNumbers //for Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeDeviceId = amplitude.store.deviceId // Adapty.setIntegrationIdentifier("amplitude_device_id", amplitudeDeviceId) { error -> if (error != null) { // handle the error } } ``` **Définir amplitudeUserId** ```kotlin showLineNumbers //for Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeUserId = amplitude.store.userId // Adapty.setIntegrationIdentifier("amplitude_user_id", amplitudeUserId) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="Flutter" label="Flutter (Dart)" default> **Définir amplitudeDeviceId** ```javascript showLineNumbers final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); try { await Adapty().setIntegrationIdentifier( key: "amplitude_device_id", value: amplitude.getDeviceId(), ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` **Définir amplitudeUserId** ```javascript showLineNumbers final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); try { await Adapty().setIntegrationIdentifier( key: "amplitude_user_id", value: "YOUR_AMPLITUDE_USER_ID", ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="Unity" label="Unity (C#)" default> **Définir amplitudeDeviceId** ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "amplitude_device_id", amplitude.getDeviceId(), (error) => { // handle the error }); ``` **Définir amplitudeUserId** ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "amplitude_user_id", "YOUR_AMPLITUDE_USER_ID", (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> **Définir amplitudeDeviceId** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` **Définir amplitudeUserId** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("amplitude_user_id", userId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Structure des événements Amplitude \{#amplitude-event-structure\} Adapty envoie les événements à Amplitude via l'API HTTP v2. Chaque événement est structuré comme suit : ```json { "api_key": "your_amplitude_api_key", "events": [ { "partner_id": "adapty", "event_type": "subscription_renewed", "time": 1709294400000, "insert_id": "123e4567-e89b-12d3-a456-426614174000", "user_id": "user_12345", "device_id": "device_12345", "platform": "iOS", "os_name": "iOS", "productId": "yearly.premium.6999", "revenue": 9.99, "event_properties": { "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383...", "currency": "USD", "environment": "Production", "store": "app_store" }, "user_properties": { "subscription_state": "subscribed", "subscription_product": "yearly.premium.6999" } } ] } ``` Où : | Paramètre | Type | Description | |:----------------------------|:-------|:---------------------------------------------------------------------| | `api_key` | String | Votre clé API Amplitude. | | `events` | Array | Liste des objets événement (Adapty en envoie un à la fois). | | `events[].partner_id` | String | Toujours "adapty". | | `events[].event_type` | String | Le nom de l'événement (mappé depuis l'événement Adapty). | | `events[].time` | Long | Horodatage de l'événement en millisecondes. | | `events[].insert_id` | String | Identifiant unique de l'événement (UUID). | | `events[].user_id` | String | Identifiant utilisateur Amplitude ou identifiant client. | | `events[].device_id` | String | Identifiant d'appareil Amplitude. | | `events[].platform` | String | Plateforme (ex. : "iOS", "Android"). | | `events[].os_name` | String | Nom du système d'exploitation. | | `events[].productId` | String | Identifiant du produit dans le store. | | `events[].revenue` | Float | Montant du revenu. | | `events[].event_properties` | Object | Attributs détaillés de l'événement (contient tous les [champs d'événement](webhook-event-types-and-fields#for-most-event-types) disponibles). | | `events[].user_properties` | Object | Attributs utilisateur tels que le statut d'abonnement. | --- # File: appmetrica --- --- title: "AppMetrica" description: "Intégrez AppMetrica avec Adapty pour des analyses d'abonnements approfondies." --- [AppMetrica](https://appmetrica.yandex.com/about) est un outil d'analyse gratuit qui vous permet de suivre le comportement des utilisateurs et d'analyser les performances de votre application mobile en temps réel. En intégrant AppMetrica avec Adapty, vous obtenez une vision plus approfondie de vos métriques d'abonnement et de l'engagement de vos utilisateurs. ## Comment configurer l'intégration AppMetrica \{#how-to-set-up-appmetrica-integration\} La configuration de l'intégration AppMetrica comprend deux étapes principales : 1. Configurer l'intégration dans l'Adapty Dashboard 2. Mettre en place l'intégration dans le code de votre application ### Configuration du tableau de bord \{#dashboard-configuration\} Pour configurer l'intégration AppMetrica : 1. Ouvrez la [liste des applications AppMetrica](https://appmetrica.yandex.ru/application/list) 2. Sélectionnez l'application que vous souhaitez suivre 3. Allez dans **Settings > Main** et copiez l'**Application ID** et la **Post API key** <img src="/assets/shared/img/appmetrica.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Rendez-vous dans [Integrations > AppMetrica](https://app.adapty.io/integrations/appmetrica) dans l'Adapty Dashboard 5. Collez vos identifiants AppMetrica. <img src="/assets/shared/img/appmetrica_creds.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Événements et tags \{#events-and-tags\} Adapty vous permet d'envoyer trois groupes d'événements à AppMetrica. Vous pouvez activer les événements dont vous avez besoin pour suivre les performances de votre application. Pour la liste complète des événements disponibles, consultez notre [documentation sur les événements](events). :::note AppMetrica synchronise les événements toutes les 4 heures, ce qui peut entraîner un délai avant que les événements n'apparaissent dans votre tableau de bord. ::: <img src="/assets/shared/img/6ed2d88-CleanShot_2023-08-18_at_14.59.042x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::tip Nous recommandons d'utiliser les noms d'événements par défaut d'Adapty pour plus de cohérence, mais vous pouvez les personnaliser pour les adapter à votre configuration analytique existante. ::: ### Paramètres de revenus \{#revenue-settings\} Par défaut, Adapty envoie les données de revenus sous forme de propriétés dans les événements, qui apparaissent dans le rapport Événements d'AppMetrica. Vous pouvez configurer la façon dont ces données de revenus sont calculées et affichées : - **Calcul des revenus** : Choisissez comment les valeurs de revenus sont calculées pour correspondre à vos besoins de reporting financier : - **Revenus bruts** : Affiche le total des revenus avant toute déduction, utile pour suivre le montant total payé par les clients - **Recettes après commission du store** : Affiche les revenus après déduction des frais de l'App Store/Play Store, pour suivre vos gains réels - **Recettes après commission du store et taxes** : Affiche les revenus nets après déduction des frais du store et des taxes applicables, offrant la vision la plus précise de vos gains - **Report user's currency** : lorsque cette option est activée, les ventes sont rapportées dans la devise locale de l'utilisateur, ce qui facilite l'analyse des revenus par région. Lorsqu'elle est désactivée, toutes les ventes sont converties en USD pour un reporting cohérent sur l'ensemble des marchés. - **Send revenue events** : activez cette option pour que les données de revenus apparaissent non seulement dans le rapport Événements, mais aussi dans le rapport [In-app and ad revenue](https://appmetrica.yandex.com/docs/en/mobile-reports/revenue-report) d'AppMetrica. Assurez-vous de ne pas envoyer des données de revenus depuis un autre endroit, car cela pourrait entraîner des doublons. - **Exclude historical events** : Lorsque cette option est activée, Adapty n'envoie pas les événements survenus avant l'installation de l'app avec le SDK Adapty. Cela permet d'éviter les doublons si vous envoyiez déjà des événements à votre outil d'analyse avant d'intégrer Adapty. <img src="/assets/shared/img/appmetrica_revenue.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Configuration du SDK \{#sdk-configuration\} Pour activer l'intégration AppMetrica dans votre application, vous devez configurer deux identifiants : 1. `appmetrica_device_id` : Requis pour l'intégration de base 2. `appmetrica_profile_id` : Optionnel, mais recommandé si votre application dispose d'un système d'inscription utilisateur Utilisez la méthode `setIntegrationIdentifier()` pour définir ces valeurs. Voici comment l'implémenter sur chaque plateforme : :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="Swift" label="iOS (Swift)" default> **Définir appmetrica_device_id** ```swift showLineNumbers AppMetrica.requestStartupIdentifiers(on: nil) { ids, error in if let error { // handle AppMetrica error return } guard let deviceIDHash = ids?[.deviceIDHashKey] as? String else { // handle AppMetrica error return } Task { do { try await Adapty.setIntegrationIdentifier( key: "appmetrica_device_id", value: deviceIDHash ) } catch { // handle the error } } } ``` **Définir appmetrica_profile_id** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "appmetrica_profile_id", value: "YOUR_APPMETRICA_PROFILE_ID" ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> **Setting appmetrica_device_id** ```kotlin showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceIdHash = result?.deviceIdHash ?: return Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash) { error -> if (error != null) { // handle the error } } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { //handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID_HASH)) ``` **Définir appmetrica_profile_id** ```kotlin showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceIdHash = result?.deviceIdHash ?: return Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash) { error -> if (error != null) { // handle the error } } Adapty.setIntegrationIdentifier("appmetrica_profile_id", "YOUR_ADAPTY_CUSTOMER_USER_ID") { error -> if (error != null) { // handle the error } } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { //handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID_HASH)) ``` </TabItem> <TabItem value="Flutter" label="Flutter (Dart)" default> **Setting appmetrica_device_id** ```javascript showLineNumbers final startupParams = await AppMetrica.requestStartupParams([AppMetricaStartupParams.deviceIdHashKey]); final deviceIdHash = startupParams.result?.deviceIdHash; if (deviceIdHash != null) { try { await Adapty().setIntegrationIdentifier( key: "appmetrica_device_id", value: deviceIdHash, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` **Setting appmetrica_profile_id** ```javascript showLineNumbers try { await Adapty().setIntegrationIdentifier( key: "appmetrica_profile_id", value: "YOUR_APPMETRICA_PROFILE_ID", ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="Unity" label="Unity (C#)" default> **Définir appmetrica_device_id** ```csharp showLineNumbers using AdaptySDK; using Io.AppMetrica; AppMetrica.RequestStartupParams( (result, errorReason) => { string deviceIdHash = result.DeviceIdHash; if (deviceIdHash != null) { Adapty.SetIntegrationIdentifier( "appmetrica_device_id", deviceIdHash, (error) => { // handle the error }); } }, new List<string>() { StartupParamsKey.AppMetricaDeviceIDHash } ); ``` **Définition de appmetrica_profile_id** ```csharp showLineNumbers Adapty.SetIntegrationIdentifier( "appmetrica_profile_id", "YOUR_APPMETRICA_PROFILE_ID", (error) => { // handle the error }); ``` </TabItem> <TabItem value="RN" label="React Native (TS)" default> **Définir appmetrica_device_id** ```typescript showLineNumbers // ... const startupParamsCallback = async ( params?: StartupParams, reason?: StartupParamsReason ) => { const deviceIdHash = params?.deviceIdHash if (deviceIdHash) { try { await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash); } catch (error) { // handle `AdaptyError` } } } AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_HASH_KEY]) ``` **Définir appmetrica_profile_id** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID'); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Structure des événements AppMetrica \{#appmetrica-event-structure\} Adapty envoie des événements à AppMetrica via des requêtes POST avec des paramètres transmis en tant que paramètres de requête. Pour chaque événement Adapty, AppMetrica reçoit jusqu'à **deux requêtes distinctes** : 1. **Événement de profil** (toujours envoyé) : contient les métadonnées de l'événement 2. **Événement de revenus** (optionnel) : contient les données de revenus si l'option « Send revenue events » est activée dans le Adapty Dashboard ### Requête d'événement de profil \{#profile-event-request\} Envoyée à : `https://api.appmetrica.yandex.ru/logs/v1/import/events` Exemple d'URL avec paramètres de requête : ``` POST https://api.appmetrica.yandex.ru/logs/v1/import/events?post_api_key=your_key&application_id=your_app_id&event_name=subscription_renewed&event_timestamp=1709294400&event_json=%7B%22vendor_product_id%22%3A%22yearly.premium%22...%7D&os_name=ios&ios_ifa=00000000-0000-0000-0000-000000000000&ios_ifv=12345678-1234-1234-1234-123456789012&profile_id=user_12345&session_type=foreground ``` Paramètres de requête : | Paramètre | Type | Description | |:-----------------------|:-------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | `post_api_key` | String | Votre clé API Post AppMetrica. | | `application_id` | String | Votre ID d'application AppMetrica. | | `event_name` | String | Le nom de l'événement (mappé depuis l'événement Adapty). | | `event_timestamp` | Long | Horodatage UNIX de l'événement en secondes. Limité aux 7 derniers jours si la date est plus ancienne. | | `event_json` | String | Chaîne JSON encodée en URL contenant tous les [champs d'événement](webhook-event-types-and-fields#for-most-event-types) disponibles. Seuls les champs non nuls sont inclus. | | `os_name` | String | "ios" ou "android". | | `profile_id` | String | ID de profil AppMetrica (si défini), sinon Customer User ID (si disponible). | | `appmetrica_device_id` | String | Hash de l'ID d'appareil AppMetrica. Envoyé uniquement si `profile_id` n'est pas disponible. | | `session_type` | String | Toujours "foreground". | | `ios_ifa` | String | **iOS uniquement**. ID for Advertisers. | | `ios_ifv` | String | **iOS uniquement**. ID for Vendors. | | `google_aid` | String | **Android uniquement**. Google Advertising ID. | ### Requête d'événement de revenu (Optionnelle) \{#revenue-event-request-optional\} Envoyée vers : `https://api.appmetrica.yandex.ru/logs/v1/import/revenue` Cette requête n'est envoyée que lorsque l'option « Send revenue events » est activée dans les paramètres d'intégration de votre Adapty Dashboard. Exemple d'URL avec paramètres de requête : ``` POST https://api.appmetrica.yandex.ru/logs/v1/import/revenue?post_api_key=your_key&application_id=your_app_id&revenue_event_type=subscription_renewed&price=9.99¤cy=USD&product_id=yearly.premium&quantity=1&transaction_id=GPA.3383...&payload=%7B%22vendor_product_id%22%3A%22yearly.premium%22...%7D&os_name=ios&ios_ifa=00000000-0000-0000-0000-000000000000&profile_id=user_12345&session_type=foreground ``` Paramètres de requête : | Paramètre | Type | Description | |:---------------------|:--------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `post_api_key` | String | Votre clé Post API AppMetrica. | | `application_id` | String | Votre ID d'application AppMetrica. | | `revenue_event_type` | String | Le type d'événement de revenus (ex. : "subscription_renewed", "refund", "intro_started"). Voir [Correspondance des événements AppMetrica](#events-and-tags). | | `price` | Float | Montant des revenus (selon vos paramètres de calcul des revenus). | | `currency` | String | Code de devise (ex. : "USD"). | | `product_id` | String | L'ID du produit dans le store. | | `quantity` | Integer | Toujours 1. | | `transaction_id` | String | ID de transaction du store. | | `payload` | String | Chaîne JSON encodée en URL contenant les détails de l'événement. Automatiquement tronquée si elle dépasse 30 Ko en supprimant les champs optionnels par ordre d'importance afin de conserver les données les plus critiques. | | `os_name` | String | "ios" ou "android". | | `profile_id` | String | L'ID de profil AppMetrica (si défini), sinon le Customer User ID (si disponible). | | `appmetrica_device_id` | String | Hash de l'ID d'appareil AppMetrica. Envoyé uniquement si `profile_id` n'est pas disponible. | | `session_type` | String | Toujours "foreground". | | `ios_ifa` | String | **iOS uniquement**. ID pour les annonceurs. | | `ios_ifv` | String | **iOS uniquement**. ID pour les éditeurs. | | `google_aid` | String | **Android uniquement**. Google Advertising ID. | --- # File: firebase-and-google-analytics --- --- title: "Firebase et Google Analytics" description: "Envoyez les événements d'abonnement Adapty vers Firebase et Google Analytics — alimentez Audiences, Remote Config, l'attribution Google Ads et d'autres outils Firebase." --- Adapty peut transmettre les événements d'abonnement — achats, renouvellements, remboursements, démarrages d'essai — vers Firebase et Google Analytics, de sorte qu'une seule intégration alimente les deux plateformes. :::warning Vous avez besoin d'un projet Firebase et d'une propriété Google Analytics liée — même si vous n'en utilisez qu'une seule. Firebase et Google Analytics partagent les mêmes données dans deux consoles distinctes. ::: Les événements d'achat et de remboursement arrivent avec les détails de revenus, de devise et de produit associés. Ces mêmes données alimentent les outils mobiles de Firebase (Audiences, Remote Config, etc.) et les rapports dans Google Analytics. Il s'agit d'une intégration analytique, pas d'un outil d'attribution Google Ads — voir [Limitations](#limitations). ## Ce que vous pouvez faire avec cette intégration \{#what-you-can-do-with-this-integration\} Adapty regroupe les utilisateurs par `subscription_state` (`subscribed`, `active_trial`, `never_subscribed`, etc.) et transmet les événements du cycle de vie des abonnements vers Firebase et Google Analytics. - **Audiences** : Créez des audiences d'abonnés dans Firebase et Google Analytics pour des canaux externes — reciblage Google Ads, campagnes FCM, modélisation de sosies. - **Conversions Google Ads** *(Google Analytics)* : Utilisez `purchase` et `refund` comme objectifs de conversion Google Ads. - **Firebase Remote Config** : Modifiez les limites d'utilisation, les textes ou les indicateurs de fonctionnalités sans mise à jour de l'application — conditionnez-les sur l'état de l'abonnement. (À ne pas confondre avec [Adapty Remote Config](customize-paywall-with-remote-config), qui configure le contenu des flows/paywalls.) - **Cloud Messaging** : Notifications push aux abonnés inactifs lorsque l'application est fermée. - **Suivi multi-appareils** *(Google Analytics)* : Adapty envoie le `customer_user_id` à Google Analytics pour que Google Ads puisse suivre la même personne sur plusieurs appareils. - **Entonnoirs de conversion** *(Google Analytics)* : Observez ce que les utilisateurs ont fait dans votre application avant de convertir ou de se désabonner. - **Prédictions** : Anticipez le taux d'attrition et les dépenses à partir de l'historique d'achats. - **Tests A/B** : Testez des fonctionnalités de l'application sur des cohortes d'abonnés — par exemple, déployez un nouveau schéma de navigation auprès des utilisateurs en essai et mesurez la durée des sessions. (Pour les variantes de paywall, utilisez les [tests A/B Adapty](ab-tests).) ## Comment fonctionne l'intégration \{#how-the-integration-works\} 1. Lorsqu'un utilisateur ouvre votre application pour la première fois, le SDK Firebase crée un identifiant unique pour l'installation — le **Firebase App Instance ID**. Firebase et Google Analytics utilisent cet identifiant pour identifier l'installation responsable de chaque événement. 2. Votre application transmet le Firebase App Instance ID au SDK Adapty. Adapty relie le profil de l'utilisateur à cette installation Firebase. 3. Lorsque l'utilisateur effectue un achat, les serveurs d'Adapty transmettent l'événement à Firebase avec le Firebase App Instance ID joint. Les données sont échangées de serveur à serveur, en dehors de l'application. 4. Firebase associe l'achat à l'installation, ce qui vous permet de voir les achats aux côtés de tout ce que l'utilisateur a fait dans l'application. :::note Un Firebase App Instance ID est spécifique à un appareil. Lorsque le même utilisateur Adapty ouvre l'application sur un autre appareil, le nouvel identifiant Firebase remplace le précédent. Utilisez un [customer user ID](identifying-users) pour maintenir l'identité de l'utilisateur sur plusieurs appareils. ::: ### Achats Stripe \{#stripe-purchases\} Un achat Stripe n'atteint Firebase que si l'acheteur a lancé votre application mobile **en premier**. Le Firebase App Instance ID doit être défini **avant** que l'achat Stripe ne se déclenche. Pour les achats App Store et Play Store, cela se produit automatiquement. Ils proviennent de votre application mobile, aux côtés de l'appel [`setIntegrationIdentifier`](#configure-your-app-code). L'identifiant Firebase est présent au moment de l'achat. Les achats Stripe proviennent de l'extérieur de l'application, depuis votre serveur. Votre application mobile doit appeler `setIntegrationIdentifier` au lancement — avant tout achat Stripe. Sinon, Adapty n'a pas d'identifiant à joindre et l'achat Stripe n'atteint jamais Firebase. ### Limitations \{#limitations\} - **Pas un outil d'attribution Google Ads.** Cette intégration envoie les événements Adapty dans Firebase et Google Analytics à des fins analytiques. Elle n'attribue pas les installations d'applications aux campagnes Google Ads (UAC / Universal App Campaigns) et ne distingue pas le trafic payant du trafic organique. Pour l'attribution des installations, utilisez [Adapty Attribution](adapty-user-acquisition) intégré à Adapty. - **Pas de remplissage historique.** Adapty transmet les événements à partir du moment où vous activez l'intégration — les achats, renouvellements et remboursements passés n'atteignent jamais Firebase. (Les données passées sont disponibles dans les exports [S3](s3-exports) / [GCS](google-cloud-storage) d'Adapty, mais leur importation dans Firebase ne fait pas partie de cette intégration.) - **Les acheteurs web uniquement n'atteignent pas Firebase.** Adapty transmet les achats à Firebase via le Firebase App Instance ID défini par votre application mobile. Les acheteurs qui n'ont jamais installé l'application n'ont pas d'identifiant — leurs achats n'atteignent pas Firebase. Consultez [Achats Stripe](#stripe-purchases) ci-dessus pour plus de détails, et envisagez [l'intégration Firebase de FunnelFox](https://funnelfox.com/docs/integrations/subscription-management/adapty) ou un flux de données web Google Analytics pour le suivi web. - **Les achats Paddle ne sont pas inclus.** Cette intégration ne prend actuellement pas en charge Paddle. Les achats Paddle restent dans Adapty Analytics et n'atteignent pas Firebase via ce chemin. - **Les achats Stripe héritent des limitations spécifiques à Stripe.** Voir [limitations de l'intégration Stripe](stripe#current-limitations). ## Instructions de configuration \{#setup-instructions\} ### Configurer Firebase \{#configure-firebase\} 1. Ouvrez la [Firebase Console](https://console.firebase.google.com/) et sélectionnez ou créez un projet. Pour garder les analyses de production à l'abri des événements sandbox, utilisez un projet Firebase séparé pour les builds de développement. 2. Liez le projet à une propriété Google Analytics. Firebase vous y invite lors de la création du projet, ou ajoutez-le plus tard via **Project settings** > **Integrations** > **Google Analytics**. 3. Dans **Project settings** > **General** > **Your apps**, ajoutez une entrée pour chaque plateforme sur laquelle vous publiez (iOS / Android / Web). Pour Stripe, ajoutez une entrée Web app — il n'existe pas de type d'application Stripe natif. Chaque entrée génère un **Firebase App ID** unique et un flux de données correspondant dans Google Analytics. Vous collerez cet identifiant dans les paramètres d'intégration Firebase d'Adapty lors de la configuration. ### Configurer Adapty \{#configure-adapty\} 1. Ouvrez [**Integrations** > **Firebase**](https://app.adapty.io/integrations/firebase) dans l'Adapty Dashboard. 2. Activez le bouton **Firebase integration**. 3. Saisissez les identifiants pour chaque plateforme sur laquelle vous publiez. Adapty a besoin d'un **Firebase App ID** et d'un **Google Analytics secret** pour chaque plateforme — chaque valeur diffère selon iOS, Android et Stripe. | Adapty Dashboard | Google Analytics | Où le trouver | | --- | --- | --- | | **Firebase App ID** | **App ID** | Firebase Console > **Project settings** > **General** > **Your apps** | | **Google Analytics secret** | **Measurement Protocol API secret** | Google Analytics > **Admin** > **Data streams** > **Measurement Protocol API secrets** > **Create** | 4. Configurez la manière dont Adapty transmet les revenus et les données utilisateur. Les quatre contrôles partagent une même ligne dans le tableau de bord : - Menu déroulant **Revenue definition** : Revenus bruts, Produits après commission du store, ou [Produits après commission du store et taxes](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue). - Bouton **Send user properties** : Lorsqu'il est activé, les événements incluent `subscription_state` et `subscription_product_id`. Pour les utiliser dans des rapports ou des audiences, voir [Utiliser les données d'abonnement dans les rapports](#use-subscription-data-in-reports-and-audiences). - Bouton **Report user's currency** : Lorsqu'il est activé, Adapty convertit la devise locale de chaque transaction dans la devise de reporting de votre compte avant de la transmettre à Google Analytics. - Bouton **Send trial price** : Les démarrages d'essai sont précieux — la plupart des utilisateurs payants commencent souvent par un essai. Mais l'optimisation des enchères Google Ads ne considère que les événements avec des revenus comme valant la peine d'être ciblés. Activez ce bouton pour attribuer un prix fictif à chaque essai afin que Google les considère comme des conversions et optimise les dépenses publicitaires pour acquérir des utilisateurs d'essai. Lorsqu'il est activé, le champ **Trial price percentage** apparaît. Définissez-le sur la part du prix d'abonnement complet que Google doit considérer comme la valeur de chaque essai — par exemple, `50%` signale la moitié du prix de l'abonnement pendant l'essai. 5. Associez les événements Adapty aux noms d'événements Firebase/Google Analytics. Adapty expose des mappages d'événements séparés pour **iOS** et **Android** afin que vous puissiez utiliser des noms différents par plateforme. **Les achats Stripe utilisent le mappage d'événements iOS** — il n'existe pas de mappage Stripe séparé. Google Analytics applique des limites strictes sur le Measurement Protocol — noms d'événements de 40 caractères, noms de propriétés utilisateur de 24 caractères et valeurs de 36 caractères. Google Analytics ignore silencieusement les événements personnalisés qui dépassent ces limites. :::warning Certains événements utilisent le vocabulaire e-commerce réservé dans Firebase et Google Analytics — `purchase` et `refund`. L'import de conversions Google Ads, les rapports de revenus Google Analytics et les audiences prédictives dépendent de ces chaînes exactes. Ne modifiez les valeurs par défaut que si vous n'avez pas besoin de ces fonctionnalités. ::: 6. Cliquez sur **Save**. Adapty commence à transmettre les événements à Firebase en quelques minutes. ### Configurer le code de votre application \{#configure-your-app-code\} :::tip Assurez-vous que votre application inclut le <InlineTooltip tooltip="SDK Firebase">[iOS](https://firebase.google.com/docs/ios/setup), [Android](https://firebase.google.com/docs/android/setup), [Flutter](https://firebase.google.com/docs/flutter/setup), [Unity](https://firebase.google.com/docs/unity/setup), [React Native](https://rnfirebase.io/), et [Capacitor](https://github.com/capawesome-team/capacitor-firebase)</InlineTooltip>. ::: Adapty doit inclure le **Firebase App Instance ID** avec chaque événement — sinon rien n'atteint Firebase (`MISSING_INTEGRATION_ID`). Après `FirebaseApp.configure()` et `Adapty.activate()`, demandez au SDK Firebase l'App Instance ID. Transmettez-le à Adapty via `setIntegrationIdentifier`. Exécutez cela une fois par lancement d'application, avant tout flux d'achat. :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> <Tabs groupId="sdk-version" queryString> <TabItem value="v4" label="Adapty SDK v4+"> ```swift showLineNumbers FirebaseApp.configure() if let appInstanceId = Analytics.appInstanceID() { do { try await Adapty.setIntegrationIdentifier(.firebaseAppInstanceId(appInstanceId)) } catch { // handle the error } } ``` </TabItem> <TabItem value="v3" label="Adapty SDK v3" default> ```swift showLineNumbers FirebaseApp.configure() if let appInstanceId = Analytics.appInstanceID() { do { try await Adapty.setIntegrationIdentifier( key: "firebase_app_instance_id", value: appInstanceId ) } catch { // handle the error } } ``` </TabItem> </Tabs> </TabItem> <TabItem value="kotlin" label="Android (Kotlin)"> ```kotlin showLineNumbers // after Adapty.activate() FirebaseAnalytics.getInstance(context).appInstanceId.addOnSuccessListener { appInstanceId -> Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId) { error -> if (error != null) { // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)"> ```java showLineNumbers // after Adapty.activate() FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId, error -> { if (error != null) { // handle the error } }); }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)"> ```dart showLineNumbers final appInstanceId = await FirebaseAnalytics.instance.appInstanceId; if (appInstanceId != null) { try { await Adapty().setIntegrationIdentifier( key: "firebase_app_instance_id", value: appInstanceId, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` </TabItem> <TabItem value="unity" label="Unity (C#)"> ```csharp showLineNumbers using AdaptySDK; using Firebase.Analytics; FirebaseAnalytics .GetAnalyticsInstanceIdAsync() .ContinueWithOnMainThread((task) => { if (!task.IsCompletedSuccessfully) { // handle the error return; } Adapty.SetIntegrationIdentifier( "firebase_app_instance_id", task.Result, (error) => { // handle the error } ); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)"> ```typescript showLineNumbers try { const appInstanceId = await analytics().getAppInstanceId(); if (appInstanceId) { await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId); } } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ### Vérifier l'intégration \{#verify-the-integration\} Le moyen le plus rapide de confirmer que les événements arrivent bien est Firebase DebugView : 1. Sur un appareil de test, lancez votre application avec le [mode debug Firebase activé](https://firebase.google.com/docs/analytics/debugview#enable_debug_mode). 2. Déclenchez un achat sandbox ou tout événement que vous avez activé dans l'Adapty Dashboard. 3. Ouvrez Firebase Console > **Analytics** > **DebugView**. Les événements apparaissent en quelques secondes, avec tous leurs paramètres. Les rapports standard — Realtime, Reports, audiences — se remplissent en quelques minutes à 24 heures, selon le rapport. DebugView est le seul endroit pour confirmer en temps réel. ## Utiliser les données d'abonnement dans les rapports et les audiences \{#use-subscription-data-in-reports-and-audiences\} Activez **Send user properties** dans le tableau de bord Adapty ([Configurer Adapty](#configure-adapty), étape 4). Sans cela, Adapty ne transmet pas `subscription_state` ni `subscription_product_id` — et le reste de cette section ne servira à rien. Par défaut, Firebase et Google Analytics n'exposent pas les propriétés utilisateur. Enregistrez chacune d'elles comme dimension personnalisée. Cela rend `subscription_state` et `subscription_product_id` disponibles dans les rapports, les Explorations et les audiences. Configurez les dimensions dans l'administration de Google Analytics. Vous pouvez ensuite les interroger dans Firebase et Google Analytics — ils partagent un backend commun. Utile pour créer des audiences Google Ads d'utilisateurs payants ou alimenter des modèles prédictifs. Une fois la configuration terminée, Adapty renseignera ces propriétés pour les événements à venir. Les événements existants ne seront pas mis à jour. 1. Dans Google Analytics, ouvrez **Admin** > **Custom definitions**. 2. Cliquez sur **Create custom dimensions**. 3. Pour chaque propriété, définissez : - **Dimension name** : N'importe quel nom lisible, par exemple "Subscription state". - **Scope** : **User**. - **User property** : `subscription_state` ou `subscription_product_id`. Le nom doit correspondre exactement — Google Analytics est sensible à la casse. ## Résolution des problèmes \{#troubleshooting\} ### Les événements n'apparaissent pas dans Firebase \{#events-dont-appear-in-firebase\} - Confirmez que le Firebase App Instance ID est défini **avant** le premier achat. Les événements sans identifiant Firebase n'atteignent pas Firebase et génèrent une erreur. - Confirmez que la propriété Google Analytics liée dans la Firebase Console correspond au flux de données. - Confirmez que les identifiants (ID + secret) dans Adapty correspondent à la plateforme. ### `access_level_updated` apparaît comme échoué dans l'Event Feed \{#access_level_updated-shows-as-failed-in-the-event-feed\} `access_level_updated` est un **événement webhook uniquement**. Adapty ne tente jamais de le transmettre à Firebase — mais l'Event Feed l'affiche quand même comme une livraison échouée. Ignorez cette ligne. Votre intégration fonctionne correctement. Pour utiliser cet événement, configurez [l'intégration webhook](webhook). ### Les événements sandbox polluent les données de production \{#sandbox-events-pollute-production-data\} Adapty transmet les transactions sandbox et de production vers le même projet Firebase. Consultez [Configurer Firebase](#configure-firebase) — l'utilisation d'un projet Firebase séparé pour les builds de développement évite entièrement ce problème. ### Firebase sous-estime les revenus pour les applications StoreKit 2 \{#firebase-undercounts-revenue-for-storekit-2-apps\} Firebase enregistre automatiquement un événement `in_app_purchase` pour chaque achat StoreKit 1 — sans code requis. StoreKit 2 utilise une API différente. Firebase ne voit jamais ces transactions. La conséquence : les applications fortement axées sur SK2 sans pipeline de revenus séparé sous-déclarent de moitié ou plus — dans Firebase, dans Google Analytics et dans chaque campagne Google Ads en aval. L'optimisation des enchères s'appuie sur un mauvais chiffre. Les rapports de revenus n'offrent qu'une vue partielle. La solution : transmettez `firebase_app_instance_id` à Adapty (voir [Configurer le code de votre application](#configure-your-app-code)). Adapty transmet chaque achat via le Measurement Protocol — revenus, devise et produit inclus. ### Les chiffres d'Adapty Analytics et de Firebase divergent \{#adapty-analytics-and-firebase-numbers-diverge\} - **StoreKit 2** : De loin la principale cause. Voir [Firebase sous-estime les revenus pour les applications StoreKit 2](#firebase-undercounts-revenue-for-storekit-2-apps). - **Adoption du SDK** : Firebase ne comptabilise que les événements des utilisateurs dont l'application envoie un Firebase App Instance ID. Les anciennes versions de l'application ne font pas cet appel. Adapty comptabilise quand même ces utilisateurs ; Firebase ne le fait pas. - **Événements sandbox** : Adapty transmet également les transactions sandbox à Firebase. Utilisez un projet Firebase séparé pour les builds de développement afin de les distinguer. - **Échantillonnage** : Google Analytics Explorations échantillonne les grands ensembles de données. Pour des chiffres non échantillonnés, consultez la vue Realtime ou les rapports standard. ### Les noms d'événements personnalisés sont rejetés par Google Analytics \{#custom-event-names-are-rejected-by-google-analytics\} Google Analytics limite les noms d'événements à 40 caractères, alphanumériques et underscores uniquement, commençant par une lettre. Renommez dans le tableau de bord tout événement Adapty personnalisé qui enfreint ces limites. --- # File: mixpanel --- --- title: "Mixpanel" description: "Connectez Mixpanel à Adapty pour une analyse puissante de vos abonnements." --- [Mixpanel](https://mixpanel.com/home/) est un puissant service d'analyse produit. Sa solution de suivi basée sur les événements permet aux équipes produit d'obtenir des informations précieuses sur les stratégies optimales d'acquisition, de conversion et de rétention des utilisateurs sur différentes plateformes. Cette intégration vous permet d'envoyer tous les événements Adapty dans Mixpanel. Vous obtenez ainsi une vision plus complète de votre activité d'abonnement et des actions de vos clients. Adapty fournit un ensemble complet de données qui vous permet de suivre les [événements d'abonnement](events) depuis les stores en un seul endroit. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et utiliser ces informations pour leur envoyer des communications ciblées et efficaces. ## Comment configurer l'intégration Mixpanel \{#how-to-set-up-mixpanel-integration\} 1. Ouvrez la page [Integrations -> Mixpanel](https://app.adapty.io/integrations/mixpanel) dans l'Adapty Dashboard. 2. Activez le toggle et saisissez votre **Mixpanel Token**. Vous pouvez spécifier un token pour toutes les plateformes ou le limiter à certaines plateformes si vous souhaitez uniquement recevoir des données de celles-ci. 3. Définissez le **Mixpanel Data Residency** pour qu'il corresponde à votre projet Mixpanel. Ce champ est obligatoire et vaut **US** par défaut. Choisissez **US** pour l'endpoint `api.mixpanel.com` ou **Europe** pour `api-eu.mixpanel.com`. :::warning Si votre projet Mixpanel utilise la résidence des données en Europe, vous devez définir **Mixpanel Data Residency** sur **Europe**. Mixpanel rejette les événements envoyés vers l'endpoint US depuis des projets européens. ::: <img src="/assets/shared/img/mixpanel.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Trouver votre Mixpanel Token \{#finding-your-mixpanel-token\} Pour obtenir votre **Mixpanel Token** : 1. Connectez-vous à votre [Mixpanel Dashboard](https://mixpanel.com/settings/project/). 2. Ouvrez **Settings** et sélectionnez **Organization Settings**. <img src="/assets/shared/img/mixpanel-settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la barre latérale gauche, accédez à **Projects** et sélectionnez votre projet. <img src="/assets/shared/img/mixpanel-project-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Fonctionnement de l'intégration \{#how-the-integration-works\} Adapty mappe automatiquement les propriétés d'événements pertinentes — comme l'identifiant utilisateur et les revenus — vers les [propriétés natives de Mixpanel](https://docs.mixpanel.com/docs/data-structure/user-profiles). Cela garantit un suivi et des rapports précis des événements liés aux abonnements. De plus, Adapty cumule les données de revenus par utilisateur et met à jour leurs [User Profile Properties](https://docs.mixpanel.com/docs/data-structure/user-profiles), notamment `subscription state` et `subscription product ID`. Dès qu'un événement est reçu, Mixpanel met à jour les champs correspondants en temps réel. ## Événements et tags \{#events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à Mixpanel depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/mixpanel-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty. Vous pouvez toutefois les modifier selon vos besoins. ## Configuration du SDK \{#sdk-configuration\} Utilisez la méthode `.setIntegrationIdentifier()` pour définir le `mixpanelUserId`. Si cette valeur n'est pas renseignée, Adapty utilise votre identifiant utilisateur (`customerUserId`) ou, s'il est null, l'identifiant Adapty. Assurez-vous que l'identifiant utilisateur que vous envoyez à Mixpanel depuis votre application est identique à celui que vous envoyez à Adapty. :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "mixpanel_user_id", value: Mixpanel.mainInstance().distinctId ) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) Adapty.updateProfile(params: builder.build()) ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelAPI.distinctId) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final mixpanel = await Mixpanel.init("Your Token", trackAutomaticEvents: true); final distinctId = await mixpanel.getDistinctId(); try { await Adapty().setIntegrationIdentifier( key: "mixpanel_user_id", value: distinctId, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; var distinctId = Mixpanel.DistinctId; if (distinctId != null) { Adapty.SetIntegrationIdentifier( "mixpanel_user_id", distinctId, (error) => { // handle the error }); } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // If you already have a shared Mixpanel instance in your app, use that instance instead. const trackAutomaticEvents = true; const mixpanel = new Mixpanel('YOUR_PROJECT_TOKEN', trackAutomaticEvents); await mixpanel.init(); // This is Mixpanel's current distinct_id (auto-generated, or set via mixpanel.identify(...)) const mixpanelUserId = await mixpanel.getDistinctId(); try { await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Structure des événements Mixpanel \{#mixpanel-event-structure\} Adapty envoie les événements à Mixpanel via la méthode `track`. Les propriétés des événements sont structurées comme suit : ```json { "event": "subscription_renewed", "properties": { "ip": 0, "time": 1709294400, "$insert_id": "123e4567-e89b-12d3-a456-426614174000", "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383...", "currency": "USD", "environment": "Production", "store": "app_store", "purchase_date": "2024-03-01T12:00:00.000000+0000" } } ``` Où : | Paramètre | Type | Description | |:-------------------------------------|:--------|:---------------------------------------------------------| | `event` | String | Nom de l'événement (mappé depuis l'événement Adapty). | | `properties` | Object | Propriétés de l'événement. | | `properties.ip` | Integer | Adresse IP (envoyée à 0 en mode serveur à serveur). | | `properties.time` | Long | Horodatage UNIX de l'événement en secondes. | | `properties.$insert_id` | String | Identifiant unique de l'événement (UUID) pour la déduplication. | | `properties.vendor_product_id` | String | Identifiant du produit dans le store. | | `properties.original_transaction_id` | String | Identifiant de transaction original. | | `properties.currency` | String | Code de la devise. | | `properties.store` | String | Nom du store (ex. : "app_store"). | | `properties.environment` | String | Environnement ("Sandbox" ou "Production"). | ### Mises à jour du profil utilisateur \{#user-profile-updates\} Adapty met également à jour le profil utilisateur Mixpanel via `people_set` avec les propriétés suivantes : | Paramètre | Type | Description | |:--------------------------|:-------|:----------------------------------------------------------------| | `subscription_state` | String | État actuel de l'abonnement (ex. : "subscribed"). | | `subscription_product_id` | String | Identifiant du produit d'abonnement actif. | --- # File: posthog --- --- title: "PostHog" description: "" --- PostHog est une plateforme d'analyse qui fournit des outils pour suivre le comportement des utilisateurs, visualiser l'utilisation du produit et analyser la rétention. Avec des fonctionnalités comme le suivi d'événements, les flows utilisateurs et les feature flags, elle est conçue pour vous aider à mieux comprendre et améliorer votre produit. L'intégration de PostHog avec Adapty permet de suivre de manière transparente les événements liés aux abonnements, tels que les démarrages d'essai, les renouvellements et les annulations. En envoyant ces événements à PostHog, vous pouvez analyser comment les changements d'abonnement affectent le comportement des utilisateurs, évaluer les performances des paywalls et obtenir des informations plus approfondies sur vos stratégies de monétisation — le tout dans votre workflow d'analyse existant. ## Caractéristiques de l'intégration \{#integration-characteristics\} | Caractéristique de l'intégration | Description | | -------------------------------- | ------------------------------------------------------------ | | Planification | Temps réel ; les événements peuvent ne pas apparaître immédiatement sur le tableau de bord PostHog. | | Direction des données | Les événements Adapty sont envoyés du serveur Adapty au serveur PostHog. | | Point d'intégration Adapty | <ul><li> Les SDK PostHog et Adapty dans le code de l'application mobile</li><li> Le serveur Adapty</li></ul> | ## Structure des événements PostHog \{#posthog-event-structure\} Adapty envoie les événements sélectionnés à PostHog tels que configurés dans la section **Events names** de la [page d'intégration PostHog](https://app.adapty.io/integrations/posthog). Chaque événement est structuré comme suit : ```json showLineNumbers { "distinct_id": "john.doe@example.com", "timestamp": "2025-01-08T11:06:12+00:00", "event": "subscription_started", "properties": { "$set": { "email": "user@example.com", "first_name": "John", "last_name": "Doe", "birthday": "1990-01-01", "gender": "male", "os": "iOS" }, "timezone": "America/New_York", "ip_address": "10.168.1.1", "*": "{{other_event_properties}}" } } ``` Où | **Paramètre** | **Type** | **Description** | | --------------- | ---------------------------- | ------------------------------------------------------------ | | **distinct_id** | String | Identifiant unique de l'utilisateur (par ex., `profile.posthog_distinct_user_id`, `customer_user_id` ou `profile_id`). | | **timestamp** | Date et heure ISO 8601 | La date et l'heure de l'événement. | | **event** | String | Le nom de l'événement tel que vous l'avez défini dans la section Events names de la [configuration PostHog](https://app.adapty.io/integrations/posthog). | | **properties** | Object | Contient les [properties.$set](posthog#propertiesset-parameters) et toutes les [propriétés spécifiques à l'événement](messaging#event-properties). Chaque propriété est facultative et ne sera pas envoyée à PostHog si elle est manquante. | ### Paramètres properties.$set \{#propertiesset-parameters\} Chaque paramètre de l'objet `properties.$set` est facultatif et ne sera pas envoyé à PostHog s'il est manquant. | **Paramètre** | **Type** | **Description** | | --------------- | -------------- | ------------------------------------------------------------ | | **email** | String | Adresse e-mail de l'utilisateur. | | **first_name** | String | Prénom de l'utilisateur. | | **last_name** | String | Nom de famille de l'utilisateur. | | **birthday** | String (Date) | Date de naissance de l'utilisateur. | | **gender** | String | Genre de l'utilisateur. | | **os** | String | Système d'exploitation de l'appareil de l'utilisateur. | ## Configuration de l'intégration PostHog \{#setting-up-posthog-integration\} 1. Ouvrez la page [Integrations -> PostHog](https://app.adapty.io/integrations/posthog) dans l'Adapty Dashboard et activez le bouton. <img src="/assets/shared/img/posthog-on.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Connectez-vous au [PostHog Dashboard](https://posthog.com/). 3. Accédez à **Settings -> Project**. <img src="/assets/shared/img/posthog-settings.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la fenêtre **Project**, faites défiler jusqu'à la section **Project ID** et copiez la **Project API key**. 5. Collez la clé API dans le champ **Project API key** de l'Adapty Dashboard. PostHog ne dispose pas de mode Sandbox spécifique pour l'intégration serveur à serveur. 6. Choisissez votre **PostHog Deployment** : | Option | Description | | ------ | ------------------------------------------------------------ | | us/eu | Déploiements hébergés par PostHog par défaut. | | Custom | Pour les instances auto-hébergées. Saisissez l'URL de votre instance dans le champ **PostHog Instance URL**. | 7. (facultatif) Si vous utilisez un déploiement PostHog auto-hébergé, saisissez l'adresse de votre déploiement dans le champ **PostHog Instance URL**. 8. (facultatif) Ajustez les paramètres tels que **Reporting Proceeds**, **Exclude Historical Events**, **Report User's Currency** et **Send Trial Price**. Consultez les [paramètres d'intégration](configuration#integration-settings) pour plus de détails sur ces options. 9. (facultatif) Vous pouvez également personnaliser les événements envoyés à PostHog dans la section **Events names**. Désactivez les événements non souhaités ou renommez-les selon vos besoins. 10. Cliquez sur **Save** pour finaliser la configuration. ## Configuration du SDK \{#sdk-configuration\} Pour activer la réception des données d'attribution depuis PostHog, transmettez la valeur `distinctId` à Adapty comme indiqué ci-dessous : :::note Les SDK tiers génèrent des identifiants utilisateur de manière asynchrone. L'identifiant peut ne pas être disponible au moment où `Adapty.activate()` s'exécute. Si votre **Customer User ID** provient de l'un de ces SDK, appelez `Adapty.activate()` sans lui. Dès que l'identifiant est disponible, appelez `setIntegrationIdentifier()`, puis `identify()` avec le CUID. ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let distinctId = PostHogSDK.shared.getDistinctId() try await Adapty.setIntegrationIdentifier( key: "posthog_distinct_user_id", value: distinctId ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("posthog_distinct_user_id", PostHog.distinctId()) { error -> if (error != null) { // handle the error } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("posthog_distinct_user_id", PostHog.distinctId(), error -> { if (error != null) { // handle the error } }); ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers try { final distinctId = await Posthog().getDistinctId(); await Adapty().setIntegrationIdentifier( key: "posthog_distinct_user_id", value: distinctId, ); } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity" default> Il n'existe pas de SDK PostHog officiel pour Unity. </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... const posthog = usePostHog(); // ... try { await adapty.setIntegrationIdentifier("posthog_distinct_user_id", posthog.getDistinctId()); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> Adapty enverra désormais des événements à PostHog et recevra les attributions de celui-ci. --- # File: splitmetrics --- --- title: "SplitMetrics Acquire" description: "Utilisez SplitMetrics avec Adapty pour les tests A/B d'abonnements et leur optimisation." --- Avec l'intégration [SplitMetrics Acquire](https://splitmetrics.com/acquire/), vous pouvez voir exactement combien vos Apple Search Ads génèrent en revenus d'abonnements. Et vous pouvez suivre vos utilisateurs pendant des mois pour mesurer le rendement de vos publicités dans le temps. De plus, Adapty envoie des [événements d'abonnement](events) à SplitMetrics Acquire afin que vous puissiez y créer des tableaux de bord personnalisés et des automatisations, basés sur l'attribution Apple Search Ads. Cela n'ajoute aucune donnée d'attribution dans Adapty, car nous disposons déjà de tout ce dont nous avons besoin directement via ASA. ## Comment configurer l'intégration SplitMetrics Acquire \{#how-to-set-up-splitmetrics-acquire-integration\} Pour intégrer SplitMetrics Acquire, accédez à [Integrations > SplitMetrics Acquire](https://app.adapty.io/integrations/splitmetrics) et renseignez vos identifiants. <img src="/assets/shared/img/8255349-CleanShot_2023-08-14_at_17.39.422x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Ouvrez votre compte SplitMetrics Acquire, survolez l'un des logos MMP et cliquez sur le bouton **Settings**. Trouvez votre Client ID dans la boîte de dialogue sous l'élément **5**, copiez-le, puis collez-le dans Adapty en tant que **Client ID**. <img src="/assets/shared/img/4d0b2b6-Adapty.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/4f8d0b8-AdaptyGuide.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous devrez également renseigner votre Apple App ID pour utiliser l'intégration. Pour trouver votre App ID, ouvrez la page de votre app dans App Store Connect, accédez à la page **App Information** dans la section **General**, et repérez l'**Apple ID** en bas à gauche de l'écran. <img src="/assets/shared/img/61578ee-CleanShot_2022-04-20_at_17.55.03.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Événements et tags \{#events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à SplitMetrics Acquire depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/1b0c777-CleanShot_2023-08-11_at_14.56.362x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Nous recommandons d'utiliser les noms d'événements par défaut fournis par Adapty. Vous pouvez cependant les modifier selon vos besoins. Adapty enverra les événements d'abonnement à SplitMetrics Acquire via une intégration server-to-server, ce qui vous permettra de les consulter dans votre tableau de bord SplitMetrics. ## Configuration du SDK \{#sdk-configuration\} Aucune configuration côté SDK n'est nécessaire, mais nous recommandons d'envoyer le `customerUserId` à Adapty pour une meilleure précision. :::warning Assurez-vous d'avoir configuré [Apple Search Ads](apple-search-ads) dans Adapty et d'avoir [importé vos identifiants](https://app.adapty.io/settings/apple-search-ads) — sans cela, SplitMetrics Acquire ne fonctionnera pas. ::: ## Dépannage \{#troubleshooting\} Si l'intégration avec SplitMetrics Acquire ne fonctionne pas malgré une configuration correcte : - Assurez-vous d'avoir activé le bouton **Receive Apple Search Ads attribution in Adapty** dans l'onglet [App Settings -> Apple Search Ads](https://app.adapty.io/settings/apple-search-ads), d'avoir configuré [Apple Search Ads](apple-search-ads) dans Adapty et d'avoir [importé vos identifiants](https://app.adapty.io/settings/apple-search-ads) — sans cela, SplitMetrics ne fonctionnera pas. - Vérifiez que les profils disposent d'une attribution ASA non organique. Seuls les profils avec une attribution ASA détaillée et non organique transmettront leurs événements à Adapty. ## Structure des événements SplitMetrics Acquire \{#splitmetrics-acquire-event-structure\} Adapty envoie les événements à SplitMetrics Acquire via une requête GET en utilisant des paramètres de requête. Chaque événement est structuré comme suit : ```json { "source": "Apple Search Ads", "app_id": "123456789", "name": "subscription_renewed", "type": "subscription_renewed", "revenue": 9.99, "currency": "USD", "tap_time": "2024-03-01 12:00:00", "open_time": "2024-03-01 12:05:00", "event_time": "2024-03-02 12:00:00", "adaccount_id": "123456", "campaign_id": "123456789", "adgroup_id": "123456789", "keyword_id": "123456789", "creative_set_id": "123456789", "Ad_id": "123456789", "country_or_region": "US", "conversion_type": "Download", "user_id": "user_12345", "att_status": "3", "device_type": "iphone", "app_version": "1.2.3", "sdk_version": "2.10.0", "ios_version": "17.2", "event_value": "{\"vendor_product_id\":\"yearly.premium.6999\",\"original_transaction_id\":\"GPA.3383...\"}", "event_id": "123e4567-e89b-12d3-a456-426614174000" } ``` Où : | Paramètre | Type | Description | |:--------------------|:-------|:-----------------------------------------------------------------------------------------------------------------------------------| | `source` | String | Toujours "Apple Search Ads". | | `app_id` | String | Apple App ID. | | `name` | String | Nom de l'événement (mappé depuis l'événement Adapty). | | `type` | String | Type d'événement (identique à `name`). | | `revenue` | Float | Montant du revenu. | | `currency` | String | Code de devise. | | `tap_time` | String | Date et heure du clic sur la publicité. | | `open_time` | String | Date et heure de l'ouverture de l'app (installation). | | `event_time` | String | Date et heure de l'événement. | | `adaccount_id` | String | ID de l'organisation ASA. | | `campaign_id` | String | ID de la campagne ASA. | | `adgroup_id` | String | ID du groupe d'annonces ASA. | | `keyword_id` | String | ID du mot-clé ASA. | | `creative_set_id` | String | ID du jeu de créatifs ASA. | | `Ad_id` | String | ID de l'annonce ASA. | | `country_or_region` | String | Pays ou région du store. | | `conversion_type` | String | Type de conversion (ex. : "Download"). | | `user_id` | String | Customer User ID ou Adapty Profile ID. | | `att_status` | String | Statut d'autorisation du suivi (0-3). | | `device_type` | String | Type d'appareil (ex. : "iphone", "ipad"). | | `app_version` | String | Version de l'application. | | `sdk_version` | String | Version du SDK Adapty. | | `ios_version` | String | Version d'iOS. | | `event_value` | String | Chaîne JSON contenant tous les [détails de l'événement](webhook-event-types-and-fields#for-most-event-types) disponibles. | | `event_id` | String | Identifiant unique de l'événement (UUID). | --- # File: messaging --- --- title: "Intégrations de services de messagerie" description: "Utilisez les outils de messagerie d'Adapty pour améliorer l'engagement et la rétention des abonnements." --- L'acquisition n'est ni facile ni bon marché sur un marché mobile en pleine croissance. Bien traiter les utilisateurs attirés améliore donc votre économie unitaire, surtout dans les niches très concurrentielles. Adapty fournit des informations en temps réel sur les principales actions de paiement des utilisateurs. Nous savons quand votre client a démarré un essai, s'il a rencontré des problèmes de paiement, ou s'il a souscrit un abonnement avant de décider de l'annuler. Ces événements, et bien d'autres, reflètent un changement d'état du client. C'est le meilleur moment pour réagir : envoyer une offre, un cadeau personnalisé ou tout autre action de rétention. Les plateformes de notifications push permettent de décrire un utilisateur avec des tags standard et personnalisés afin de construire un système automatique de rétention efficace. Pour que ce système fonctionne, il suffit d'événements déclencheurs pour indiquer au système qu'il est temps d'envoyer un message. Ces événements arriveront sur la plateforme push depuis Adapty via l'intégration configurée. Choisissez ci-dessous le service à intégrer et suivez les instructions : - [Braze](braze) - [OneSignal](onesignal) - [Pushwoosh](pushwoosh) - [Slack](slack) :::note Vous ne trouvez pas votre fournisseur d'attribution ? Faites-le nous savoir ! [Créez une demande de fonctionnalité](https://adapty.featurebase.app/en?b=6979f233ebd3cffd4f425ba0) et nous envisagerons de l'ajouter. ::: ## Propriétés des événements \{#event-properties\} Les événements webhook sont envoyés au format JSON. Tous les événements suivent la même structure, mais leurs champs varient selon le type d'événement, le store et votre configuration spécifique. :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: | Propriété | Type | Description | | ----------------------------- | ------------- | ------------------------------------------------------------ | | **profile_id** | uuid | ID utilisateur Adapty. | | **currency** | str | Devise locale (USD par défaut). | | **price_usd** | float | Prix du produit avant la commission Apple/Google. Revenu. | | **proceeds_usd** | float | Prix du produit après la commission Apple/Google. Revenu net. | | **net_revenue_usd** | float | Revenu net (revenu après commission Apple/Google et taxes) en USD. Peut être vide. | | **price_local** | float | Prix du produit avant la commission Apple/Google en devise locale. Revenu. | | **proceeds_local** | float | Prix du produit après la commission Apple/Google en devise locale. Revenu net. | | **transaction_id** | str | Identifiant unique d'une transaction, comme un achat ou un renouvellement. | | **original_transaction_id** | str | Identifiant de transaction de l'achat d'origine. | | **purchase_date** | ISO 8601 date | Date et heure d'achat du produit. | | **original_purchase_date** | ISO 8601 date | Date et heure de l'achat d'origine. | | **environment** | str | Peut être _Sandbox_ ou _Production_. | | **vendor_product_id** | str | ID du produit sur l'Apple App Store, le Google Play Store ou Stripe. | | **base_plan_id** | str | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) sur le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) sur Stripe. | | **event_datetime** | ISO 8601 date | Date et heure de l'événement. | | **store** | str | Peut être _app_store_ ou _play_store_. | | **trial_duration** | str | Durée de la période d'essai en jours. Envoyée au format "{} days", par exemple "7 days". | | **cancellation_reason** | str | <p>Raison pour laquelle l'utilisateur a annulé son abonnement.</p><p></p><p>Peut être</p><p>iOS & Android</p><p>_voluntarily_cancelled_, _billing_error_, _refund_</p><p>iOS</p><p>_price_increase_, _product_was_not_available_, _unknown_</p><p>Android</p><p>_new_subscription_replace_, _cancelled_by_developer_</p> | | **subscription_expires_at** | ISO 8601 date | Date d'expiration de l'abonnement. Généralement dans le futur. | | **consecutive_payments** | int | Nombre de périodes pendant lesquelles l'utilisateur est abonné sans interruption. Inclut la période en cours. | | **rate_after_first_year** | bool | Booléen indiquant que l'abonnement est éligible à un taux de commission réduit (généralement 15 %) après un an de renouvellement continu. Les taux de commission varient selon l'éligibilité au programme et le pays. Voir [Commission du store et taxes](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) pour plus de détails. | | **promotional_offer_id** | str | ID de l'offre promotionnelle tel qu'indiqué dans la section Produit de l'Adapty Dashboard. | | **store_offer_category** | str | Peut être _introductory_ ou _promotional_. | | **store_offer_discount_type** | str | Peut être _free_trial_, _pay_as_you_go_ ou _pay_up_front_. | | **paywall_name** | str | Nom du paywall d'où provient la transaction. | | **paywall_revision** | int | Révision du paywall d'où provient la transaction. La valeur est définie à 1. | | **developer_id** | str | ID développeur (SDK) du placement d'où provient la transaction. | | **ab_test_name** | str | Nom du test A/B d'où provient la transaction. | | **ab_test_revision** | int | Révision du test A/B d'où provient la transaction. La valeur est définie à 1. | | **cohort_name** | str | Nom de l'audience à laquelle appartient le profil. | | **profile_event_id** | uuid | ID d'événement unique pouvant être utilisé pour la déduplication. | | **store_country** | str | Le pays transmis par le store. | | **profile_ip_address** | str | IP du profil (peut être IPv4 ou IPv6, IPv4 étant préférée si disponible). Mise à jour à chaque changement d'IP de l'appareil. | | **profile_country** | str | Déterminé par Adapty, à partir de l'IP du profil. | | **profile_total_revenue_usd** | float | Revenu total pour le profil, remboursements inclus. | | **variation_id** | uuid | ID unique du paywall où l'achat a été effectué. | | **access_level_id** | str | ID du niveau d'accès payant. | | **is_active** | bool | Booléen indiquant si le niveau d'accès payant est actif pour le profil. | | **will_renew** | bool | Booléen indiquant si le niveau d'accès payant sera renouvelé. | | **is_refund** | bool | Booléen indiquant si la transaction est remboursée. | | **is_lifetime** | bool | Booléen indiquant si le niveau d'accès payant est à vie. | | **is_in_grace_period** | bool | Booléen indiquant si le profil est en délai de grâce. | | **starts_at** | ISO 8601 date | Date et heure auxquelles le niveau d'accès payant démarre pour l'utilisateur. | | **renewed_at** | ISO 8601 date | Date et heure auxquelles l'accès payant sera renouvelé. | | **expires_at** | ISO 8601 date | Date et heure auxquelles l'accès payant expirera. | | **activated_at** | ISO 8601 date | Date et heure auxquelles l'accès payant a été activé. | | **billing_issue_detected_at** | ISO 8601 date | Date et heure du problème de facturation. | | **profile_has_access_level** | Bool | Booléen indiquant si le profil dispose d'un niveau d'accès actif (webhook uniquement). | Chaque événement possède les propriétés suivantes : `transaction_id, original_transaction_id, purchase_date, original_purchase_date, environment, vendor_product_id, event_datetime, store`. De plus, certains événements ont des propriétés supplémentaires. Pour les événements `subscription_refunded` et `non_subscription_purchase_refunded`, il est obligatoire de fournir les valeurs de `price_usd` et `proceeds_usd` comme propriétés supplémentaires. | Nom de l'événement | Propriétés | | :---------------------------------- | :----------------------------------------------------------- | | **subscription\_initial\_purchase** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **subscription\_renewed** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **subscription\_cancelled** | cancellation\_reason, trial\_duration | | **trial\_started** | subscription\_expires\_at, trial\_duration | | **trial\_converted** | price\_usd, proceeds\_usd, subscription\_expires\_at, consecutive\_payments, rate\_after\_first\_year, trial\_duration | | **trial\_cancelled** | cancellation\_reason, trial\_duration | | **non\_subscription\_purchase** | price\_usd, proceeds\_usd | | **billing\_issue\_detected** | subscription\_expires\_at, trial\_duration | | **entered\_grace\_period** | subscription\_expires\_at, trial\_duration | Exemple d'événement ```json title="Json" { "price_usd": 9.99, "proceeds_usd": 6.99, "transaction_id": "1000000628581600", "original_transaction_id": "1000000628581600", "purchase_date": "2020-02-18T18:40:22.000000+0000", "original_purchase_date": "2020-02-18T18:40:22.000000+0000", "environment": "Sandbox", "vendor_product_id": "premium", "event_datetime": "2020-02-18T18:40:22.000000+0000", "store": "app_store" } ``` Adapty envoie les événements à votre serveur et aux systèmes analytiques tiers. La propriété **profile_ip_address** est synchronisée avec l'IP actuelle de l'appareil. Chaque fois que les serveurs Adapty reçoivent des informations du SDK, l'IP est mise à jour si elle diffère de celle enregistrée. --- # File: braze --- --- title: "Braze" description: "Intégrez Braze avec Adapty pour un engagement client et des notifications push sans friction." --- En tant que l'une des meilleures solutions d'engagement client, [Braze](https://www.braze.com/) propose un large éventail d'outils pour les notifications push, l'e-mail, le SMS et la messagerie in-app. En intégrant Adapty à Braze, vous accédez facilement à tous vos événements d'abonnement au même endroit, ce qui vous permet de déclencher des communications automatisées en fonction de ces événements. Adapty fournit un ensemble complet de données pour suivre les [événements d'abonnement](events) de tous les stores au même endroit, et peut être utilisé pour mettre à jour les profils de vos utilisateurs dans Braze. Avec Adapty, vous pouvez facilement observer le comportement de vos abonnés, comprendre leurs préférences et utiliser ces informations pour communiquer avec eux de manière ciblée et efficace. Cette intégration vous permet donc de suivre les événements d'abonnement dans votre tableau de bord Braze et de les associer à vos [campagnes d'acquisition.](https://www.braze.com/product/journey-orchestration) Adapty envoie les événements d'abonnement, les propriétés utilisateur et les achats vers Braze, afin que vous puissiez construire une communication ciblée avec vos clients via les notifications push Braze, après une intégration simple et rapide comme décrit ci-dessous. ## Comment configurer l'intégration Braze \{#how-to-set-up-braze-integration\} Pour intégrer Braze, rendez-vous dans [Integrations -> Braze](https://app.adapty.io/integrations/braze), activez le bouton et remplissez les champs. La première étape du processus d'intégration consiste à fournir les identifiants nécessaires pour établir une connexion entre vos profils Braze et Adapty. Vous aurez besoin de la **REST API Key**, de votre **Braze Instance ID** et des **App IDs** iOS et Android pour que l'intégration fonctionne correctement : <img src="/assets/shared/img/5f1e62c-adapty_braze.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. La **REST API Key** peut être créée dans **Braze Dashboard** → **Settings** → **API Keys**. Assurez-vous que votre clé dispose de la permission `users.track` lors de sa création : <img src="/assets/shared/img/b5fdf16-adapty_braze_create_api_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/1e5b4b8-adapty_braze_api_key_users_track.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Pour obtenir le **Braze Instance ID**, notez l'URL de votre Braze Dashboard et consultez la section de la [documentation Braze](https://www.braze.com/docs/api/basics/#endpoints) où l'ID d'instance est indiqué. Il doit avoir un format régional tel que US-03, EU-01, etc. 3. Les App IDs iOS et Android se trouvent également dans Braze Dashboard → Settings → API Keys. Copiez-les depuis ici : <img src="/assets/shared/img/1e6d21b-adapty_braze_app_ids.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Événements, attributs utilisateur et achats \{#events-user-attributes-and-purchases\} Sous les identifiants, trois groupes d'événements peuvent être envoyés à Braze depuis Adapty. Activez simplement ceux dont vous avez besoin. Vous pouvez également renommer les événements selon vos besoins avant de les envoyer à Braze. Consultez la liste complète des événements proposés par Adapty [ici](events) : <img src="/assets/shared/img/702e628-adapty_braze_events_names.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty enverra les événements d'abonnement et les attributs utilisateur à Braze via une intégration server-to-server, ce qui vous permettra de les consulter dans votre Braze Dashboard et de configurer des campagnes en conséquence. Pour les événements avec revenus, comme les conversions d'essai et les renouvellements, Adapty enverra ces informations à Braze sous forme d'achats. [Ici](messaging#event-properties), vous trouverez les spécifications complètes des propriétés d'événements envoyées à Braze. :::note Attributs utilisateur utiles Adapty envoie par défaut certains attributs utilisateur pour l'intégration Braze. Vous pouvez vous référer à la liste ci-dessous pour déterminer lesquels correspondent le mieux à vos besoins. ::: | Attribut utilisateur | Type | Valeur | |--------------|----|-----| | `adapty_customer_user_id` | String | Contient la valeur de l'identifiant unique de l'utilisateur défini par le client. Peut être trouvé à la fois dans le [Dashboard](profiles-crm) Adapty et dans Braze. | | `adapty_profile_id` | String | Contient la valeur de l'identifiant unique Adapty User Profile ID de l'utilisateur, qui peut être trouvé dans le [Dashboard](profiles-crm) Adapty. | | `environment` | String | <p>Indique si l'utilisateur opère dans un environnement sandbox ou de production.</p><p></p><p>Les valeurs sont soit `Sandbox`, soit `Production`</p> | | `store` | String | <p>Contient le nom du Store utilisé pour effectuer l'achat.</p><p></p><p>Valeurs possibles :</p><p>`app_store` ou `play_store`.</p> | | `vendor_product_id` | String | <p>Contient la valeur de l'ID de produit dans le store Apple/Google.</p><p></p><p>ex. : org.locals.12345</p> | | `subscription_expires_at` | String | <p>Contient la date d'expiration du dernier abonnement.</p><p></p><p>Le format de la valeur est :</p><p>YYYY-MM-DDTHH:mm:ss.SSS+TZ</p><p>ex. : 2023-02-15T17:22:03.000+0000</p> | | `active_subscription` | String | La valeur sera définie à `true` lors de tout événement d'achat/renouvellement, ou `false` si l'abonnement est expiré. | | `period_type` | String | <p>Indique le dernier type de période pour l'achat ou le renouvellement.</p><p></p><p>Les valeurs possibles sont</p><p>`trial` pour une période d'essai ou `normal` pour le reste.</p> | Toutes les valeurs flottantes seront arrondies à l'entier. Les chaînes restent inchangées. En plus de la liste prédéfinie de tags disponibles, il est possible d'envoyer des [attributs personnalisés](segments#custom-attributes) via des tags. Cela offre plus de flexibilité dans le type de données pouvant être incluses dans le tag et peut être utile pour suivre des informations spécifiques liées à un produit ou un service. Tous les attributs utilisateur personnalisés sont envoyés automatiquement à Braze si l'utilisateur coche la case **Send user attributes** sur [la page d'intégration](https://app.adapty.io/integrations/braze). ## Configuration du SDK \{#sdk-configuration\} Pour lier les profils utilisateur dans Adapty et Braze, vous devez soit configurer le SDK Braze avec le même identifiant utilisateur client que dans Adapty, soit utiliser sa méthode `.changeUser()` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers let braze = Braze(configuration: configuration) braze.changeUser(userId: "adapty_customer_user_id") ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Braze.getInstance(context).changeUser("adapty_customer_user_id") ``` </TabItem> </Tabs> --- # File: onesignal --- --- title: "OneSignal" description: "Intégrez OneSignal avec Adapty pour améliorer l'engagement par notifications push." --- [OneSignal](https://onesignal.com/) est une plateforme d'engagement client de premier plan proposant des notifications push, des e-mails, des SMS et des messages in-app. L'intégration d'Adapty avec OneSignal vous permet de centraliser tous vos événements d'abonnement, et ainsi de déclencher des communications automatisées en réponse à ces événements. Avec Adapty, vous pouvez suivre les [événements d'abonnement](events) sur plusieurs stores, analyser le comportement des utilisateurs et exploiter ces données pour des communications plus ciblées. Cette intégration vous permet de surveiller les événements d'abonnement depuis votre tableau de bord OneSignal et de les associer à vos [campagnes d'acquisition](https://documentation.onesignal.com/docs/en/automated-messages). Adapty met à jour les tags OneSignal en fonction des événements d'abonnement, ce qui vous permet d'envoyer des notifications push personnalisées avec une configuration minimale. **Caractéristiques de l'intégration** | Caractéristique | Description | | :------------------------- | :----------------------------------------------------------- | | Fréquence | Mises à jour en temps réel | | Direction des données | Unidirectionnelle : d'Adapty vers le serveur OneSignal | | Point d'intégration Adapty | <ul><li>SDK OneSignal et Adapty dans le code de l'application mobile</li><li>Serveur Adapty</li></ul>| ## Configurer l'intégration OneSignal \{#setting-up-one-signal-integration\} Pour configurer l'intégration : 1. Ouvrez [Integrations → OneSignal](https://app.adapty.io/integrations/onesignal) dans votre Adapty Dashboard. <img src="/assets/shared/img/onesignal-on.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Activez le bouton de l'intégration. 3. Saisissez votre **OneSignal App ID**. Pour configurer l'intégration avec OneSignal, accédez à [Integrations -> OneSignal](https://app.adapty.io/integrations/onesignal) dans votre Adapty Dashboard, activez le bouton et configurez les identifiants de l'intégration. ## Récupérer votre OneSignal App ID \{#retrieving-your-onesignal-app-id\} Trouvez votre **OneSignal App ID** dans votre [OneSignal Dashboard](https://dashboard.onesignal.com/login) : 1. Accédez à **Settings** → **Keys & IDs**. <img src="/assets/shared/img/onesignal-dashboard.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Copiez votre **OneSignal App ID** et collez-le dans le champ **App ID** de l'Adapty Dashboard. <img src="/assets/shared/img/onesignal-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous trouverez plus d'informations sur l'identifiant OneSignal dans la [documentation suivante](https://documentation.onesignal.com/docs/en/keys-and-ids). ### Configurer les événements \{#configuring-events\} Adapty vous permet d'envoyer trois groupes d'événements à OneSignal. Activez ceux dont vous avez besoin dans l'Adapty Dashboard. Vous pouvez consulter la liste complète des événements disponibles avec leur description détaillée [ici](events). <img src="/assets/shared/img/onesignal.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty envoie les événements d'abonnement à OneSignal via une intégration serveur-à-serveur, vous permettant de suivre toute l'activité liée aux abonnements dans OneSignal. :::warning À partir du 17 avril 2023, le plan gratuit de OneSignal ne prend plus en charge cette intégration. Elle est disponible uniquement sur les plans **Growth**, **Professional** et **supérieurs**. Pour plus de détails, consultez les [tarifs OneSignal](https://onesignal.com/pricing). ::: ## Tags personnalisés \{#custom-tags\} Cette intégration met à jour et attribue diverses propriétés à vos utilisateurs Adapty sous forme de tags, qui sont ensuite envoyés à OneSignal. Consultez la liste des tags ci-dessous pour trouver ceux qui correspondent le mieux à vos besoins. :::warning OneSignal impose une limite de tags. Cela inclut les tags générés par Adapty et tous les tags existants dans OneSignal. Dépasser cette limite peut provoquer des erreurs lors de l'envoi des événements. ::: | Tag | Type | Description | |---|----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `adapty_customer_user_id` | String | L'identifiant unique de l'utilisateur dans votre application. Il doit être cohérent dans votre système, Adapty et OneSignal. | | `adapty_profile_id` | String | L'identifiant de profil utilisateur Adapty, disponible dans votre [Adapty Dashboard](profiles-crm). | | `environment` | String | `Sandbox` ou `Production`, indiquant l'environnement actuel de l'utilisateur. | | `store` | String | Store où le produit a été acheté. Options : **app_store**, **play_store**, **stripe**, ou le nom de votre [store personnalisé](custom-store). | | `vendor_product_id` | String | L'identifiant du produit dans l'app store (ex. : `org.locals.12345`). | | `subscription_expires_at` | String | Date d'expiration du dernier abonnement (`YYYY-MM-DDTHH:MM:SS+0000`, ex. : `2023-02-10T17:22:03.000000+0000`). | | `last_event_type` | String | Le dernier type d'événement de la [liste d'événements Adapty](events).<br/> Remarques :<br/>- Pour l'événement **Subscription expired**, Adapty envoie la propriété `last_event_type` avec la valeur `subscription_cancelled`.<br/>- Pour **Trial renew canceled** – `auto_renew_off`<br/>- Pour **Subscription renew canceled** – `auto_renew_off_subscription` | | `purchase_date` | String | Date de la dernière transaction (`YYYY-MM-DDTHH:MM:SS+0000`, ex. : `2023-02-10T17:22:03.000000+0000`). | | `active_subscription` | String | `true` si l'utilisateur a un abonnement actif, `false` si l'abonnement a expiré. | | `period_type` | String | Indique le type de période le plus récent pour l'achat ou le renouvellement. Valeurs possibles : `trial` pour une période d'essai ou `normal` pour tous les autres cas. | Toutes les valeurs de type float sont arrondies à des entiers. Les chaînes de caractères restent inchangées. En plus des tags prédéfinis, vous pouvez envoyer des [attributs personnalisés](segments#custom-attributes) sous forme de tags, offrant ainsi plus de flexibilité dans les données que vous incluez. Cela est utile pour suivre des détails spécifiques liés à votre produit ou service. Les attributs utilisateur personnalisés sont automatiquement envoyés à OneSignal si la case **Send user attributes** est cochée sur la [page d'intégration](https://app.adapty.io/integrations/onesignal). Lorsqu'elle est décochée, Adapty envoie exactement 10 tags. Si elle est cochée, plus de 10 tags peuvent être envoyés, permettant une collecte de données enrichie. ## Configuration du SDK \{#sdk-configuration\} Il existe deux façons d'intégrer OneSignal avec Adapty : 1. **Ancienne version (pré-v5) :** Utilise `playerId` (obsolète depuis le [SDK OneSignal v5](https://github.com/OneSignal/OneSignal-iOS-SDK/releases/tag/5.0.0)). 2. **Version actuelle (v5+) :** Utilise `subscriptionId`. :::warning Assurez-vous d'envoyer `playerId` (pour le SDK OneSignal pré-v5) ou `subscriptionId` (pour le SDK OneSignal v5+) à Adapty. Sans cela, les tags OneSignal ne seront pas mis à jour et l'intégration ne fonctionnera pas correctement. ::: <Tabs groupId="current-version" queryString> <TabItem value="v5+" label="OneSignal SDK v5+ (current)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers // SubscriptionID OneSignal.Notifications.requestPermission({ accepted in Task { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.oneSignalSubscriptionId(OneSignal.User.pushSubscription.id)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "one_signal_subscription_id", value: OneSignal.User.pushSubscription.id ) } }, fallbackToSettings: true) ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // SubscriptionID val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver { override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) { Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.current.id) { error -> if (error != null) { // handle the error } } } } ``` </TabItem> <TabItem value="java" label="(Android) Java" default> ```java showLineNumbers // SubscriptionID IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> { Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.getCurrent().getId(), error -> { if (error != null) { // handle the error } }); }; ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers // 1. Since OneSignal.User.pushSubscription.id may return null if called too early, // OneSignal suggests to listen for the updates: OneSignal.User.pushSubscription.addObserver((state) { if (state.current.optedIn) { // now you can try to retrieve subscriptionId } }); // 2. Then you can push subscriptionId to Adapty: final subscriptionId = OneSignal.User.pushSubscription.id; if (subscriptionId != null) { await Adapty().setIntegrationIdentifier(key: "one_signal_subscription_id", value: subscriptionId); } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; using OneSignalSDK; var pushUserId = OneSignal.Default.PushSubscriptionState.userId; Adapty.SetIntegrationIdentifier( "one_signal_player_id", pushUserId, (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers OneSignal.User.pushSubscription.addEventListener('change', (subscription) => { const subscriptionId = subscription.current.id; if (subscriptionId) { adapty.setIntegrationIdentifier("one_signal_subscription_id", subscriptionId); } }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="pre-v5" label="OneSignal SDK v. up to 4.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers // PlayerID // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { Task { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.oneSignalPlayerId(playerId)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "one_signal_player_id", value: playerId ) } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // PlayerID val osSubscriptionObserver = OSSubscriptionObserver { stateChanges -> stateChanges?.to?.userId?.let { playerId -> Adapty.setIntegrationIdentifier("one_signal_player_id", playerId) { error -> if (error != null) { // handle the error } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers // PlayerID OSSubscriptionObserver osSubscriptionObserver = stateChanges -> { OSSubscriptionState to = stateChanges != null ? stateChanges.getTo() : null; String playerId = to != null ? to.getUserId() : null; if (playerId != null) { Adapty.setIntegrationIdentifier("one_signal_player_id", playerId, error -> { if (error != null) { // handle the error } }); } }; ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers // PlayerID (pre-v5 OneSignal SDK) // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { Task { try await Adapty.setIntegrationIdentifier( key: "one_signal_player_id", value: playerId ) } } } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers OneSignal.addSubscriptionObserver(event => { const playerId = event.to.userId; adapty.setIntegrationIdentifier("one_signal_player_id", playerId); }); ``` </TabItem> </Tabs> </TabItem> </Tabs> Pour en savoir plus, consultez la documentation OneSignal : - [Identifiant d'abonnement push](https://documentation.onesignal.com/docs/en/mobile-sdk-reference#user-pushsubscription-id) - [Changements d'abonnement push](https://documentation.onesignal.com/docs/en/mobile-sdk-reference#addobserver-push-subscription-changes) ## Gérer plusieurs appareils \{#dealing-with-multiple-devices\} Lorsqu'un utilisateur possède plusieurs appareils, le suivi des événements d'achat et des abonnements peut s'avérer complexe. OneSignal propose une solution via les [identifiants utilisateur externes](https://documentation.onesignal.com/docs/en/users). Pour maintenir la cohérence des données utilisateur sur tous les appareils : 1. Faites correspondre les différents appareils côté **serveur** et envoyez ces données à OneSignal. 2. Utilisez le [customer_user_id](identifying-users) d'Adapty comme [externalUserId](https://documentation.onesignal.com/docs/en/users#external-id) dans OneSignal. Si votre application ne dispose pas de système d'inscription, envisagez d'utiliser un autre identifiant unique qui reste cohérent sur tous les appareils de l'utilisateur. Il est important de maintenir la cohérence de l'identifiant utilisateur sur tous les appareils et de mettre à jour OneSignal à chaque changement d'ID d'un utilisateur. Cela simplifie le suivi de l'activité et des abonnements des utilisateurs tout en garantissant une messagerie cohérente, et permet des analyses plus précises ainsi qu'une meilleure expérience utilisateur. Pour plus de détails, consultez la [documentation de OneSignal sur les identifiants utilisateur externes](https://documentation.onesignal.com/docs/en/users). --- # File: pushwoosh --- --- title: "Pushwoosh" description: "Intégrez Pushwoosh avec Adapty pour un suivi fluide des notifications push." --- Adapty utilise les événements d'abonnement pour mettre à jour les tags de profil [Pushwoosh](https://www.pushwoosh.com/), ce qui vous permet de créer des communications ciblées avec vos clients via des notifications push après une configuration d'intégration rapide et simple, comme décrit ci-dessous. ## Comment configurer l'intégration Pushwoosh \{#how-to-set-up-pushwoosh-integration\} Pour intégrer Pushwoosh, rendez-vous dans [**Integrations** -> **Pushwoosh**](https://app.adapty.io/integrations/pushwoosh), activez le bouton et remplissez les champs. Commencez par renseigner les identifiants pour établir la connexion entre vos profils Pushwoosh et Adapty. L'App ID Pushwoosh et le token d'authentification sont obligatoires. <img src="/assets/shared/img/64e48a1-CleanShot_2023-08-18_at_11.13.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. L'**App ID** se trouve dans votre tableau de bord Pushwoosh. <img src="/assets/shared/img/ee27687-CleanShot_2023-08-18_at_14.37.442x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. L'**Auth token** se trouve dans la section API Access des paramètres Pushwoosh. <img src="/assets/shared/img/50e634b-CleanShot_2023-08-18_at_14.35.022x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Événements et tags \{#events-and-tags\} Sous les identifiants, vous trouverez trois groupes d'événements que vous pouvez envoyer à Pushwoosh depuis Adapty. Activez simplement ceux dont vous avez besoin. Vous pouvez également renommer les événements selon vos besoins avant de les envoyer à Pushwoosh. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/392dc31-screencapture-app-adapty-io-integrations-pushwoosh-2023-08-22-13_31_07.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty enverra les événements d'abonnement à Pushwoosh via une intégration serveur à serveur, ce qui vous permettra de consulter tous les événements d'abonnement dans votre Pushwoosh Dashboard. :::note Tags personnalisés Avec Adapty, vous pouvez également utiliser vos propres tags personnalisés pour l'intégration Pushwoosh. Vous pouvez vous référer à la liste de tags ci-dessous pour déterminer lequel convient le mieux à vos besoins. ::: | Tag | Type | Valeur | |---|----|-----| | `adapty_customer_user_id` | String | Contient la valeur de l'identifiant unique de l'utilisateur, qui peut être trouvé côté Pushwoosh. | | `adapty_profile_id` | String | Contient la valeur de l'identifiant unique du profil utilisateur Adapty, que vous pouvez retrouver dans votre [tableau de bord](profiles-crm) Adapty. | | `environment` | String | <p>Indique si l'utilisateur opère dans un environnement sandbox ou de production.</p><p></p><p>Les valeurs possibles sont `Sandbox` ou `Production`.</p> | | `store` | String | <p>Contient le nom du store utilisé pour effectuer l'achat.</p><p></p><p>Valeurs possibles :</p><p>`app_store` ou `play_store`.</p> | | `vendor_product_id` | String | <p>Contient la valeur de l'ID produit dans le store Apple/Google.</p><p></p><p>Ex. : org.locals.12345</p> | | `subscription_expires_at` | String | <p>Contient la date d'expiration du dernier abonnement.</p><p></p><p>Format de la valeur :</p><p>année-mois jourTheure:minute:seconde</p><p>Ex. : 2023-02-10T17:22:03.000000+0000</p> | | `last_event_type` | String | Indique le type du dernier événement reçu parmi les [événements Adapty](events) standard que vous avez activés pour l'intégration. | | `purchase_date` | String | <p>Contient la date de la dernière transaction (achat initial ou renouvellement).</p><p></p><p>Format de la valeur :</p><p>année-mois jourTheure:minute:seconde</p><p>Ex. : 2023-02-10T17:22:03.000000+0000</p> | | `original_purchase_date` | String | <p>Contient la date du premier achat selon la transaction.</p><p></p><p>Format de la valeur :</p><p>année-mois jourTheure:minute:seconde</p><p>Ex. : 2023-02-10T17:22:03.000000+0000</p> | | `active_subscription` | String | La valeur sera définie sur `true` lors de tout événement d'achat ou de renouvellement, ou sur `false` si l'abonnement est expiré. | | `period_type` | String | <p>Indique le dernier type de période pour l'achat ou le renouvellement.</p><p></p><p>Valeurs possibles :</p><p>`trial` pour une période d'essai ou `normal` pour le reste.</p> | Toutes les valeurs flottantes seront arrondies à des entiers. Les chaînes restent inchangées. En plus de la liste prédéfinie de tags disponibles, il est possible d'envoyer des [attributs personnalisés](segments#custom-attributes) via des tags. Cela offre plus de flexibilité dans le type de données pouvant être incluses avec le tag et peut s'avérer utile pour suivre des informations spécifiques liées à un produit ou service. Tous les attributs utilisateur personnalisés sont envoyés automatiquement à Pushwoosh si l'utilisateur coche la case **Send user custom attributes** sur [la page d'intégration](https://app.adapty.io/integrations/pushwoosh). ## Configuration du SDK \{#sdk-configuration\} Pour relier Adapty à Pushwoosh, vous devez nous envoyer la valeur `HWID` : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "pushwoosh_hwid", value: Pushwoosh.sharedInstance().getHWID() ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().hwid) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().getHwid(), error -> { if (error != null) { // handle the error } }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final hwid = await Pushwoosh.getInstance.getHWID; try { await Adapty().setIntegrationIdentifier( key: "pushwoosh_hwid", value: hwid, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "pushwoosh_hwid", Pushwoosh.Instance.HWID, (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... try { await adapty.setIntegrationIdentifier("pushwoosh_hwid", hwid); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> --- # File: slack --- --- title: "Slack" description: "Intégrez Slack avec Adapty pour recevoir des notifications en temps réel sur les événements d'abonnement." --- [Slack](https://slack.com/) est une messagerie d'entreprise et une plateforme de productivité qui ne nécessite probablement pas de présentation. Grâce à cette intégration, vous serez notifié dans Slack chaque fois qu'un événement de revenu est enregistré par Adapty. C'est utile si vous aimez célébrer chaque augmentation de votre MRR, ou si vous souhaitez surveiller les annulations d'essai, les problèmes de facturation, les remboursements, et bien plus encore. ## Comment configurer l'intégration Slack \{#how-to-set-up-slack-integration\} Vous devrez : - créer une application dans votre espace de travail Slack - lui donner la permission de publier des messages - puis fournir les informations nécessaires à Adapty dans [Integrations → Slack](https://app.adapty.io/integrations/slack). ### 1\. Créer une application dans Slack \{#1-create-an-app-in-slack\} 1. Rendez-vous sur le [tableau de bord de l'API Slack](https://api.slack.com/apps) et créez une application comme suit : <img src="/assets/shared/img/f43aedc-CleanShot_2024-01-04_at_18.27.412x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/08fa9e6-CleanShot_2024-01-04_at_18.28.142x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Donnez-lui un nom quelconque (`Adapty` par exemple) et ajoutez-la à votre espace de travail : <img src="/assets/shared/img/5002bb1-CleanShot_2024-01-04_at_18.29.132x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 2\. Accorder la permission de publier et obtenir un token pour votre application \{#2-give-permission-to-post-and-get-a-token-for-your-app\} Vous serez redirigé vers la page de votre application dans Slack. 1. Faites défiler vers le bas et cliquez sur **Permissions** : <img src="/assets/shared/img/9750451-CleanShot_2024-01-04_at_18.48.072x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Après la redirection, faites défiler vers le bas jusqu'à **Scopes** et cliquez sur **Add an OAuth Scope** : <img src="/assets/shared/img/db5b5f4-CleanShot_2024-01-04_at_18.50.262x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Accordez les permissions `chat:write`, `chat:write.public` et `chat:write.customize`. Celles-ci sont nécessaires pour publier dans vos canaux et personnaliser les messages : <img src="/assets/shared/img/d97ccb9-CleanShot_2024-01-04_at_18.51.572x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Remontez en haut de la page et cliquez sur **Install to Workspace** : <img src="/assets/shared/img/14608e3-CleanShot_2024-01-04_at_19.17.58.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Allow** ici : <img src="/assets/shared/img/143967e-CleanShot_2024-01-04_at_18.53.292x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Après cela, vous serez redirigé vers la même page, mais un token OAuth sera disponible (`xoxb-...`). C'est exactement ce qu'il faut pour finaliser la configuration : <img src="/assets/shared/img/59b33ee-CleanShot_2024-01-04_at_18.55.222x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 3\. Configurer l'intégration dans Adapty \{#3-configure-the-integration-in-adapty\} 1. Rendez-vous dans [**Integrations** → **Slack**](https://app.adapty.io/integrations/slack) : <img src="/assets/shared/img/b4ffd71-CleanShot_2024-01-04_at_19.05.222x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Collez le token `xoxb-...` de l'étape précédente et choisissez les canaux dans lesquels l'application publiera. Vous pouvez configurer l'intégration pour recevoir les événements uniquement en production, en sandbox, ou dans les deux environnements. Vous pouvez également choisir la devise dans laquelle publier (devise d'origine ou convertie en USD). :::note Si vous souhaitez que les messages d'Adapty soient publiés dans un canal privé, vous devrez ajouter manuellement l'application `Adapty` que vous avez créée dans Slack à ce canal. Sans cela, cela ne fonctionnera pas. ::: 3. Enfin, vous pouvez choisir les événements que vous souhaitez recevoir sous **Events** : <img src="/assets/shared/img/970a7bb-CleanShot_2024-01-04_at_19.09.472x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Tout est prêt ! Les événements seront envoyés dans les canaux que vous avez spécifiés. Vous pourrez voir le revenu lorsque cela est applicable et consulter le profil client dans Adapty : <img src="/assets/shared/img/852b8c8-CleanShot_2024-01-04_at_19.11.332x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: webhook-and-etl --- --- title: "Webhook et intégrations ETL" description: "Configurez l'intégration webhook et ETL pour un suivi avancé des événements d'abonnement." --- Consultez les guides étape par étape d'Adapty pour intégrer le SDK Adapty avec les options webhook et ETL telles qu'Amazon S3 et Google Cloud Storage. Avec l'intégration webhook, vous pouvez recevoir des notifications en temps réel concernant les actions et événements des utilisateurs. Ces notifications peuvent être personnalisées et envoyées vers un endpoint de votre choix, ce qui vous permet de surveiller et d'analyser facilement les données de votre application. Consultez la documentation suivante pour en savoir plus sur l'intégration webhook d'Adapty et comment la mettre en œuvre dans votre application : - [Webhook](webhook) Adapty propose une fonctionnalité pratique permettant la livraison automatique de toutes les données de transactions liées à votre application. Grâce à cette fonctionnalité, vous pouvez exporter sans effort vos données de transactions vers différents fournisseurs de stockage cloud sur une base quotidienne. Les données sont téléchargées sous forme de fichier .csv compressé au format gzip, ce qui permet un stockage et une analyse efficaces des informations. Découvrez comment gérer efficacement vos données et simplifier votre gestion des données en suivant nos guides faciles à utiliser : - [Amazon S3](s3-exports) - [Google Cloud Storage](google-cloud-storage) --- # File: s3-exports --- --- title: "Amazon S3" description: "Exportez les données d'abonnement vers S3 pour des analyses et des rapports avancés." --- L'intégration d'Adapty avec Amazon S3 vous permet de stocker les données d'événements et de visites de paywall de façon sécurisée en un seul endroit centralisé. Vous pouvez enregistrer vos [événements d'abonnement](events) dans votre bucket Amazon S3 sous forme de fichiers .csv. Pour configurer cette intégration, vous devrez suivre quelques étapes simples dans la console AWS et dans l'Adapty Dashboard. :::note Planification Adapty envoie vos données toutes les **24h** à 4h00 UTC. Chaque fichier contiendra les données des événements créés au cours de l'intégralité de la journée calendaire précédente en UTC. Par exemple, les données exportées automatiquement à 4h00 UTC le 8 mars contiendront tous les événements créés le 7 mars de 00:00:00 à 23:59:59 UTC. ::: ## Comment configurer l'intégration Amazon S3 \{#how-to-set-up-amazon-s3-integration\} Pour commencer à recevoir des données, vous aurez besoin des identifiants suivants : 1. Access key ID 2. Secret access key 3. S3 bucket name 4. Folder name inside the S3 bucket :::note Répertoires imbriqués Vous pouvez spécifier des répertoires imbriqués dans le champ Amazon S3 bucket name, par exemple : adapty-events/com.sample-app ::: Pour intégrer Amazon S3, rendez-vous dans [**Integrations** -> **Amazon S3**](https://app.adapty.io/integrations/s3), activez le bouton (de off à on) et renseignez les champs. Commencez par saisir vos identifiants afin d'établir la connexion entre Amazon S3 et les profils Adapty. <img src="/assets/shared/img/2b1a6e3-CleanShot_2023-03-24_at_14.51.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans l'Adapty Dashboard, les champs suivants sont nécessaires pour configurer la connexion : | Champ | Description | | :--------------------------- | :----------------------------------------------------------- | | **Access Key ID** | Un identifiant unique utilisé pour authentifier l'accès d'un utilisateur ou d'une application à un service AWS. Cet identifiant se trouve dans le [fichier csv](s3-exports#how-to-create-amazon-s3-credentials) téléchargé. | | **Secret Access Key** | Une clé privée utilisée conjointement avec l'Access Key ID pour authentifier l'accès d'un utilisateur ou d'une application à un service AWS. Cette clé se trouve dans le [fichier csv](s3-exports#how-to-create-amazon-s3-credentials) téléchargé. | | **S3 Bucket Name** | Un nom unique au niveau mondial qui identifie un bucket S3 spécifique dans le cloud AWS. Les buckets S3 sont un service de stockage simple permettant aux utilisateurs de stocker et de récupérer des objets de données, tels que des fichiers et des images, dans le cloud. | | **Folder Inside the Bucker** | Le nom du dossier que vous souhaitez créer dans le bucket S3 sélectionné. Notez que S3 simule les dossiers en utilisant des préfixes de clé d'objet, qui correspondent essentiellement à des noms de dossiers. | ## Comment créer des identifiants Amazon S3 \{#how-to-create-amazon-s3-credentials\} Ce guide vous aidera à créer les identifiants nécessaires dans votre AWS Console. ### 1\. Créer une politique d'accès \{#create-access-policy\} Commencez par accéder au [tableau de bord des politiques IAM](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) dans votre console AWS et sélectionnez l'option **Create Policy**. <img src="/assets/shared/img/7af075c-CleanShot_2023-03-21_at_10.52.002x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans l'éditeur de politiques, collez le JSON suivant et remplacez `adapty-s3-integration-test` par le nom de votre bucket : ```json showLineNumbers title="Json" { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListObjectsInBucket", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::adapty-s3-integration-test" }, { "Sid": "AllowAllObjectActions", "Effect": "Allow", "Action": "s3:*Object", "Resource": [ "arn:aws:s3:::adapty-s3-integration-test/*", "arn:aws:s3:::adapty-s3-integration-test" ] }, { "Sid": "AllowBucketLocation", "Effect": "Allow", "Action": "s3:GetBucketLocation", "Resource": "arn:aws:s3:::adapty-s3-integration-test" } ] } ``` <img src="/assets/shared/img/d4e474a-CleanShot_2023-03-21_at_10.56.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois la configuration de la politique terminée, vous pouvez ajouter des tags (facultatif), puis cliquer sur **Next** pour passer à l'étape finale. Dans cette étape, nommez votre politique et cliquez sur **Create policy** pour finaliser la création. <img src="/assets/shared/img/7dcb02f-CleanShot_2023-03-21_at_11.03.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 2\. Créer un utilisateur IAM \{#2-create-iam-user\} Pour permettre à Adapty de téléverser des rapports de données brutes dans votre bucket, vous devrez lui fournir l'Access Key ID et la Secret Access Key d'un utilisateur disposant d'un accès en écriture sur le bucket concerné. Pour ce faire, accédez à la console IAM et sélectionnez la [section Utilisateurs](https://console.aws.amazon.com/iamv2/home#/users). Cliquez ensuite sur le bouton **Add users**. <img src="/assets/shared/img/bb612c8-CleanShot_2023-03-21_at_11.12.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Donnez un nom à l'utilisateur, choisissez **Access key – Programmatic access**, puis passez aux permissions. <img src="/assets/shared/img/467ee4d-j6aoX.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour l'étape suivante, sélectionnez l'option **Add user to group**, puis cliquez sur le bouton **Create group**. <img src="/assets/shared/img/bfd0e80-CleanShot_2023-03-21_at_11.24.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Ensuite, vous devez attribuer un nom à votre groupe d'utilisateurs et sélectionner la politique que vous avez créée précédemment. Une fois la politique sélectionnée, cliquez sur le bouton **Create group** pour finaliser le processus. <img src="/assets/shared/img/df29c12-CleanShot_2023-03-21_at_11.28.052x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois le groupe créé avec succès, veuillez **le sélectionner** et passer à l'étape suivante. <img src="/assets/shared/img/1f3722e-CleanShot_2023-03-21_at_11.36.192x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Comme il s'agit de la dernière étape de cette section, vous pouvez continuer en cliquant simplement sur le bouton **Create User**. <img src="/assets/shared/img/ea43722-CleanShot_2023-03-21_at_11.40.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Enfin, vous pouvez soit **télécharger les identifiants au format .csv**, soit les copier-coller directement depuis le tableau de bord. <img src="/assets/shared/img/bcf35e1-S3created.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Export manuel des données \{#manual-data-export\} En plus de l'export automatique des données d'événements vers Amazon S3, Adapty propose également une fonctionnalité d'export manuel de fichiers. Grâce à cette fonctionnalité, vous pouvez sélectionner un intervalle de temps spécifique pour les données d'événements et les exporter manuellement vers votre bucket S3. Cela vous offre un meilleur contrôle sur les données que vous exportez et sur le moment où vous les exportez. La plage de dates spécifiée sera utilisée pour exporter les événements créés entre la date A à 00:00:00 UTC et la date B à 23:59:59 UTC. <img src="/assets/shared/img/466bd29-CleanShot_2023-03-21_at_12.35.252x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Structure de la table \{#table-structure\} Dans l'intégration AWS S3, Adapty fournit une table pour stocker les données historiques des événements de transaction et des visites de paywall. La table contient des informations sur le profil utilisateur, les revenus et les produits, ainsi que le store d'origine, entre autres données. Ces tables enregistrent essentiellement toutes les transactions générées par une application pour une période donnée. :::warning Notez que cette structure peut évoluer au fil du temps — de nouvelles données peuvent être introduites par nous ou par les tiers avec lesquels nous travaillons. Assurez-vous que votre code qui la traite est suffisamment robuste et s'appuie sur des champs spécifiques, mais pas sur la structure dans son ensemble. ::: Voici la structure du tableau pour les événements : :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: | Colonne | Description | |---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile_id** | ID utilisateur Adapty. | | **event_type** | Nom de l'événement en minuscules. Consultez la section [Événements](events) pour connaître les types d'événements. | | **event_datetime** | Date au format ISO 8601. | | **transaction_id** | Identifiant unique d'une transaction, comme un achat ou un renouvellement. | | **original_transaction_id** | Identifiant de transaction de l'achat d'origine. | | **subscription_expires_at** | Date d'expiration de l'abonnement. Généralement dans le futur. | | **environment** | Peut être Sandbox ou Production. | | **revenue_usd** | Revenu en USD. Peut être vide. | | **proceeds_usd** | Recettes en USD. Peut être vide. | | **net_revenue_usd** | Revenu net (après taxes) en USD. Peut être vide. | | **tax_amount_usd** | Montant déduit pour les taxes en USD. Peut être vide. | | **revenue_local** | Revenu en devise locale. Peut être vide. | | **proceeds_local** | Recettes en devise locale. Peut être vide. | | **net_revenue_local** | Revenu net (après taxes) en devise locale. Peut être vide. | | **tax_amount_local** | Montant déduit pour les taxes en devise locale. Peut être vide. | | **customer_user_id** | ID utilisateur développeur. Par exemple, il peut s'agir de votre UUID utilisateur, d'un e-mail ou de tout autre identifiant. Null si vous ne l'avez pas défini. | | **store** | Peut être _app_store_ ou _play_store_. | | **product_id** | ID du produit dans l'Apple App Store, le Google Play Store ou Stripe. | | **base_plan_id** | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) dans le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) dans Stripe. | | **developer_id** | ID développeur (SDK) du paywall depuis lequel la transaction est originaire. | | **ab_test_name** | Nom du test A/B depuis lequel la transaction est originaire. | | **ab_test_revision** | Révision du test A/B depuis lequel la transaction est originaire. | | **paywall_name** | Nom du paywall depuis lequel la transaction est originaire. | | **paywall_revision** | Révision du paywall depuis lequel la transaction est originaire. | | **profile_county** | Pays du profil déterminé par Adapty, d'après l'adresse IP. | | **install_date** | Date d'installation au format ISO 8601. | | **idfv** | [identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) sur les appareils iOS | | **idfa** | [advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) sur les appareils iOS | | **advertising_id** | L'Advertising ID est un code unique attribué par le système d'exploitation Android que les annonceurs peuvent utiliser pour identifier de manière unique l'appareil d'un utilisateur. | | **ip_address** | IP de l'appareil (peut être IPv4 ou IPv6, IPv4 étant préférée lorsqu'elle est disponible). Elle est mise à jour à chaque changement d'adresse IP de l'appareil. | | **cancellation_reason** | <p>Raison pour laquelle l'utilisateur a annulé un abonnement.</p><p></p><p>Peut être :</p><p>**iOS & Android** _voluntarily_cancelled_, _billing_error_, _refund_</p><p>**iOS** _price_increase_, _product_was_not_available_, _unknown_, _upgraded_</p><p>**Android** _new_subscription_replace_, _cancelled_by_developer_</p> | | **android_app_set_id** | Un [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) - ID réinitialisable par l'utilisateur, unique par appareil et par compte développeur, destiné aux cas d'usage publicitaires non monétisants. | | **android_id** | Sur Android 8.0 (niveau d'API 26) et versions supérieures, un nombre 64 bits (exprimé en chaîne hexadécimale), unique pour chaque combinaison de clé de signature d'application, d'utilisateur et d'appareil. Pour plus de détails, voir la [documentation Android developer](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Nom du modèle d'appareil visible par l'utilisateur final. | | **currency** | Code devise à 3 lettres (ISO-4217) de la transaction. | | **store_country** | Pays du profil déterminé par le store Apple/Google. | | **attribution_source** | Source d'attribution. | | **attribution_network_user_id** | ID attribué à l'utilisateur par la source d'attribution. | | **attribution_status** | Peut être organic, non_organic ou unknown. | | **attribution_channel** | Nom du canal marketing. | | **attribution_campaign** | Nom de la campagne marketing. | | **attribution_ad_group** | Groupe d'annonces d'attribution. | | **attribution_ad_set** | Ensemble d'annonces d'attribution. | | **attribution_creative** | Mot-clé créatif d'attribution. | | **attributes** | JSON des [attributs utilisateur personnalisés](setting-user-attributes#custom-user-attributes). Inclut tous les attributs personnalisés que vous avez configurés pour les envoyer depuis votre application mobile. Pour les envoyer, activez l'option **Send User Attributes** sur la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Tous les IDs d'intégration associés à un profil. Dictionnaire. Exemple : {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | Voici la structure du tableau pour les visites de paywall : | Colonne | Description | | :-------------------- | :------------------------------------------------------------------------------------------------------------------------- | | **profile_id** | Identifiant utilisateur Adapty. | | **customer_user_id** | Identifiant utilisateur développeur. Par exemple, il peut s'agir d'un UUID, d'un e-mail ou de tout autre identifiant. Null si non défini. | | **profile_country** | Pays du profil déterminé par le store Apple/Google. | | **install_date** | Date ISO 8601 de l'installation. | | **store** | Peut être _app_store_ ou _play_store_. | | **paywall_showed_at** | La date à laquelle le paywall a été affiché au client. | | **developer_id** | Identifiant développeur (SDK) du paywall d'où provient la transaction. | | **ab_test_name** | Nom du test A/B d'où provient la transaction. | | **ab_test_revision** | Révision du test A/B d'où provient la transaction. | | **paywall_name** | Nom du paywall d'où provient la transaction. | | **paywall_revision** | Révision du paywall d'où provient la transaction. | ## Événements et tags \{#events-and-tags\} Vous pouvez gérer les données transmises par l'intégration. Celle-ci propose les options de configuration suivantes : | Paramètre | Description | | :--------------------------------- | :----------------------------------------------------------- | | **Exclude Historical Events** | Choisissez d'exclure les événements survenus avant que l'utilisateur ait installé l'application avec le SDK Adapty. Cela évite la duplication des événements et garantit des rapports précis. Par exemple, si un utilisateur a activé un abonnement mensuel le 10 janvier et mis à jour l'application avec le SDK Adapty le 6 mars, Adapty ignorera les événements antérieurs au 6 mars et conservera les événements suivants. | | **Include events without profile** | Choisissez d'inclure les transactions qui ne sont pas liées à un profil utilisateur dans Adapty. Il peut s'agir d'achats effectués avant l'installation du SDK Adapty ou de transactions reçues depuis les notifications du serveur du store qui ne peuvent pas être immédiatement associées à un utilisateur spécifique. | | **Send User Attributes** | Si vous souhaitez envoyer des attributs spécifiques à l'utilisateur, comme les préférences de langue, et que votre forfait OneSignal prend en charge plus de 10 tags, sélectionnez cette option. L'activer permet d'inclure des informations supplémentaires au-delà des 10 tags par défaut. Notez que dépasser les limites de tags peut entraîner des erreurs. | <img src="/assets/shared/img/s3-settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Sous les paramètres d'intégration, vous trouverez trois groupes d'événements que vous pouvez exporter, envoyer et stocker dans Amazon S3 depuis Adapty. Activez simplement ceux dont vous avez besoin. Consultez la liste complète des événements proposés par Adapty [ici](events). <img src="/assets/shared/img/fd5ccb9-CleanShot_2023-08-17_at_14.49.282x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: google-cloud-storage --- --- title: "Google Cloud Storage" description: "Intégrez Google Cloud Storage avec Adapty pour un stockage sécurisé des données." --- Activez l'intégration Google Cloud Storage pour stocker de manière sécurisée les [événements d'abonnement](events) et les [données de visites de paywall](paywall-metrics) dans un emplacement centralisé : votre bucket Google Cloud Storage. Chaque jour à 4h00 UTC, Adapty téléverse des fichiers .csv contenant les données de la veille vers vos buckets. Vous pouvez choisir de recevoir les données d'**événements**, les données de **visites de paywall**, ou **les deux**. Vous pouvez également exporter ces données [manuellement](#manual-data-export) à tout moment, pour n'importe quelle période. Pour configurer l'intégration, [générez une clé d'accès au bucket](#create-google-cloud-storage-credentials) dans votre console Google Cloud, puis [ajoutez-la dans vos paramètres Adapty](#set-up-google-cloud-storage-integration). ## Calendrier et durée des téléversements \{#upload-schedule-and-duration\} Adapty téléverse les données vers Google Cloud Storage toutes les 24 heures, à 04:00 UTC. Les fichiers contiennent les données des événements créés durant le jour calendaire précédent (UTC). Le fichier téléversé le 8 mars contiendra tous les événements créés le 7 mars, de 00:00:00 à 23:59:59 UTC. Le processus peut prendre jusqu'à plusieurs heures selon le nombre total de fichiers en attente et la quantité de données que vous avez personnellement demandée. Si Adapty inclut des données historiques dans votre premier téléversement, celui-ci sera plus long que les téléversements quotidiens suivants. ## Configurer l'intégration Google Cloud Storage \{#set-up-google-cloud-storage-integration\} Vous devez disposer d'une clé de compte de service Google Cloud valide avec un **accès en écriture**. Pour la générer, suivez les étapes de la section [créer des identifiants](#create-google-cloud-storage-credentials). :::warning Vous pouvez utiliser des buckets différents avec des identifiants différents pour les événements et les visites de paywall. Cependant, si **l'un ou l'autre** ensemble d'identifiants est invalide, [**les deux téléversements échoueront**](#troubleshooting). ::: Accédez à [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/integrations/google-cloud-storage), puis ouvrez l'onglet souhaité (**Events** ou **Paywall visits**). Activez l'intégration. Téléversez le fichier contenant votre **clé de compte de service Google Cloud**. Indiquez le **bucket** et le **dossier** cibles. Enregistrez vos modifications. ### Paramètres optionnels pour les données d'événements \{#optional-settings-for-event-data\} Vous pouvez spécifier les événements à inclure dans le rapport et définir des noms personnalisés pour ces événements. Consultez l'article [événements](events) pour la liste complète des événements disponibles. | Nom | Valeur par défaut | Description | | ------------------------------ | ----------------- | ----------- | | Exclude historical events | true | Exclure les informations sur les événements survenus avant l'intégration du SDK Adapty dans votre application. <br /> <br />Si votre plateforme d'analyse a reçu des événements d'abonnement **avant** que vous commenciez à utiliser Adapty, cette option garantit qu'elle ne reçoit pas de doublons. <Details summary="Exemple pratique"><p>Un utilisateur a souscrit un abonnement mensuel le 10 janvier. La mise à jour du 1er mars de votre application est la première à inclure le SDK Adapty. <br /> <br /> Si ce paramètre est **activé**, le rapport n'inclura ni l'événement « abonnement démarré » de janvier, ni l'événement « renouvellement d'abonnement » de février. Il **inclura** l'événement « renouvellement d'abonnement » du 10 mars.</p> </Details> | | Include events without profile | false | Inclure les transactions non liées à un profil utilisateur, ou qui ne peuvent pas être immédiatement associées à un utilisateur spécifique. Cela peut inclure des achats effectués avant l'installation du SDK Adapty, ou des transactions reçues via des notifications serveur. | | Send user attributes | false | Inclure les [attributs utilisateur personnalisés](setting-user-attributes), tels que les données utilisateur et les données d'utilisation de l'application. Sélectionnez cette option si votre forfait OneSignal prend en charge plus de 10 tags. Notez que le dépassement des limites de tags peut entraîner des erreurs. | ## Créer des identifiants Google Cloud Storage \{#create-google-cloud-storage-credentials\} Ce guide vous aidera à créer les identifiants nécessaires dans votre console Google Cloud Platform. Pour qu'Adapty puisse téléverser des rapports de données brutes dans votre bucket, la clé du compte de service est requise, ainsi qu'un accès en écriture au bucket correspondant. En fournissant la clé du compte de service et en accordant l'accès en écriture au bucket, vous permettez à Adapty de transférer de manière sécurisée et efficace les rapports de données brutes depuis sa plateforme vers votre environnement de stockage. :::warning Veuillez noter que nous ne prenons en charge que l'autorisation par clé HMAC de compte de service. Il est donc essentiel de s'assurer que votre clé HMAC de compte de service dispose des rôles « Storage Object Viewer », « Storage Legacy Bucket Writer » et « Storage Object Creator » pour permettre un accès correct à Google Cloud Storage. ::: 1. Pour commencer, accédez à la section [IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts) de votre compte Google Cloud et choisissez le projet concerné ou créez-en un nouveau. 1. Ensuite, créez un nouveau compte de service pour Adapty en cliquant sur le bouton « + CREATE SERVICE ACCOUNT ». 2. Remplissez les champs de la première étape, car les accès seront accordés ultérieurement. Pour en savoir plus sur cette page, consultez la documentation [ici](https://docs.cloud.google.com/iam/docs/service-accounts-create). 3. Pour créer et télécharger une [clé JSON privée](https://docs.cloud.google.com/iam/docs/keys-create-delete), accédez à la section KEYS et cliquez sur le bouton « ADD KEY ». 4. Dans la section DETAILS, repérez la valeur Email associée au compte de service récemment créé et copiez-la. Cette information sera nécessaire pour les étapes suivantes afin d'autoriser le compte et lui permettre d'écrire dans le bucket. 5. Pour continuer, accédez à la page [Buckets](https://console.cloud.google.com/storage/browser) de Google Cloud Storage et sélectionnez un bucket existant ou créez-en un nouveau pour stocker les rapports de données d'événements ou de visites d'Adapty. Accédez ensuite à la section PERMISSIONS et sélectionnez l'option [GRANT ACCESS](https://docs.cloud.google.com/identity/docs/how-to?hl=en). 6. Dans la section PERMISSIONS, saisissez l'Email du compte de service obtenu à la cinquième étape, puis choisissez le rôle Storage Object Creator. Enfin, cliquez sur SAVE pour appliquer les modifications. Pensez à noter le nom du bucket pour référence ultérieure. ## Export manuel des données \{#manual-data-export\} En plus de l'export automatique des données d'événements vers Google Cloud Storage, Adapty propose également une fonctionnalité d'export manuel de fichiers. Grâce à cette fonctionnalité, vous pouvez sélectionner un intervalle de temps spécifique pour les données d'événements et les exporter manuellement vers votre bucket GCS. Vous avez ainsi un meilleur contrôle sur les données exportées et le moment de l'export. La plage de dates spécifiée sera utilisée pour exporter les événements créés de la Date A à 00:00:00 UTC jusqu'à la Date B à 23:59:59 UTC. ## Structure des données \{#data-structure\} Adapty utilise des fichiers `.csv` pour exporter les données sous forme tabulaire. :::warning Le contenu des événements peut évoluer au fil du temps, avec de nouvelles données introduites par nous-mêmes ou par des tiers avec lesquels nous travaillons. Assurez-vous que le code qui les traite est suffisamment robuste et s'appuie sur des champs spécifiques, et non sur la structure dans son ensemble. ::: ### Événements \{#events\} Vous pouvez [modifier](#optional-settings-for-event-data) la liste des événements inclus dans vos rapports. :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: | Colonne | Description | |------|-----------| | **profile_id** | Identifiant utilisateur Adapty. | | **event_type** | Nom de l'événement en minuscules. Consultez la section [Événements](events) pour connaître les types d'événements. | | **event_datetime** | Date au format ISO 8601. | | **transaction_id** | Identifiant unique d'une transaction, comme un achat ou un renouvellement. | | **original_transaction_id** | Identifiant de la transaction d'achat d'origine. | | **subscription_expires_at** | Date d'expiration de l'abonnement. Généralement dans le futur. | | **environment** | Peut être Sandbox ou Production. | | **revenue_usd** | Revenus en USD. Peut être vide. | | **proceeds_usd** | Recettes en USD. Peut être vide. | | **net_revenue_usd** | Revenus nets (revenus après taxes) en USD. Peut être vide. | | **tax_amount_usd** | Montant déduit pour les taxes en USD. Peut être vide. | | **revenue_local** | Revenus en devise locale. Peut être vide. | | **proceeds_local** | Recettes en devise locale. Peut être vide. | | **net_revenue_local** | Revenus nets (revenus après taxes) en devise locale. Peut être vide. | | **tax_amount_local** | Montant déduit pour les taxes en devise locale. Peut être vide. | | **customer_user_id** | Identifiant utilisateur développeur. Par exemple, il peut s'agir de votre UUID utilisateur, email, ou tout autre identifiant. Null si vous ne l'avez pas défini. | | **store** | Peut être *app_store* ou *play_store*. | | **product_id** | Identifiant du produit dans l'Apple App Store, le Google Play Store, ou Stripe. | | **base_plan_id** | [Identifiant du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) dans le Google Play Store ou [identifiant de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) dans Stripe. | | **developer_id** | Identifiant développeur (SDK) du paywall depuis lequel la transaction est originaire. | | **ab_test_name** | Nom du test A/B depuis lequel la transaction est originaire. | | **ab_test_revision** | Révision du test A/B depuis lequel la transaction est originaire. | | **paywall_name** | Nom du paywall depuis lequel la transaction est originaire. | | **paywall_revision** | Révision du paywall depuis lequel la transaction est originaire. | | **profile_country** | Pays du profil déterminé par Adapty, sur la base de l'adresse IP. | | **install_date** | Date ISO 8601 de l'installation. | | **idfv** | [identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) sur les appareils iOS | | **idfa** | [advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) sur les appareils iOS | | **advertising_id** | L'Advertising ID est un code unique attribué par le système d'exploitation Android que les annonceurs peuvent utiliser pour identifier de manière unique l'appareil d'un utilisateur | | **ip_address** | IP de l'appareil (peut être IPv4 ou IPv6, IPv4 étant préférée lorsqu'elle est disponible). Elle est mise à jour à chaque changement d'IP de l'appareil | | **cancellation_reason** | <p>La raison pour laquelle l'utilisateur a annulé un abonnement.</p><p></p><p>Valeurs possibles :</p><p>**iOS & Android** — *voluntarily_cancelled*, *billing_error*, *refund*</p><p>**iOS uniquement** — *price_increase*, *product_was_not_available*, *unknown*, *upgraded*</p><p> **Android uniquement** — *new_subscription_replace*, *cancelled_by_developer*</p> | | **android_app_set_id** | Un [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) - identifiant réinitialisable par l'utilisateur, unique par appareil et par compte développeur, destiné aux cas d'utilisation publicitaires non monétaires. | | **android_id** | Sur Android 8.0 (API niveau 26) et les versions supérieures de la plateforme, un nombre de 64 bits (exprimé sous forme de chaîne hexadécimale), unique pour chaque combinaison de clé de signature d'application, d'utilisateur et d'appareil. Pour plus de détails, consultez la [documentation développeur Android](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Le nom du modèle d'appareil visible par l'utilisateur final. | | **currency** | Le code de devise à 3 lettres (ISO-4217) de la transaction. | | **store_country** | Pays du profil déterminé par le store Apple/Google. | | **attribution_source** | Source d'attribution. | | **attribution_network_user_id** | Identifiant attribué à l'utilisateur par la source d'attribution. | | **attribution_status** | Peut être organic, non_organic ou unknown. | | **attribution_channel** | Nom du canal marketing. | | **attribution_campaign** | Nom de la campagne marketing. | | **attribution_ad_group** | Groupe d'annonces d'attribution. | | **attribution_ad_set** | Ensemble d'annonces d'attribution. | | **attribution_creative** | Mot-clé créatif d'attribution. | | **attributes** | JSON des [attributs utilisateur personnalisés](setting-user-attributes#custom-user-attributes). Cela inclut tous les attributs personnalisés que vous avez configurés pour être envoyés depuis votre application mobile. Pour l'activer, activez l'option **Send User Attributes** dans la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Tous les identifiants d'intégration associés à un profil. Dictionnaire. Exemple : {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | ### Visites de paywall \{#paywall-visits\} | Colonne | Description | | :-------------------- | :----------------------------------------------------------------------------------------------------------- | | **profile_id** | Identifiant utilisateur Adapty. | | **customer_user_id** | Identifiant utilisateur développeur. Par exemple, il peut s'agir de votre UUID utilisateur, email, ou tout autre identifiant. Null si vous ne l'avez pas défini. | | **profile_country** | Pays du profil déterminé par le store Apple/Google. | | **install_date** | Date ISO 8601 de l'installation. | | **store** | Peut être *app_store* ou *play_store*. | | **paywall_showed_at** | La date à laquelle le paywall a été affiché à l'utilisateur. | | **developer_id** | Identifiant développeur (SDK) du paywall depuis lequel la transaction est originaire. | | **ab_test_name** | Nom du test A/B depuis lequel la transaction est originaire. | | **ab_test_revision** | Révision du test A/B depuis lequel la transaction est originaire. | | **paywall_name** | Nom du paywall depuis lequel la transaction est originaire. | | **paywall_revision** | Révision du paywall depuis lequel la transaction est originaire. | ## Dépannage \{#troubleshooting\} Adapty vérifie la validité de vos clés d'accès **avant** de commencer le téléversement. Même si une seule de vos clés Google Cloud Storage est invalide, Adapty **interrompt le téléversement** et génère une erreur. Pour garantir des téléversements ininterrompus, remplacez vos clés avant leur expiration. Si vous mettez à jour la clé pour les **événements**, n'oubliez pas de mettre à jour également la clé pour les **visites de paywall**, et vice versa. --- # File: webhook --- --- title: "Intégration Webhook" description: "Intégrez les webhooks dans Adapty pour automatiser le suivi des événements d'abonnement." --- Un webhook est un moyen efficace de recevoir des notifications en temps réel sur les [événements](webhook-event-types-and-fields#webhook-event-types), notamment pour suivre les changements d'abonnements et d'achats. Cela vous permet de surveiller le statut des abonnés et d'y réagir en conséquence. Contrairement aux requêtes API qui nécessitent une interrogation constante, un webhook se configure une seule fois et envoie automatiquement des données via HTTP lorsqu'un événement se produit. :::tip Vous configurez ceci avec un agent de codage IA ? Consultez [Gérer les événements d'abonnement Adapty avec des webhooks](handle-webhooks-with-ai) pour un guide complet sur une seule page. ::: Avec les webhooks intégrés, vous pouvez : - Suivre les abonnements et les achats dans votre système backend. - Automatiser les processus et les workflows en fonction des cycles de vie des abonnements. - Interagir avec les abonnés en leur rappelant les avantages de l'application, en traitant les décisions de désabonnement et en gérant les problèmes de facturation. - Effectuer une analyse détaillée du comportement des utilisateurs. **Caractéristiques de l'intégration** | Caractéristique de l'intégration | Description | | :-------------------------------- | :----------------------------------------------------------------- | | Fréquence | Mises à jour en temps réel | | Direction des données | Transmission de données unidirectionnelle : d'Adapty vers votre serveur | | Flux d'intégration Adapty | Les événements sont envoyés par le serveur Adapty dès leur réception | ## Événements envoyés au webhook \{#events-sent-to-webhook\} Vous pouvez consulter tous les types d'événements pouvant être envoyés à un webhook sur la page [Types et champs d'événements webhook](webhook-event-types-and-fields). Vous pouvez tous les envoyer à votre webhook ou n'en choisir que certains. Consultez notre page [Flux d'événements](event-flows) pour décider quels événements sont nécessaires ou non. Vous pouvez désactiver les types d'événements dont vous n'avez pas besoin lors de la [configuration de votre intégration Webhook](set-up-webhook-integration#configure-webhook-integration-in-the-adapty-dashboard). Vous pouvez également y remplacer les identifiants d'événements Adapty par défaut par les vôtres si nécessaire. **Prochaines étapes :** - [Types et champs d'événements webhook](webhook-event-types-and-fields) : Explorez les descriptions détaillées de chaque événement et de leurs champs de données. - [Flux d'événements](event-flows) : Découvrez la séquence des événements et leurs dépendances. - [Configurer l'intégration webhook](set-up-webhook-integration) : Guide pas à pas pour configurer votre webhook dans l'Adapty Dashboard. - [Tester l'intégration webhook](test-webhook) : Vérifiez que votre webhook est correctement configuré grâce à nos outils de test. --- # File: webhook-event-types-and-fields --- --- title: "Types d'événements et champs des webhooks" description: "" --- Adapty envoie des webhooks en réponse aux événements d'abonnement. Cette section définit ces types d'événements ainsi que les données contenues dans chaque webhook. ## Types d'événements webhook \{#webhook-event-types\} Vous pouvez envoyer tous les types d'événements à votre webhook ou n'en choisir que certains. Consultez nos [Flux d'événements](event-flows) pour savoir quel type de données entrantes attendre et comment construire votre logique métier autour de ces données. Vous pouvez désactiver les types d'événements dont vous n'avez pas besoin lors de la [configuration de votre intégration Webhook](set-up-webhook-integration#configure-webhook-integration-in-the-adapty-dashboard). Vous pouvez également y remplacer les ID d'événements Adapty par défaut par les vôtres si nécessaire. | Nom de l'événement | Description | |:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | Déclenché lorsqu'un utilisateur active un abonnement payant sans période d'essai, c'est-à-dire qu'il est facturé immédiatement. | | subscription_renewed | Se produit lors du renouvellement d'un abonnement et de la facturation de l'utilisateur. Cet événement débute à partir de la deuxième facturation, que l'abonnement soit avec ou sans essai. | | subscription_renewal_cancelled | Un utilisateur a désactivé le renouvellement automatique de son abonnement. Il conserve l'accès aux fonctionnalités premium jusqu'à la fin de la période d'abonnement payante. | | subscription_renewal_reactivated | Déclenché lorsqu'un utilisateur réactive le renouvellement automatique de son abonnement. | | subscription_expired | Déclenché lorsqu'un abonnement prend fin après une annulation. Par exemple, si un utilisateur annule son abonnement le 12 décembre mais qu'il reste actif jusqu'au 31 décembre, l'événement est enregistré le 31 décembre à l'expiration de l'abonnement. | | subscription_paused | Se produit lorsqu'un utilisateur active la [mise en pause de l'abonnement](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (Android uniquement). | | subscription_deferred | Déclenché lorsqu'un achat d'abonnement est [différé](https://adapty.io/glossary/subscription-purchase-deferral/), permettant aux utilisateurs de reporter le paiement tout en conservant l'accès aux fonctionnalités premium. Cette fonctionnalité est disponible via l'API Google Play Developer et peut être utilisée pour des essais gratuits ou pour les utilisateurs rencontrant des difficultés financières. | | non_subscription_purchase | Tout achat sans abonnement, tel qu'un accès à vie ou des produits consommables comme des pièces dans un jeu. | | trial_started | Déclenché lorsqu'un utilisateur active un abonnement d'essai. | | trial_converted | Se produit lorsqu'un essai se termine et que l'utilisateur est facturé (premier achat). Par exemple, si un utilisateur a un essai jusqu'au 14 janvier mais est facturé le 7 janvier, cet événement est enregistré le 7 janvier. | | trial_renewal_cancelled | Un utilisateur a désactivé le renouvellement automatique de son abonnement pendant la période d'essai. Il conserve l'accès aux fonctionnalités premium jusqu'à la fin de l'essai, mais ne sera pas facturé et ne démarrera pas d'abonnement. | | trial_renewal_reactivated | Se produit lorsqu'un utilisateur réactive le renouvellement automatique de son abonnement pendant la période d'essai. | | trial_expired | Déclenché lorsqu'un essai se termine sans conversion en abonnement. | | entered_grace_period | Se produit lorsqu'une tentative de paiement échoue et que l'utilisateur entre dans un délai de grâce (si activé). L'utilisateur conserve l'accès premium pendant cette période. | | billing_issue_detected | Déclenché lorsqu'un problème de facturation survient lors d'une tentative de débit (par exemple, solde de carte insuffisant). | | subscription_refunded | Déclenché lorsqu'un abonnement est remboursé (par exemple, par le support Apple). | | non_subscription_purchase_refunded | Déclenché lorsqu'un achat sans abonnement est remboursé. | | access_level_updated | Se produit lorsque le niveau d'accès d'un utilisateur est mis à jour. | :::note `subscription_renewal_reactivated` contient l'identifiant du produit **précédent** — celui qui était actif au moment où l'utilisateur a annulé — même si l'utilisateur a ensuite réactivé son abonnement en achetant un produit différent. Apple conserve le même `original_transaction_id` tout au long de la chaîne annulation → réactivation, de sorte que cet événement reflète le produit d'origine. Le nouveau produit apparaît dans le prochain événement `subscription_renewed`, lorsque la facturation du nouveau produit commence. ::: ## Structure des événements webhook \{#webhook-event-structure\} Adapty vous enverra uniquement les événements que vous avez sélectionnés dans la section **Events names** de la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). Les événements webhook sont sérialisés en JSON. Le corps d'une requête `POST` envoyée à votre serveur contiendra l'événement sérialisé dans la structure ci-dessous. Tous les événements suivent la même structure, mais leurs champs varient selon le type d'événement, le store et votre configuration spécifique. Les attributs utilisateur correspondent aux [attributs utilisateur personnalisés](setting-user-attributes#custom-user-attributes) que vous avez définis, ils contiennent donc ce que vous avez configuré. Les champs de données d'attribution sont identiques pour tous les types d'événements, mais la liste des attributions dépend des sources d'attribution que vous utilisez dans votre application mobile. Voici un exemple d'événement : ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "idfv": "00000000-0000-0000-0000-000000000000", "idfa": "00000000-0000-0000-0000-000000000000", "advertising_id": "00000000-0000-0000-0000-000000000000", "profile_install_datetime": "2000-01-31T00:00:00.000000+0000", "user_agent": "ExampleUserAgent/1.0 (Device; OS Version) Browser/Engine", "email": "john.doe@company.com", "event_type": "subscription_started", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "profile_id": "00000000-0000-0000-0000-000000000000", "cohort_name": "All Users", "environment": "Production", "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "base_plan_id": "b1", "developer_id": "onboarding_placement", "ab_test_name": "onboarding_ab_test", "ab_test_revision": 1, "paywall_name": "UsedPaywall", "proceeds_usd": 4.2315, "variation_id": "00000000-0000-0000-0000-000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "store_country": "AR", "event_datetime": "2000-01-31T00:00:00.000000+0000", "proceeds_local": 4.2415, "tax_amount_usd": 0, "transaction_id": "0000000000000000", "net_revenue_usd": 4.2415, "profile_country": "AR", "paywall_revision": "1", "profile_event_id": "00000000-0000-0000-0000-000000000000", "tax_amount_local": 0, "net_revenue_local": 4.2415, "vendor_product_id": "onemonth_no_trial", "profile_ip_address": "10.10.1.1", "consecutive_payments": 1, "rate_after_first_year": false, "original_purchase_date": "2000-01-31T00:00:00.000000+0000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2000-01-31T00:00:00.000000+0000", "profile_has_access_level": true, "profile_total_revenue_usd": 4.99, "promotional_offer_id": null, "store_offer_category": null, "store_offer_discount_type": null }, "event_api_version": 1, "profiles_sharing_access_level": [{"profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem"}], "attributions": { "appsflyer": { "ad_set": "Keywords 1.12", "status": "non_organic", "channel": "Google Ads", "ad_group": null, "campaign": "Social media influencers - Rest of the world", "creative": null, "created_at": "2000-01-31T00:00:00.000000+0000" } }, "user_attributes": {"Favourite_color": "Violet", "Pet_name": "Fluffy"}, "integration_ids": {"firebase_app_instance_id": "val1", "branch_id": "val2", "one_signal_player_id": "val3"}, "play_store_purchase_token": { "product_id": "product_123", "purchase_token": "token_abc_123", "is_subscription": true } } ``` ### Champs d'événement \{#event-fields\} Les paramètres d'événement sont identiques pour tous les types d'événements. | **Champ** | **Type** | **Description** | |---|---|---| | **advertising_id** | UUID | Advertising ID (Android uniquement). | | **attributions** | JSON | [Données d'attribution](webhook-event-types-and-fields#attributions). Inclus si **Send Attribution** est activé dans les [paramètres du Webhook](https://app.adapty.io/integrations/customwebhook). | | **customer_user_id** | String | ID utilisateur de votre application (UUID, e-mail ou autre identifiant) si vous l'avez défini dans le code de votre application lors de [l'identification des utilisateurs](ios-quickstart-identify). Si vous n'identifiez pas les utilisateurs dans le code de l'application ou si cet utilisateur est anonyme (non connecté), ce champ vaut `null`. | | **email** | String | E-mail de l'utilisateur si vous l'avez défini via la méthode [`updateProfile`](setting-user-attributes) du SDK Adapty ou lors de la création/mise à jour de profils via l'API server-side. Si vous ne transmettez pas la valeur `email` au SDK ou à la méthode API, ce champ vaut `null`. | | **event_api_version** | Integer | Version de l'API Adapty (actuelle : `1`). | | **event_datetime** | ISO 8601 | L'heure effective (métier) de l'événement — par exemple la date d'achat pour un achat ou la date d'expiration pour une expiration — et non le moment où Adapty a reçu ou envoyé l'événement. Format [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (ex. : `2020-07-10T15:00:00.000000+0000`). Voir la note ci-dessous sur l'ordre des événements. | | **event_properties** | JSON | [Propriétés de l'événement](webhook-event-types-and-fields#event-properties). | | **event_type** | String | Nom de l'événement au format Adapty. Consultez les [types d'événements Webhook](webhook-event-types-and-fields#webhook-event-types) pour la liste complète. | | **idfa** | UUID | Advertising ID (Apple uniquement). **IDFA** dans le profil sur l'[Adapty Dashboard](https://app.adapty.io/profiles/users). Peut être `null` si indisponible en raison de restrictions de suivi, du mode enfant ou des paramètres de confidentialité. | | **idfv** | UUID | Identifier for Vendors (IDFV), unique par développeur. **IDFV** dans le profil sur l'[Adapty Dashboard](https://app.adapty.io/profiles/users). | | **integration_ids** | JSON | IDs d'intégration utilisateur si vous les avez définis via la méthode `setIntegrationIdentifier` du SDK Adapty ou lors de la création/mise à jour de profils via l'API server-side. Vaut `null` si indisponible ou si les intégrations sont désactivées. | | **play_store_purchase_token** | JSON | [Token d'achat Play Store](webhook-event-types-and-fields#play-store-purchase-token), inclus si **Send Play Store purchase token** est activé dans les [paramètres du Webhook](https://app.adapty.io/integrations/customwebhook). | | **profile_id** | UUID | ID de profil généré automatiquement par Adapty pour chaque profil. Un même identifiant Apple/Google peut être associé à différents IDs de profil si vous n'identifiez pas les utilisateurs ou autorisez les achats avant la connexion. En savoir [plus sur la façon dont Adapty gère les profils parent/héritier](how-profiles-work#parent-and-inheritor-profiles). | | **profile_install_datetime** | ISO 8601 | Horodatage d'installation au format [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (ex. : `2020-07-10T15:00:00.000000+0000`). | | **profiles_sharing_access_level** | JSON | Liste des utilisateurs [partageant le niveau d'accès](general#6-sharing-paid-access-between-user-accounts), à l'exclusion du profil utilisateur actuel. Si le partage des niveaux d'accès est activé pour votre application, cette liste inclut les autres profils associés au même identifiant Apple/Google.<br/>Format : <ul><li>**profile_id** : (UUID) ID Adapty</li><li>**customer_user_id** : (String) Customer User ID si fourni</li></ul> | | **user_agent** | String | User-agent du navigateur de l'appareil. | | **user_attributes** | JSON | Données personnalisées que vous pouvez définir pour enrichir les profils utilisateurs avec des informations propres à l'application. Généralement utilisées pour suivre les préférences (ex. : thème, langue) ou des indicateurs comportementaux (onboarding terminé, utilisation de fonctionnalités). <br/>Formatées sous forme de paires clé-valeur où les clés sont des chaînes et les valeurs peuvent être des chaînes ou des nombres (ex. : `{"Favourite_color": "Violet", "Pet_name": "Fluffy"}`). <br/>Vous pouvez définir des attributs personnalisés manuellement dans l'Adapty Dashboard pour des profils individuels, par programmation via la méthode `updateProfile` du SDK Adapty, ou via l'API server-side lors de la création/mise à jour de profils. <br/>Inclus si **Send User Attributes** est activé dans les [paramètres du Webhook](https://app.adapty.io/integrations/customwebhook). <p>Bien que les valeurs d'attributs personnalisés dans le code de l'application mobile puissent être définies en tant que flottants ou chaînes, les attributs reçus via l'API server-side ou une importation historique peuvent arriver dans des formats différents. Les valeurs booléennes et entières seront alors converties en flottants.</p> | :::note `event_datetime` reflète le moment où un événement s'est produit dans le cycle de vie de l'abonnement, et non le moment où Adapty l'a traité ou transmis. Pour cette raison, des événements peuvent partager le même `event_datetime` ou arriver dans le désordre chronologique. Par exemple, un événement `subscription_expired` peut avoir un `event_datetime` antérieur à celui d'un événement `subscription_renewal_cancelled` qu'Adapty lui transmet avant. Ne vous fiez pas à `event_datetime` pour ordonner les événements. Ordonnez-les plutôt selon votre propre heure de réception, et dédoublonnez-les à l'aide de `profile_event_id` ou des identifiants de transaction. ::: ### Attributions \{#attributions\} Pour envoyer les données d'attribution, activez l'option **Send Attribution** sur la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). Si vous avez activé l'envoi des données d'attribution et configuré des [intégrations d'attribution](attribution-integration), les données ci-dessous seront envoyées avec l'événement pour chaque source. Les mêmes données d'attribution sont envoyées pour tous les types d'événements. ```json title="Json" showLineNumbers { "attributions": { "appsflyer": { "ad_set": "sample_ad_set_123", "status": "non_organic", "channel": "sample_channel", "ad_group": "sample_ad_group_456", "campaign": "sample_ios_campaign", "creative": "sample_creative_789", "created_at": "2000-01-31T00:00:00.000000+0000", "network_user_id": "0000000000000-0000000" } } } ``` | Nom du champ | Type de champ | Description | | :------------------ | :------------ | :------------------------------------------------- | | **ad_set** | String | Ensemble d'annonces d'attribution. | | **status** | String | Peut être `organic`, `non_organic,` ou `unknown`. | | **channel** | String | Nom du canal marketing. | | **ad_group** | String | Groupe d'annonces d'attribution. | | **campaign** | String | Nom de la campagne marketing. | | **creative** | String | Mot-clé créatif d'attribution. | | **created_at** | ISO 8601 date | Date et heure de création de l'enregistrement d'attribution. | | **network_user_id** | String | ID attribué à l'utilisateur par la source d'attribution. | ### ID d'intégration \{#integration-ids\} Les ID d'intégration suivants sont désormais utilisés dans les événements : - `adjust_device_id` - `airbridge_device_id` - `amplitude_device_id` - `amplitude_user_id` - `appmetrica_device_id` - `appmetrica_profile_id` - `appsflyer_id` - `branch_id` - `facebook_anonymous_id` - `firebase_app_instance_id` - `mixpanel_user_id` - `pushwoosh_hwid` - `one_signal_player_id` - `one_signal_subscription_id` - `tenjin_analytics_installation_id` - `posthog_distinct_user_id` ### Jeton d'achat Play Store \{#play-store-purchase-token\} Ce champ contient toutes les données nécessaires pour revalider un achat, si besoin. Il n'est envoyé que si l'option **Send Play Store purchase token** est activée dans les [paramètres de l'intégration Webhook](https://app.adapty.io/integrations/customwebhook). | Field | Type | Description | | :------------------ | :------ | :----------------------------------------------------------- | | **product_id** | String | L'identifiant unique du produit (SKU) acheté sur le Play Store. | | **purchase_token** | String | Un token généré par Google Play pour identifier de manière unique cette transaction d'achat. | | **is_subscription** | Boolean | Indique si le produit acheté est un abonnement (`true`) ou un achat unique (`false`). | ### Propriétés des événements \{#event-properties\} Les propriétés des événements peuvent varier selon le type d'événement, et même entre des événements du même type. Par exemple, un événement provenant de l'App Store ne comportera pas les propriétés spécifiques à Android comme `base_plan_id`. L'événement [Niveau d'accès mis à jour](webhook-event-types-and-fields#for-access-level-updated-event) possède des propriétés distinctes, c'est pourquoi nous lui avons consacré une section séparée. De même, nous avons séparé les [Propriétés fiscales et de revenus supplémentaires](webhook-event-types-and-fields#additional-tax-and-revenue-event-properties), car elles sont spécifiques à certains types d'événements seulement. #### Pour la plupart des types d'événements \{#for-most-event-types\} Les propriétés d'événement sont cohérentes pour la plupart des types d'événements (à l'exception de l'événement **Access Level Updated**, décrit dans sa propre section). Voici un tableau complet des propriétés, indiquant celles qui s'appliquent à des événements spécifiques. :::note Adapty convertit les autres devises en USD au taux de change de [currencylayer.com](https://currencylayer.com/) (actualisé toutes les 8 heures). Le taux est **fixé au moment de la transaction** — les variations ultérieures n'affectent pas le résultat de la conversion. ::: | Champ | Type | Description | |:------------------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **ab_test_name** | String | Nom du [test A/B Adapty](ab-tests) dont est issue la transaction. | | **ab_test_revision** | Integer | Révision du test A/B dont est issue la transaction. | | **base_plan_id** | String | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) dans le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) dans Stripe. | | **cancellation_reason** | String | <p>Raisons possibles d'annulation : `voluntarily_cancelled`, `billing_error`, `price_increase`, `product_was_not_available`, `refund`, `cancelled_by_developer`, `new_subscription_replace`, `upgraded`, `unknown`, `adapty_revoked`.</p><p>Présent dans les types d'événements suivants :</p>`subscription_cancelled`, `subscription_refunded` et `trial_cancelled`. | | **cohort_name** | String | Nom de l'[audience](audience) qui a déterminé quel paywall a été affiché à l'utilisateur. | | **consecutive_payments** | Integer | Nombre de périodes durant lesquelles l'utilisateur est abonné sans interruption. Inclut la période en cours. | | **currency** | String | Devise locale. | | **developer_id** | String | ID du [placement](placements) dont est issue la transaction. | | **discount_amount_local** | Float | La remise appliquée à la transaction : le prix standard moins le montant réellement facturé, avant la commission Apple/Google, en devise locale. `0` pour un achat au plein tarif. Pour un essai gratuit, équivaut au prix standard complet (`original_price_local`), rien n'étant facturé. `null` lorsqu'une offre a été appliquée mais que le prix standard est inconnu (voir `original_price_local`). Toujours `null` pour les offres App Store avec paiement anticipé : le montant unique versé couvre plusieurs périodes de facturation et ne peut donc pas être comparé au prix standard par période. | | **discount_amount_usd** | Float | Valeur de `discount_amount_local` en USD. | | **environment** | String | Valeurs possibles : `Sandbox` ou `Production`. | | **event_datetime** | ISO 8601 date | Date et heure de l'événement. Identique à la valeur au niveau racine de l'événement. | | **original_price_local** | Float | Prix standard non remisé du produit avant la commission Apple/Google, en devise locale. Pour les abonnements, il s'agit du prix de renouvellement. Égale `price_local` pour un achat au plein tarif et toujours égale `price_local` pour les achats uniques, les stores ne communiquant pas de prix standard distinct pour ceux-ci. `null` pour un achat remisé lorsque le store ne fournit pas de prix standard fiable (par exemple, le renouvellement automatique est désactivé, le renouvellement est toujours soumis à une offre, ou un changement de produit est en attente). | | **original_price_usd** | Float | Identique à `original_price_local`, en USD. | | **original_purchase_date** | ISO 8601 date | Pour les abonnements récurrents, l'achat d'origine est la première transaction de la chaîne, dont l'ID — appelé ID de transaction d'origine — relie la chaîne de renouvellements ; les transactions ultérieures en sont des extensions. La date d'achat d'origine est la date et l'heure de cette première transaction. | | **original_transaction_id** | String | <p>Pour les abonnements récurrents, il s'agit de l'ID de transaction d'origine qui relie la chaîne de renouvellements. La transaction d'origine est la première de la chaîne ; les transactions ultérieures en sont des extensions.</p><p>En l'absence d'extension, `original_transaction_id` correspond à store_transaction_id.</p> | | **paywall_name** | String | Nom du paywall dont est issue la transaction. | | **paywall_revision** | String | Révision du paywall dont est issue la transaction. La valeur par défaut est 1. | | **price_local** | Float | Montant facturé pour la transaction avant la commission Apple/Google, en devise locale. `null` pour les essais gratuits, rien n'étant facturé. | | **price_usd** | Float | Montant facturé pour la transaction avant la commission Apple/Google, en USD. `null` pour les essais gratuits, rien n'étant facturé. | | **profile_country** | String | Déterminé par Adapty, sur la base de l'IP du profil. | | **profile_event_id** | UUID | ID d'événement unique pouvant être utilisé pour la déduplication. | | **profile_has_access_level** | Boolean | Booléen indiquant si le profil dispose d'un niveau d'accès actif. | | **profile_id** | UUID | ID de profil généré par Adapty. Identique à la valeur au niveau racine de l'événement. | | **profile_ip_address** | String | IP du profil (IPv4 ou IPv6, avec préférence pour IPv4 si disponible). `null` si **Collect users' IP addresses** est désactivé dans les [paramètres de l'application](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Revenus totaux du profil, remboursements déduits. | | **promotional_offer_id** | String | ID Adapty de l'[offre promotionnelle](offers) utilisée. Cet ID est défini lors de la création de l'offre dans le tableau de bord. | | **purchase_date** | ISO 8601 date | Date et heure de l'achat du produit. | | **rate_after_first_year** | Boolean | Booléen indiquant que l'abonnement est éligible à un taux de commission réduit (généralement 15 %) après un an de renouvellement continu. Les taux de commission varient selon l'éligibilité au programme et le pays. Voir [Commission du store et taxes](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) pour plus de détails. | | **store** | String | Store où le produit a été acheté. Valeurs standard : **app_store**, **play_store**, **stripe**, **paddle**. <br/>Si vous définissez des [transactions de store personnalisées](api-adapty/operations/setTransaction) via l'API côté serveur, la valeur du paramètre **store** est utilisée. | | **store_country** | String | Pays transmis par le store. | | **store_offer_category** | String | Catégorie d'offre appliquée. Valeurs possibles : `introductory`, `promotional`, `winback`. | | **store_offer_discount_type** | String | Type d'offre appliqué. Valeurs possibles : `free_trial`, `pay_as_you_go` et `pay_up_front`. | | **store_offer_number_of_periods** | Integer | Nombre de périodes de facturation de base remisées par l'offre (1 ou plus). Présent uniquement lorsqu'une offre est appliquée. `null` pour les offres App Store avec paiement anticipé et lorsque le store ne communique pas la durée de l'offre. | | **subscription_expires_at** | ISO 8601 date | Date d'expiration de l'abonnement. Généralement dans le futur. | | **transaction_id** | String | Identifiant unique d'une transaction. | | **trial_duration** | String | Durée de la période d'essai en jours. Transmise au format « {} days », par exemple « 7 days ». Présent uniquement pour les types d'événements liés aux essais : `trial_started`, `trial_converted`, `trial_cancelled`. | | **variation_id** | UUID | ID unique du paywall sur lequel l'achat a été effectué. | | **vendor_product_id** | String | <p>ID du produit dans l'Apple App Store, le Google Play Store ou Stripe.</p><p>Si l'accès a été accordé sans transaction réelle dans un store, `vendor_product_id` prendra l'une des valeurs suivantes :</p><ul><li>`adapty_server_side_product` — accordé via l'[API côté serveur](api-adapty/operations/grantAccessLevel).</li><li>`adapty_dashboard_product` — [accordé manuellement](give-access-level-to-specific-customer) dans l'Adapty Dashboard.</li><li>`adapty_promotion` — héritage.</li></ul> | #### Propriétés d'événement supplémentaires pour les taxes et revenus \{#additional-tax-and-revenue-event-properties\} Les propriétés d'événement liées aux taxes et aux revenus ci-dessous sont des champs supplémentaires qui s'appliquent uniquement à certains types d'événements. Cela signifie que les types d'événements listés incluent les [Propriétés d'événement pour la plupart des types d'événements](webhook-event-types-and-fields#for-most-event-types), ainsi que les champs supplémentaires listés ci-dessous. Types d'événements ayant les propriétés d'événement de taxes et revenus : - `subscription_renewed` - `subscription_initial_purchase` (également appelé `subscription_started` — même événement) - `subscription_refunded` - `non_subscription_purchase` | Field | Type | Description | | :-------------------- | :---- | :----------------------------------------------------------- | | **net_revenue_local** | Float | Revenu net (revenu après déduction d'Apple/Google et des taxes) en devise locale. | | **net_revenue_usd** | Float | Revenu net (revenu après déduction d'Apple/Google et des taxes) en USD. | | **proceeds_local** | Float | Prix du produit après déduction d'Apple/Google en devise locale. | | **proceeds_usd** | Float | Prix du produit après déduction d'Apple/Google. | | **tax_amount_local** | Float | Montant des taxes déduit en devise locale. | | **tax_amount_usd** | Float | Montant des taxes déduit en USD. | #### Exemple de payload `non_subscription_purchase` `non_subscription_purchase` suit la même structure que les événements d'abonnement, mais reflète un achat unique ou consommable. Les champs propres aux abonnements ne s'appliquent pas : `cancellation_reason`, `will_renew`, `is_in_grace_period`, `is_refund`, `is_lifetime` et `trial_duration` sont absents. `subscription_expires_at` est présent mais vaut `null`. Les champs de taxes et de revenus (`net_revenue_*`, `proceeds_*`, `tax_amount_*`) sont inclus. <details> <summary>Exemple de payload (cliquer pour développer)</summary> ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "event_type": "non_subscription_purchase", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "app_store", "currency": "USD", "price_usd": 4.99, "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "proceeds_usd": 4.2415, "proceeds_local": 4.2415, "net_revenue_usd": 4.2415, "net_revenue_local": 4.2415, "tax_amount_usd": 0, "tax_amount_local": 0, "profile_id": "00000000-0000-0000-0000-000000000000", "environment": "Production", "vendor_product_id": "100coins", "transaction_id": "0000000000000000", "original_transaction_id": "0000000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "original_purchase_date": "2024-11-15T10:45:36.181000+0000", "subscription_expires_at": null, "store_country": "US", "profile_country": "US", "profile_ip_address": "10.10.1.1", "profile_has_access_level": false, "profile_total_revenue_usd": 4.99, "consecutive_payments": 1, "rate_after_first_year": false, "profile_event_id": "00000000-0000-0000-0000-000000000000" }, "event_api_version": 1 } ``` </details> #### Pour l'événement Access Level Updated \{#for-access-level-updated-event\} L'événement **Access Level Updated** est un événement webhook spécifique, généré uniquement lorsque l'intégration Webhook est active et que ce type d'événement est activé. S'il est activé, il est envoyé au Webhook configuré et apparaît dans l'**Event Feed**. S'il n'est pas activé, l'événement ne sera pas créé. Si vous avez activé le [partage des niveaux d'accès](general#6-sharing-paid-access-between-user-accounts), l'événement **access level updated** sera envoyé pour tous les profils partageant le niveau d'accès. :::tip Utilisez cet événement pour mettre à jour le niveau d'accès de l'utilisateur dans votre base de données, accorder ou révoquer les fonctionnalités premium sur votre backend, et synchroniser les accès sur tous les appareils ou plateformes. ::: | Propriété | Type | Description | | ---------------------------------- | ------------- | ------------------------------------------------------------ | | **ab_test_name** | String | Nom du test A/B dont est issue la transaction. | | **access_level_id** | String | L'ID du niveau d'accès. | | **activated_at** | ISO 8601 date | Date et heure de la dernière activation de l'accès. | | **active_introductory_offer_type** | String | Type d'offre de lancement appliquée. Valeurs possibles : `free_trial`, `pay_as_you_go` et `pay_up_front`. | | **active_promotional_offer_id** | String | ID de l'offre promotionnelle tel qu'indiqué dans la section Product de l'Adapty Dashboard | | **active_promotional_offer_type** | String | Type d'offre promotionnelle appliquée. Valeurs possibles : `free_trial`, `pay_as_you_go` et `pay_up_front`. | | **base_plan_id** | String | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) dans le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) dans Stripe. | | **billing_issue_detected_at** | ISO 8601 date | Date et heure du problème de facturation. | | **cancellation_reason** | String | Raisons possibles d'annulation : `voluntarily_cancelled`, `billing_error`, `price_increase`, `product_was_not_available`, `refund`, `cancelled_by_developer`, `new_subscription_replace`, `upgraded`, `unknown`, `adapty_revoked`. | | **cohort_name** | String | Nom de l'audience à laquelle appartient le profil. | | **currency** | String | Devise locale (USD par défaut). | | **developer_id** | String | L'ID du placement dont est issue la transaction. | | **environment** | String | Valeurs possibles : `Sandbox` ou `Production`. | | **event_datetime** | ISO 8601 date | Date et heure de l'événement. | | **expires_at** | ISO 8601 date | Date et heure d'expiration de l'accès. | | **is_active** | Boolean | Indique si le niveau d'accès est actif. | | **is_in_grace_period** | Boolean | Indique si le profil est en délai de grâce. | | **is_lifetime** | Boolean | Indique si le niveau d'accès est à vie. | | **is_refund** | Boolean | Indique si la transaction est un remboursement. | | **original_purchase_date** | ISO 8601 date | Pour les abonnements récurrents, l'achat original est la première transaction de la chaîne, dont l'ID (appelé ID de transaction original) relie la chaîne de renouvellements ; les transactions suivantes en sont des extensions. La date d'achat original correspond à la date et l'heure de cette première transaction. | | **original_transaction_id** | String | <p>Pour les abonnements récurrents, il s'agit de l'ID de transaction original qui relie la chaîne de renouvellements. La transaction originale est la première de la chaîne ; les transactions suivantes en sont des extensions.</p><p>En l'absence d'extensions, `original_transaction_id` correspond à store_transaction_id.</p>Identifiant de transaction de l'achat original. | | **paywall_name** | String | Nom du paywall dont est issue la transaction. | | **paywall_revision** | String | Révision du paywall dont est issue la transaction. La valeur par défaut est 1. | | **profile_country** | String | Déterminé par Adapty, d'après l'IP du profil. | | **profile_event_id** | UUID | ID d'événement unique pouvant être utilisé pour la déduplication. | | **profile_has_access_level** | Boolean | Indique si le profil dispose d'un niveau d'accès actif. | | **profile_id** | UUID | ID de profil utilisateur interne Adapty. | | **profile_ip_address** | String | IP du profil (IPv4 ou IPv6, IPv4 étant privilégiée si disponible). `null` si **Collect users' IP addresses** est désactivé dans les [paramètres de l'app](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Revenus totaux du profil, remboursements inclus. | | **purchase_date** | ISO 8601 date | Date et heure de l'achat du produit. | | **renewed_at** | ISO 8601 date | Date et heure de renouvellement de l'accès. | | **starts_at** | ISO 8601 date | Date et heure de début du niveau d'accès. | | **store** | String | Store où le produit a été acheté. Valeurs standard : **app_store**, **play_store**, **stripe**, **paddle**. <br/>Si vous configurez des [transactions de store personnalisées](api-adapty/operations/setTransaction) via l'API serveur, la valeur du paramètre **store** est utilisée. | | **store_country** | String | Pays transmis à Adapty par le store. | | **subscription_expires_at** | ISO 8601 date | Date d'expiration de l'abonnement. | | **transaction_id** | String | Identifiant unique d'une transaction. | | **trial_duration** | String | Durée de la période d'essai en jours (ex. : « 7 days »). | | **variation_id** | UUID | Identifiant d'une variante, utilisé pour attribuer les achats à ce paywall. | | **vendor_product_id** | String | <p>ID du produit dans le store (Apple/Google/Stripe).</p><p>Si l'accès a été accordé sans transaction réelle dans un store, `vendor_product_id` sera l'une des valeurs suivantes :</p><ul><li>`adapty_server_side_product` — accordé via l'[API serveur](api-adapty/operations/grantAccessLevel).</li><li>`adapty_dashboard_product` — [accordé manuellement](give-access-level-to-specific-customer) dans l'Adapty Dashboard.</li><li>`adapty_promotion` — héritage.</li></ul> | | **will_renew** | Boolean | Indique si le niveau d'accès payant sera renouvelé. | :::warning Notez que cette structure peut évoluer dans le temps — de nouvelles données pouvant être introduites par nous ou par les tiers avec lesquels nous travaillons. Assurez-vous que votre code qui la traite est suffisamment robuste et repose sur des champs spécifiques plutôt que sur la structure entière. ::: --- # File: set-up-webhook-integration --- --- title: "Configurer l'intégration webhook" description: "Configurez l'intégration webhook dans Adapty pour automatiser le suivi des événements." --- L'[intégration webhook](webhook) d'Adapty se compose des étapes suivantes : <img src="/assets/shared/img/webhook-setup.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> 1. **Vous configurez votre endpoint :** 1. Assurez-vous que votre serveur peut traiter les requêtes Adapty avec l'en-tête **Content-Type** défini sur `application/json`. 2. Configurez votre serveur pour recevoir la requête de vérification d'Adapty et répondre avec n'importe quel statut `2xx` et un corps JSON. 3. [Gérez les événements d'abonnement](#subscription-events) une fois la connexion vérifiée. 2. **Vous configurez et activez l'intégration webhook** dans l'[Adapty Dashboard](#configure-webhook-integration-in-the-adapty-dashboard). Vous pouvez également [mapper les événements Adapty vers des noms d'événements personnalisés](#configure-webhook-integration-in-the-adapty-dashboard). Nous recommandons de tester dans l'**environnement Sandbox** avant de passer en production. 3. **Adapty envoie une requête de vérification** à votre serveur. 4. **Votre serveur répond** avec un statut `2XX` et un corps JSON. 5. **Une fois qu'Adapty reçoit une réponse valide, il commence à envoyer les événements d'abonnement.** ## Configurer votre serveur pour traiter les requêtes Adapty \{#set-up-your-server-to-process-adapty-requests\} Adapty enverra à votre endpoint webhook 2 types de requêtes : 1. [Requête de vérification](#verification-request) : la requête initiale pour vérifier que la connexion est correctement configurée. Cette requête ne contiendra aucun événement et sera envoyée au moment où vous cliquerez sur le bouton **Save** dans l'intégration Webhook de l'Adapty Dashboard. Pour confirmer que votre endpoint a bien reçu la requête de vérification, votre endpoint doit répondre avec la réponse de vérification. 2. [Événement d'abonnement](#subscription-events) : une requête standard qu'Adapty envoie chaque fois qu'un événement est créé dans son système. Votre serveur n'a pas besoin de répondre avec une réponse spécifique. La seule chose dont le serveur Adapty a besoin est de recevoir une réponse HTTP standard avec le code 200 s'il reçoit bien le message. ### Requête de vérification \{#verification-request\} Après avoir activé l'intégration webhook dans l'Adapty Dashboard, Adapty enverra une requête POST de vérification contenant un objet JSON vide `{}` en corps. Configurez votre endpoint pour que l'**en-tête Content-Type** soit `application/json`, c'est-à-dire que l'endpoint de votre serveur doit s'attendre à ce que la requête webhook entrante ait son contenu formaté en JSON. Votre serveur doit répondre avec un code de statut 2xx et envoyer n'importe quelle réponse JSON valide, par exemple : ```json title="Json" {} ``` Une fois qu'Adapty reçoit la réponse de vérification dans le bon format et avec un code de statut 2xx, votre intégration webhook Adapty est entièrement configurée. ### Événements d'abonnement \{#subscription-events\} Les événements d'abonnement sont envoyés avec l'en-tête **Content-Type** défini sur `application/json` et contiennent les données d'événement au format JSON. Pour les types d'événements possibles et les structures de requêtes, consultez [Types d'événements webhook et champs](webhook-event-types-and-fields). ## Configurer l'intégration webhook dans l'Adapty Dashboard \{#configure-webhook-integration-in-the-adapty-dashboard\} Dans Adapty, vous pouvez configurer des flows distincts pour les événements de production et les événements de test reçus depuis l'environnement sandbox d'Apple ou de Stripe, ou depuis un compte de test Google. :::tip Adapty prend en charge une seule URL webhook par environnement (production et sandbox). Pour envoyer des événements à plusieurs services, pointez le webhook vers votre propre backend et distribuez-les depuis là. ::: Pour les événements de production, utilisez le champ **Production endpoint URL** en spécifiant l'URL à laquelle les callbacks seront envoyés. Configurez également le champ **Authorization header value for production endpoint** — l'en-tête que votre serveur utilisera pour authentifier les événements Adapty. Notez que nous utiliserons la valeur spécifiée dans le champ **Authorization header value for production endpoint** comme en-tête `Authorization` exactement telle quelle, sans aucune modification ni ajout. Pour les événements de test, utilisez les champs **Sandbox endpoint URL** et **Authorization header value for sandbox endpoint** en conséquence. Pour configurer l'intégration webhook : 1. Ouvrez [Integrations -> Webhook](https://app.adapty.io/integrations/customwebhook) dans votre Adapty Dashboard. <img src="/assets/shared/img/webhook_integration.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Activez le bouton pour lancer l'intégration. 4. Remplissez les champs d'intégration : | Champ | Description | | ------------------------------------------------------ | ------------------------------------------------------------ | | **Production endpoint URL** | L'URL qu'Adapty utilise pour envoyer des requêtes HTTP POST pour les événements en production. | | **Authorization header value for production endpoint** | <p>L'en-tête que votre serveur utilisera pour authentifier les requêtes d'Adapty en production. Notez que nous utiliserons la valeur spécifiée dans ce champ comme en-tête `Authorization` exactement telle quelle, sans aucune modification ni ajout.</p><p></p><p>Bien que non obligatoire, il est vivement recommandé pour une sécurité renforcée.</p> | De plus, pour vos besoins de test dans l'environnement sandbox, deux autres champs sont disponibles : | Champ de test | Description | | --------------------------------------------------- | ------------------------------------------------------------ | | **Sandbox endpoint URL** | L'URL qu'Adapty utilise pour envoyer des requêtes HTTP POST pour les événements dans l'environnement sandbox. | | **Authorization header value for sandbox endpoint** | <p>L'en-tête que votre serveur utilisera pour authentifier les requêtes d'Adapty lors des tests dans l'environnement sandbox. Notez que nous utiliserons la valeur spécifiée dans ce champ comme en-tête `Authorization` exactement telle quelle, sans aucune modification ni ajout.</p><p></p><p>Bien que non obligatoire, il est vivement recommandé pour une sécurité renforcée.</p> | 4. (facultatif) Choisissez les événements que vous souhaitez recevoir et mappez leurs noms. Consultez nos [Flows d'événements](event-flows) pour voir quels événements sont déclenchés dans différentes situations. Si vos identifiants d'événements diffèrent de ceux utilisés dans Adapty, conservez les identifiants de votre système tels quels et remplacez les identifiants d'événements Adapty par défaut par les vôtres dans la section **Events names** de la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). L'identifiant d'événement peut être n'importe quelle chaîne de caractères ; assurez-vous simplement que l'identifiant d'événement dans votre serveur de traitement webhook correspond à celui que vous avez saisi dans l'Adapty Dashboard. Vous ne pouvez pas laisser l'identifiant d'événement vide pour les événements activés. <img src="/assets/shared/img/86942b8-event_names_renaming.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Les champs et options supplémentaires ne sont pas obligatoires ; utilisez-les selon vos besoins : | Paramètre | Description | | :--------------------------------- | :----------------------------------------------------------- | | **Send Trial Price** | Lorsque cette option est activée, Adapty inclura le prix de l'abonnement dans les champs `price_local` et `price_usd` pour l'événement **Trial Started**. | | **Exclude Historical Events** | Choisissez d'exclure les événements survenus avant que l'utilisateur n'installe l'application avec le SDK Adapty. Cela évite la duplication des événements et garantit des rapports précis. Par exemple, si un utilisateur a activé un abonnement mensuel le 10 janvier et mis à jour l'application avec le SDK Adapty le 6 mars, Adapty ignorera les événements antérieurs au 6 mars et conservera les événements suivants. | | **Send user attributes** | Activez cette option pour envoyer les attributs spécifiques à l'utilisateur, tels que les préférences de langue. Ces attributs apparaîtront dans le champ `user_attributes`. Consultez [Champs d'événement](webhook-event-types-and-fields#event-fields) pour plus d'informations. | | **Send attribution** | Activez cette option pour inclure les informations d'attribution (par exemple, les données AppsFlyer) dans le champ `attributions`. Consultez la section [Données d'attribution](webhook-event-types-and-fields#attributions) pour plus de détails. | | **Send Play Store purchase token** | Activez cette option pour recevoir le token Play Store requis pour la revalidation des achats, si nécessaire. Son activation ajoutera le paramètre `play_store_purchase_token` à l'événement. Pour plus de détails sur son contenu, consultez la section [Token d'achat Play Store](webhook-event-types-and-fields#play-store-purchase-token). | 6. N'oubliez pas de cliquer sur le bouton **Save** pour confirmer les modifications. Au moment où vous cliquez sur le bouton **Save**, Adapty enverra une requête de vérification et attendra la réponse de vérification de votre serveur. ### Choisir les événements à envoyer et mapper les noms d'événements \{#choose-events-to-send-and-map-event-names\} Choisissez les événements que vous souhaitez recevoir sur votre serveur en activant le bouton correspondant. Si vos noms d'événements diffèrent de ceux utilisés dans Adapty et que vous devez conserver vos noms tels quels, vous pouvez configurer le mapping en remplaçant les noms d'événements Adapty par défaut par les vôtres dans la section **Events names** de la page [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). <img src="/assets/shared/img/86942b8-event_names_renaming.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Le nom d'événement peut être n'importe quelle chaîne de caractères. Vous ne pouvez pas laisser les champs vides pour les événements activés. Si vous avez accidentellement supprimé un nom d'événement Adapty, vous pouvez toujours le copier depuis la rubrique [Événements à envoyer aux intégrations tierces](events). ## Gérer les événements webhook \{#handle-webhook-events\} Les webhooks sont généralement envoyés dans un délai de 5 à 60 secondes après la survenue de l'événement. Les événements d'annulation, en revanche, peuvent prendre jusqu'à 2 heures à être envoyés après qu'un utilisateur annule son abonnement. Si le code de statut de la réponse de votre serveur est en dehors de la plage 200-404, Adapty relance la livraison avec un backoff exponentiel. La première relance survient environ **1 minute** après l'échec initial, en doublant à chaque tentative suivante — jusqu'à 9 relances réparties sur 24 heures. Nous vous suggérons de configurer votre webhook pour effectuer uniquement une validation de base du corps de l'événement envoyé par Adapty avant de répondre. Si votre serveur ne peut pas traiter l'événement et que vous ne souhaitez pas qu'Adapty effectue de nouvelles tentatives, utilisez un code de statut dans la plage 200-404. Gérez également toutes les tâches chronophages de manière asynchrone et répondez rapidement à Adapty. Si Adapty ne reçoit pas de réponse dans les 10 secondes, il considérera la tentative comme un échec et effectuera une nouvelle tentative. --- # File: test-webhook --- --- title: "Tester l'intégration webhook" description: "Testez les intégrations webhook dans Adapty pour automatiser le suivi des événements d'abonnement." --- Une fois votre intégration configurée, il est temps de la tester. Vous pouvez tester aussi bien votre intégration sandbox que votre intégration de production. Nous recommandons de commencer par le sandbox et d'y valider le maximum de cas : - Les événements sont bien envoyés et correctement reçus. - Les options sont correctement configurées pour les événements historiques, le prix de l'abonnement pour l'événement **Trial started**, l'attribution, les attributs utilisateur, et le token d'achat Google Play Store — envoyés ou non avec un événement. - Les noms d'événements sont correctement mappés et votre serveur peut les traiter. ## Comment tester \{#how-to-test\} Avant de commencer à tester une intégration, assurez-vous d'avoir : 1. Configuré l'intégration webhook comme décrit dans la rubrique [Configurer l'intégration webhook](set-up-webhook-integration). 2. Configuré l'environnement comme décrit dans les rubriques [Tester les achats intégrés dans l'App Store Apple](test-purchases-in-sandbox) et [Tester les achats intégrés dans Google Play Store](testing-on-android). Vérifiez que votre application de test a bien été compilée en environnement sandbox et non en production. 3. Effectué un achat / démarré un essai / effectué un remboursement qui déclenchera un événement que vous avez choisi d'envoyer au webhook. Par exemple, pour obtenir l'événement **Subscription started**, souscrivez un nouvel abonnement. ## Validation du résultat \{#validation-of-the-result\} ### Résultat d'envoi d'événements réussi \{#successful-sending-events-result\} En cas d'intégration réussie, un événement apparaîtra dans la section **Last sent events** de l'intégration et aura le statut **Success**. <img src="/assets/shared/img/6ccc3bb-webhook_integration_success.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Résultat d'envoi d'événements échoué \{#unsuccessful-sending-events-result\} | Problème | Solution | |-----|--------| | L'événement n'est pas apparu | Votre achat n'a pas eu lieu et l'événement n'a donc pas été créé. Consultez la rubrique [Résoudre les problèmes d'achats de test](troubleshooting-test-purchases) pour trouver une solution. | | L'événement est apparu avec le statut **Sending failed** | <p>Nous déterminons la délivrabilité en fonction du statut HTTP et considérons tout ce qui est **en dehors de la plage 200-399** comme un échec.</p><p>Pour en savoir plus sur le problème, survolez le statut **Sending failed** de votre événement en échec comme indiqué ci-dessous.</p> | <img src="/assets/shared/img/12ff189-hover_sending_failed.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: handle-integration-errors --- --- title: "Gérer les erreurs dans les intégrations" description: "Gérer les erreurs dans les intégrations" --- Lorsque vous utilisez des intégrations d'attribution, de messagerie ou d'analytique, vous pouvez rencontrer certaines erreurs courantes. Consultez ce guide pour les cas de dépannage. ## Écart de données \{#data-discrepancy\} **Raison** : Cela peut se produire car tous vos utilisateurs n'utilisent pas la version de l'application qui intègre le SDK Adapty. **Solution** : Pour garantir la cohérence des données, vous pouvez forcer vos utilisateurs à mettre à jour l'application vers une version intégrant le SDK Adapty. ## Erreurs réseau \{#network-errors\} **Raison** : Cela est très probablement dû à une absence de connexion Internet entre le serveur Adapty et le serveur d'intégration. **Solution** : Ces problèmes ne durent généralement pas longtemps et n'affectent qu'un faible nombre d'événements. ## Échec du traitement de l'événement par le serveur d'intégration \{#integration-server-failed-to-process-the-event\} **Raison** : L'intégration est configurée de manière incorrecte. **Solution** : Consultez l'article sur l'intégration dans notre documentation. Assurez-vous d'avoir effectué toutes les étapes de configuration dans l'Adapty Dashboard, du côté de l'outil tiers, et dans le code de votre application. ## Données d'intégration manquantes \{#missing-integration-data\} **Raison** : Le profil ne contient pas certains identifiants spécifiques à l'intégration. Cela peut se produire lorsque l'intégration n'est pas correctement configurée dans le code de l'application. **Solution** : Consultez l'article sur l'intégration dans notre documentation. Assurez-vous d'avoir implémenté les méthodes issues des extraits de code dans votre application et que ces méthodes interagissent bien avec les profils de vos utilisateurs. ## Identifiants d'intégration manquants \{#missing-integration-credentials\} **Raison** : Certains identifiants d'intégration sont manquants ou incorrects. **Solution** : Vérifiez tous les identifiants de cette intégration dans l'Adapty Dashboard. Le problème peut être lié à une incompatibilité de version ou d'environnement. ## L'événement a expiré \{#the-event-has-expired\} **Raison** : L'option **Exclude historical events** est activée dans les paramètres de l'intégration, et la date de création de l'événement est antérieure à la date de création du profil dans notre système. Cela peut se produire lorsqu'une chaîne de transactions remontant à plusieurs années arrive dans Adapty via la validation de reçu pour un profil créé récemment. **Solution** : Assurez-vous que cela ne se produise pas pour les nouveaux événements. Si vous souhaitez envoyer des événements historiques à l'intégration, désactivez **Exclude historical events**. ## Type d'événement désactivé ou non pris en charge \{#disabledunsupported-event-type\} **Raison** : Soit l'événement n'est pas pris en charge par cette intégration, soit vous l'avez désactivé lors de la configuration de l'intégration. Par exemple, les événements `access_level_updated` ne sont pas pris en charge par la plupart des intégrations. **Solution** : Vérifiez dans la documentation de l'intégration si ce type d'événement est pris en charge. Si c'est le cas, dans l'Adapty Dashboard, assurez-vous que ce type d'événement est bien activé dans les paramètres de l'intégration. --- # File: manage-adapty-with-ai --- --- title: "Gérer Adapty avec des agents IA et des outils de code" description: "Toutes les façons d'utiliser Adapty avec l'IA — intégrer le SDK avec un agent de code, interroger vos analytics avec un LLM, et alimenter vos outils IA avec la documentation Adapty." --- Adapty fonctionne avec les outils de code IA et les agents. Utilisez-les pour intégrer le SDK, interroger vos analytics ou consulter la documentation Adapty sans quitter votre éditeur. Cette page liste ce qui est disponible et à qui chaque outil est destiné. ## Intégrer le SDK Adapty avec l'IA \{#integrate-the-adapty-sdk-with-ai\} Deux façons d'ajouter le SDK Adapty à votre application avec un outil de code IA. Les deux fonctionnent avec Cursor, Claude et d'autres assistants IA. ### Intégration par compétence \{#skill-based-integration\} La compétence d'intégration du SDK Adapty effectue toute l'intégration depuis votre outil de code IA en une seule commande. Utilisez-la quand vous souhaitez une configuration guidée et automatisée. Choisissez votre plateforme : [iOS](adapty-sdk-integration-skill) · [Android](adapty-sdk-integration-skill-android) · [React Native](adapty-sdk-integration-skill-react-native) · [Flutter](adapty-sdk-integration-skill-flutter) · [Unity](adapty-sdk-integration-skill-unity) · [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) · [Capacitor](adapty-sdk-integration-skill-capacitor) ### Intégration étape par étape \{#step-by-step-integration\} Guidez votre outil IA à travers l'intégration étape par étape, en lui fournissant les bonnes docs dans l'ordre. Utilisez-la quand vous souhaitez revoir chaque étape au fur et à mesure. Choisissez votre plateforme : [iOS](adapty-cursor) · [Android](adapty-cursor-android) · [React Native](adapty-cursor-react-native) · [Flutter](adapty-cursor-flutter) · [Unity](adapty-cursor-unity) · [Kotlin Multiplatform](adapty-cursor-kmp) · [Capacitor](adapty-cursor-capacitor) ## Gérer Adapty depuis la ligne de commande \{#manage-adapty-from-the-command-line\} Le [CLI développeur Adapty](developer-cli-quickstart) vous permet de gérer vos entités Adapty — applications, niveaux d'accès, produits, paywalls et placements — depuis le terminal, sans ouvrir le tableau de bord. Comme c'est un outil en ligne de commande, votre agent de code IA peut l'exécuter directement. ## Interroger vos données \{#ask-about-your-data\} Connectez un agent de code IA à l'API Export Analytics pour interroger vos métriques en langage naturel — revenus, rétention, LTV, et plus encore. Aucun serveur MCP n'est requis. [Interroger l'IA sur vos données analytics](export-analytics-with-ai) ## Fournir la documentation Adapty à votre outil IA \{#give-your-ai-tool-the-adapty-docs\} ### Docs en texte brut \{#plain-text-docs\} Chaque doc Adapty est disponible en Markdown — ajoutez `.md` à l'URL de la page, ou cliquez sur **Copy for LLM** sous le titre. Pour un contexte plus large, donnez à votre outil l'index [`llms.txt`](https://adapty.io/docs/fr/llms.txt) ou un sous-ensemble spécifique à une plateforme comme [`ios-llms.txt`](https://adapty.io/docs/fr/ios-llms.txt). ### Context7 \{#context7\} [Context7](https://context7.com/adaptyteam/adapty-docs) est un serveur MCP qui fournit la documentation Adapty à votre outil IA, mais il n'indexe que les extraits de code — pas le texte complet. Utilisez-le pour des exemples de code rapides ; pour des conseils complets, fournissez à votre outil les docs en texte brut ci-dessus. Context7 fonctionne avec Cursor, Claude Code, Windsurf et d'autres outils compatibles MCP. --- # File: export-analytics-with-ai --- --- title: "Interroger l'IA sur vos données analytiques" description: "Interrogez vos données analytiques Adapty en langage naturel avec un agent IA, via l'API Export Analytics." --- Posez des questions à un agent IA sur vos données analytiques Adapty en langage naturel — revenus, conversions, rétention, LTV — et laissez-le récupérer les chiffres pour vous. Connectez un outil capable d'effectuer des appels API à l'[API Export Analytics](https://adapty.io/docs/fr/export-analytics-api.md), et il interroge vos métriques à la demande. ## Ce que vous pouvez demander \{#what-you-can-ask-about\} L'API Export Analytics retourne les mêmes métriques que celles affichées dans les graphiques du tableau de bord Adapty. Chaque métrique possède sa propre opération : | Métrique | Ce qu'elle couvre | Opération | | --- | --- | --- | | Revenus, MRR, ARR, ARPU | Argent généré dans le temps, groupé par période, pays ou campagne | [retrieveAnalyticsData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveAnalyticsData.md) | | Rétention par cohorte | Combien de temps les abonnés d'une cohorte donnée continuent à payer | [retrieveCohortData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveCohortData.md) | | Taux de conversion | Combien d'utilisateurs progressent d'une étape ou d'un canal au suivant | [retrieveConversionData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveConversionData.md) | | Churn et entonnoir | Où les utilisateurs abandonnent et à quelle vitesse ils se désabonnent | [retrieveFunnelData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveFunnelData.md) | | Valeur vie (LTV) | Revenu moyen par segment d'utilisateurs dans le temps | [retrieveLTVData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveLTVData.md) | | Rétention | Part des utilisateurs toujours actifs après un certain nombre de jours | [retrieveRetentionData](https://adapty.io/docs/fr/api-export-analytics/operations/retrieveRetentionData.md) | Pour la liste complète des paramètres et filtres, consultez la [référence API](https://adapty.io/docs/fr/api-export-analytics.md). ## Avant de commencer \{#before-you-start\} Il vous faut trois éléments : - **Un compte Adapty avec des données** : L'API retourne les mêmes métriques que les graphiques de votre tableau de bord, donc votre application doit déjà collecter des données analytiques. - **Une clé API secrète** : Trouvez-la dans [App settings → General](https://app.adapty.io/settings/general), dans le champ **Secret key**. Les clés sont spécifiques à chaque application, utilisez donc une clé distincte pour chacune. Stockez-la dans une variable d'environnement (par exemple, `ADAPTY_SECRET_KEY`) pour que votre agent puisse la lire sans que vous ayez à la coller dans le chat. - **Un outil IA capable d'appeler des API** : Par exemple, Claude Code, Cursor, ou Claude Desktop avec un outil fetch. Les outils de chat classiques comme claude.ai ou ChatGPT ne peuvent pas appeler l'API directement. ## Fournir la spécification API à votre agent \{#give-your-agent-the-api-spec\} La [spécification OpenAPI](https://adapty.io/docs/fr/api-specs/export-analytics-api.yaml) décrit chaque endpoint, l'en-tête d'authentification, le corps de la requête et des exemples de réponses. Une fois que votre agent dispose de la spec, il construit des requêtes correctes sans que vous ayez à écrire le moindre code. Fournissez la spec à votre agent par URL : - **Collez l'URL** : Si votre agent peut récupérer des URLs, donnez-lui `https://adapty.io/docs/fr/api-specs/export-analytics-api.yaml` et demandez-lui de lire la spec. - **Utilisez un outil fetch** : Si votre agent dispose d'un outil qui récupère des URLs (par exemple, un serveur MCP fetch), pointez-le vers la même URL. La spec définit l'URL de base sur `https://api-admin.adapty.io`, donc votre agent a tout ce dont il a besoin dès que votre clé est dans l'environnement. ## Interroger vos données \{#ask-about-your-data\} Une fois la spec chargée et votre clé dans une variable d'environnement, décrivez la métrique souhaitée en langage naturel. Exemples de questions : ``` What was my MRR at the end of each month this year, and how does it compare to last year? Show my trial-to-paid conversion rate for the last 90 days, broken down by product. Which countries drive the most revenue from my yearly subscription? Top 10. How is week-1 retention trending for subscribers who started in the last 6 months? What's the refund rate on my annual plan since launch, by month? Compare LTV for paid-campaign users vs. organic over the last year, and export it as CSV. ``` L'agent associe votre demande à la bonne opération, lit la clé depuis l'environnement et retourne les données. Les réponses sont en JSON par défaut. Demandez un CSV si vous voulez un fichier prêt à utiliser dans un tableur — l'agent définit alors `format` sur `csv` dans le corps de la requête. :::warning Gardez votre clé secrète dans une variable d'environnement — ne la collez pas dans le chat et ne la commitez pas dans un fichier de règles. Les clés sont spécifiques à chaque application, donc renouvelez la vôtre dans **Settings → General** si elle est compromise. Consultez [rotation des clés API](https://adapty.io/docs/fr/export-analytics-api-authorization.md). ::: ## Configurer une fois pour une utilisation répétée \{#set-up-once-for-repeated-use\} Pour éviter de refaire la configuration à chaque session, enregistrez la spec et la clé là où votre agent peut les réutiliser : - **Sauvegardez le lien de la spec** : Ajoutez l'URL de la spec aux règles ou au fichier mémoire de votre agent (par exemple, un fichier `CLAUDE.md` ou un fichier de règles Cursor) pour qu'elle se charge à chaque session. - **Stockez la clé dans votre environnement** : Conservez `ADAPTY_SECRET_KEY` dans votre profil shell ou le gestionnaire de secrets de l'outil, pour ne plus jamais avoir à la coller. - **Sauvegardez des prompts réutilisables ou créez une compétence personnalisée** : Gardez vos questions courantes comme prompts enregistrés, ou encapsulez-les dans une compétence personnalisée ou une commande slash pour que votre agent génère un rapport à la demande. ## Limites \{#limits\} Gardez ces contraintes à l'esprit : - **Limite de débit** : L'API autorise 2 requêtes par seconde par clé API. En cas de dépassement, une erreur `429 Too Many Requests` est retournée. Indiquez à votre agent d'attendre et de réessayer en cas de `429`. - **Clés spécifiques à chaque application** : Chaque clé fonctionne pour une seule application. Pour récupérer des données de plusieurs applications, fournissez la clé correspondante pour chacune. - **Format de sortie** : Les réponses sont en JSON par défaut. Définissez `format` sur `csv` dans le corps de la requête pour un export CSV. Pour les règles complètes d'authentification et de format des requêtes, consultez [Autorisation et format des requêtes](https://adapty.io/docs/fr/export-analytics-api-authorization.md). --- # File: handle-webhooks-with-ai --- --- title: "Gérer les événements d'abonnement Adapty avec les webhooks" description: "Recevez et gérez les événements d'abonnement Adapty sur votre serveur avec les webhooks — configuration de l'endpoint, authentification, payload et tests en une seule page." --- Les webhooks permettent à votre serveur de recevoir en temps réel les événements d'abonnement Adapty — achats, renouvellements, annulations, problèmes de facturation et remboursements — afin d'accorder des accès, synchroniser votre backend ou déclencher des workflows. Ce guide vous accompagne de la configuration de l'endpoint jusqu'à une intégration vérifiée et testée en une seule page, et montre comment confier l'écriture du handler à un agent de codage IA. :::tip Vous utilisez un agent de codage IA ? Cliquez sur **Copy for LLM** sous le titre et collez toute cette page dans votre agent — il y trouvera la configuration, le payload et la logique du handler dont il a besoin. ::: ## Comment fonctionnent les webhooks Adapty \{#how-adapty-webhooks-work\} - **Unidirectionnel et temps réel** : Adapty envoie un `POST` HTTP à votre serveur dès qu'un événement se produit — pas de polling. - **Deux types de requêtes** : Une requête de vérification unique (envoyée à la sauvegarde de l'intégration) et les événements d'abonnement continus. - **Une URL par environnement** : Vous configurez un endpoint distinct pour la production et pour le sandbox. - **Vous accusez réception de chaque requête** : Répondez rapidement avec un statut `2xx`, et Adapty relance en cas d'échec. ## Créer votre endpoint \{#build-your-endpoint\} Créez un endpoint HTTPS public qui gère deux types de requêtes : - **Requête de vérification** : Envoyée une seule fois à la sauvegarde de l'intégration. Elle a un corps JSON vide (`{}`). Répondez avec un statut `2xx` et un corps JSON. - **Événements d'abonnement** : Requêtes `POST` continues avec l'événement dans le corps. Répondez `200` en moins de 10 secondes, puis effectuez tout travail lourd de manière asynchrone. Choisissez une chaîne secrète et stockez-la comme variable d'environnement (par exemple, `ADAPTY_WEBHOOK_SECRET`). À chaque requête, vérifiez que l'en-tête `Authorization` correspond bien, et rejetez la requête dans le cas contraire — vous saisirez ce même secret dans le tableau de bord ensuite. ```javascript title="webhook.js" const app = express(); app.use(express.json()); const WEBHOOK_SECRET = process.env.ADAPTY_WEBHOOK_SECRET; app.post("/adapty/webhook", (req, res) => { // 1. Verify the shared secret Adapty echoes back. if (req.get("Authorization") !== WEBHOOK_SECRET) { return res.sendStatus(401); } // 2. Acknowledge fast, then process asynchronously. res.status(200).json({}); // 3. The verification request has an empty body — nothing to handle. const event = req.body; if (!event.event_type) return; switch (event.event_type) { case "subscription_started": case "subscription_renewed": case "trial_converted": // Grant or extend access. break; case "subscription_expired": case "subscription_refunded": // Revoke access. break; default: break; } }); app.listen(3000); ``` Déployez l'endpoint sur une URL HTTPS publique avant de configurer l'intégration — Adapty envoie la requête de vérification dès que vous sauvegardez. ### Événements clés et le payload \{#key-events-and-the-payload\} Chaque événement partage la même enveloppe. Les champs varient selon le type d'événement, le store et les options que vous avez activées. Voici un événement `subscription_started` simplifié : ```json title="Example event" { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "event_type": "subscription_started", "event_datetime": "2024-11-15T10:45:36.181000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "vendor_product_id": "onemonth_no_trial", "transaction_id": "0000000000000000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2024-12-15T10:45:36.181000+0000", "profile_event_id": "00000000-0000-0000-0000-000000000000" }, "event_api_version": 1 } ``` Les événements que vous traiterez le plus souvent : | Type d'événement | Se déclenche quand | | --- | --- | | `subscription_started` | Un utilisateur démarre un abonnement payant | | `subscription_renewed` | Un abonnement se renouvelle et est facturé avec succès | | `subscription_renewal_cancelled` | Un utilisateur désactive le renouvellement automatique (l'accès dure jusqu'à l'expiration) | | `subscription_expired` | L'accès prend fin après l'expiration d'un abonnement non renouvelé | | `trial_started` | Un utilisateur démarre un essai gratuit | | `trial_converted` | Un essai se convertit en abonnement payant | | `billing_issue_detected` | Un paiement de renouvellement échoue | | `subscription_refunded` | Un achat d'abonnement est remboursé | Pour la liste complète des événements et tous les champs, consultez [Types d'événements et champs webhook](https://adapty.io/docs/fr/webhook-event-types-and-fields.md). :::warning N'ordonnez pas les événements par `event_datetime` — c'est l'heure métier de l'événement, les événements peuvent donc arriver dans le désordre ou partager un même horodatage. Ordonnez-les selon votre propre heure de réception, et dédoublonnez en utilisant `profile_event_id` ou les identifiants de transaction. ::: ## Configurer le webhook dans Adapty \{#configure-the-webhook-in-adapty\} 1. Ouvrez [Integrations → Webhook](https://app.adapty.io/integrations/customwebhook) dans l'Adapty Dashboard. 2. Activez l'intégration. 3. Dans **Production endpoint URL**, saisissez l'URL HTTPS de l'endpoint que vous avez déployé. 4. Dans **Authorization header value for production endpoint**, entrez le même secret que celui vérifié par votre endpoint. Adapty renvoie cette valeur dans l'en-tête `Authorization` à chaque requête. C'est facultatif mais fortement recommandé. 5. Pour tester d'abord en sandbox, renseignez également **Sandbox endpoint URL** et sa valeur **Authorization header value**. 6. Cliquez sur **Save**. Adapty envoie immédiatement la requête de vérification à votre endpoint, qui répond avec un `2xx` pour finaliser la configuration. Pour choisir les événements à envoyer, mapper les noms d'événements ou activer des champs optionnels (prix d'essai, événements historiques, attribution, attributs utilisateur, token Play Store), consultez [Configurer l'intégration webhook](https://adapty.io/docs/fr/set-up-webhook-integration.md). ## Créer le handler avec votre agent de codage IA \{#build-it-with-your-ai-coding-agent\} Donnez à votre agent de codage IA ce guide et la documentation de référence en Markdown (ajoutez `.md` à l'URL de n'importe quelle page), indiquez-lui votre stack, et laissez-le générer le handler : - [Types d'événements et champs webhook](https://adapty.io/docs/fr/webhook-event-types-and-fields.md) - [Configurer l'intégration webhook](https://adapty.io/docs/fr/set-up-webhook-integration.md) Exemple de prompt : ``` Read these Adapty webhook docs, then write a webhook handler for my Express app: verify the Authorization header against ADAPTY_WEBHOOK_SECRET, answer the verification request, acknowledge events with 200, and grant or revoke access based on event_type. ``` L'agent écrit le code du handler, mais il ne peut pas déployer votre endpoint ni configurer le tableau de bord — hébergez l'endpoint vous-même et renseignez l'URL et le secret dans **Integrations → Webhook**. ## Tester votre webhook \{#test-your-webhook\} Testez en sandbox avant la production : 1. Configurez l'endpoint sandbox et le secret comme décrit ci-dessus. 2. Dans votre app sandbox, effectuez un achat, démarrez un essai ou émettez un remboursement pour déclencher un événement. 3. Ouvrez la section **Last sent events** de l'intégration. Un événement livré affiche le statut **Success**. Si un événement affiche **Sending failed**, votre serveur a renvoyé un statut hors de la plage 200–399 — survolez le statut pour obtenir des détails. Pour le guide de test complet, consultez [Tester l'intégration webhook](https://adapty.io/docs/fr/test-webhook.md). ## Limites \{#limits\} - **Accusez réception en moins de 10 secondes** : Si Adapty ne reçoit pas de réponse à temps, la tentative est considérée comme échouée et relancée. - **Nouvelles tentatives** : Si votre statut est hors de la plage 200–404, Adapty relance avec un backoff exponentiel — jusqu'à 9 tentatives sur 24 heures. - **Délai d'annulation** : Les événements d'annulation peuvent mettre jusqu'à 2 heures à arriver. - **Une URL par environnement** : Pour livrer les événements à plusieurs services, pointez le webhook vers votre propre backend et redistribuez-les depuis là. --- # File: server-side-api-with-ai --- --- title: "Vérifier et accorder l'accès à un abonnement depuis votre backend" description: "Utilisez l'API côté serveur d'Adapty pour vérifier si un utilisateur a un abonnement actif et accorder l'accès manuellement, avec l'aide d'un agent IA." --- Depuis votre backend, utilisez l'API côté serveur d'Adapty pour vérifier si un utilisateur a un abonnement actif et accorder l'accès manuellement. Ce guide couvre les deux appels les plus courants — `getProfile` et `grantAccessLevel` — et montre comment demander à un agent IA d'écrire l'intégration pour votre stack. :::tip Vous utilisez un agent IA ? Cliquez sur **Copy for LLM** sous le titre et collez toute cette page dans votre agent — il y trouvera les appels, les champs et les points de vigilance dont il a besoin. ::: ## Avant de commencer \{#before-you-start\} - **Une clé API secrète** : retrouvez-la dans [App settings → General](https://app.adapty.io/settings/general), dans le champ **Secret key**. Les clés sont spécifiques à chaque app. Stockez-la dans une variable d'environnement (par exemple, `ADAPTY_SECRET_KEY`) et envoyez-la via `Authorization: Api-Key {key}`. - **L'URL de base** : toutes les requêtes vont vers `https://api.adapty.io`. - **Un moyen d'identifier l'utilisateur** : envoyez soit `adapty-customer-user-id` (votre propre identifiant utilisateur — fonctionne uniquement si vous identifiez les utilisateurs dans l'app) soit `adapty-profile-id` (l'identifiant de profil Adapty). Ils sont interchangeables ; utilisez l'un ou l'autre. ## Vérifier un abonnement \{#check-a-subscription\} Pour vérifier le statut, appelez `getProfile` avec `GET` et passez l'identifiant utilisateur dans un header — il n'y a pas de corps de requête. ```javascript title="check-access.js" const res = await fetch("https://api.adapty.io/api/v2/server-side-api/profile/", { headers: { "Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`, "adapty-customer-user-id": userId, }, }); const { data } = await res.json(); function hasActiveAccess(profile, accessLevelId = "premium") { const level = profile.access_levels?.find(a => a.access_level_id === accessLevelId); if (!level) return false; if (level.is_in_grace_period) return true; if (!level.expires_at) return true; // lifetime / non-expiring return new Date(level.expires_at) > new Date(); // not expired yet } if (hasActiveAccess(data)) { // unlock premium features } ``` Contrairement au profil SDK, la réponse côté serveur **n'a pas de champ `is_active`**. Déduisez le statut vous-même à partir de `access_levels[].expires_at` : `null` signifie un accès à vie, une date future signifie actif, et une date passée signifie expiré. Traitez `is_in_grace_period` comme toujours actif. Pour la liste complète des champs du profil et des niveaux d'accès, consultez [getProfile](https://adapty.io/docs/fr/api-adapty/operations/getProfile.md). ## Accorder l'accès manuellement \{#grant-access-manually\} Pour débloquer des fonctionnalités payantes sans achat — codes promo, accès investisseur ou bêta, cas de support — appelez `grantAccessLevel` avec `POST`. ```javascript title="grant-access.js" await fetch("https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/", { method: "POST", headers: { "Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`, "adapty-customer-user-id": userId, "Content-Type": "application/json", }, body: JSON.stringify({ access_level_id: "premium" }), // add "expires_at" for temporary access }); ``` Deux points à garder à l'esprit : - **Le niveau d'accès doit déjà exister** dans votre tableau de bord (**Access levels**) — `access_level_id` est son identifiant, pas un nouveau nom. - **Les accords manuels n'apparaissent pas dans les analytics**. Ils sont transmis uniquement à votre intégration webhook et à l'Event Feed, donc les graphiques de revenus et de conversion ne les reflèteront pas. Pour les détails de la requête et de la réponse, consultez [grantAccessLevel](https://adapty.io/docs/fr/api-adapty/operations/grantAccessLevel.md). ## Construire l'intégration avec votre agent IA \{#build-it-with-your-ai-coding-agent\} Donnez à votre agent IA ce guide et la spécification API en Markdown (ajoutez `.md` à n'importe quelle URL de page), indiquez-lui votre stack, et laissez-le écrire les appels : - [Spécification OpenAPI](https://adapty.io/docs/fr/api-specs/adapty-api.yaml) - [getProfile](https://adapty.io/docs/fr/api-adapty/operations/getProfile.md) - [grantAccessLevel](https://adapty.io/docs/fr/api-adapty/operations/grantAccessLevel.md) Exemple de prompt : ``` Using the Adapty server-side API spec, write backend functions to check whether a user has an active "premium" access level (GET /profile/, derive status from expires_at — there's no is_active field) and to grant it (grantAccessLevel). Authenticate with ADAPTY_SECRET_KEY and identify users by adapty-customer-user-id. ``` L'agent écrit le code, mais il ne peut pas exécuter votre backend ni configurer vos clés — vous fournissez la clé secrète et les identifiants utilisateurs. ## Limites \{#limits\} - **Limite de débit** : jusqu'à 40 000 requêtes par minute et par app. - **Clés spécifiques à chaque app** : chaque clé fonctionne pour une seule app ; utilisez la clé correspondante par app. - **Un identifiant requis** : chaque requête nécessite `adapty-customer-user-id` ou `adapty-profile-id`. --- # File: app-store-test --- --- title: "Tester les achats intégrés dans l'App Store" description: "Testez les achats dans l'environnement sandbox pour garantir des transactions fluides." --- Une fois tout configuré dans l'Adapty Dashboard et votre application mobile, il est temps de procéder aux tests d'achats intégrés. Il existe deux façons de tester les achats dans votre application iOS : - [**Tests sandbox**](test-purchases-in-sandbox) : Utilisez un compte sandbox et lancez votre application depuis Xcode ou téléchargez-la depuis TestFlight. Cette option vous permet de tester l'ensemble du flow d'achat et de voir les mises à jour du profil dans l'Adapty Dashboard. - [**Tests StoreKit dans Xcode**](local-sk-files) : Lancez votre application depuis Xcode sans avoir à créer ou réinitialiser un compte sandbox. Cette option convient particulièrement aux développeurs qui souhaitent tester différents scénarios dans l'environnement Xcode. Notez toutefois que tous les scénarios s'exécutent localement et qu'aucune modification n'apparaîtra dans l'Adapty Dashboard. --- # File: test-purchases-in-sandbox --- --- title: "Tests en sandbox" description: "Testez vos achats dans l'environnement sandbox pour garantir des transactions fluides." --- Une fois que vous avez tout configuré dans l'Adapty Dashboard et votre application mobile, il est temps de tester les achats intégrés. **Remarque :** aucun des outils de test ne facture les utilisateurs lorsqu'ils testent l'achat d'un produit. L'App Store n'envoie pas d'e-mails pour les achats ou les remboursements effectués dans les environnements de test. :::note **Les transactions sandbox sont exclues de tous les graphiques analytiques.** Elles apparaissent tout de même sur les pages de profil individuelles et dans le flux d'événements. ::: :::info Pour procéder aux tests d'achats intégrés, assurez-vous que : - Vous avez suivi les guides de [démarrage rapide](quickstart) sur l'intégration au store, l'ajout de produits et l'intégration du SDK Adapty. - Votre produit est marqué [**Ready to submit**](InvalidProductIdentifiers#step-2-check-products) dans App Store Connect. ::: ## Tests en sandbox \{#sandbox-testing\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/hq4PRU-vuik?si=m5F5Sj6iLEJ-2q6n" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> :::info Nous recommandons de tester les achats intégrés sur un vrai appareil. Bien que les achats sandbox puissent être effectués sur des simulateurs, les vrais appareils sont nécessaires pour tester tous les flows dans leur intégralité, y compris les dialogues de paiement et les invites biométriques. ::: Vous avez deux façons principales de tester les achats intégrés : - **Compiler avec Xcode et lancer sur un appareil de test** : pratique pour les développeurs et les ingénieurs QA. - **Utiliser un compte de test sandbox avec TestFlight** : adapté à tous les autres. Ces deux options sont couvertes dans le guide ci-dessous. ### Étape 1. Créer un compte de test Sandbox dans App Store Connect \{#step-1-create-sandbox-test-account-in-app-store-connect\} :::warning Créez un nouveau compte de test Sandbox pour vous assurer que votre historique d'achats est vierge. Si vous réutilisez un compte existant, les produits déjà achetés resteront disponibles et vous ne pourrez pas tester leur achat à nouveau. ::: Vous pouvez créer un nouveau compte de test Sandbox en quelques clics : 1. Accédez à [**Users and Access** > **Sandbox** > **Test Accounts**](https://appstoreconnect.apple.com/access/users/sandbox) dans App Store Connect et cliquez sur **+**. <img src="/assets/shared/img/add-sandbox-user.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Renseignez les informations de l'utilisateur de test. Veillez à définir le **Country or Region** que vous souhaitez tester, car cela influe sur la disponibilité des produits pour cette région et sur la devise d'achat. :::tip - Si vous utilisez Gmail ou iCloud, vous pouvez réutiliser votre adresse e-mail existante grâce au [sous-adressage avec le signe plus](https://www.wikihow.com/Use-Plus-Addressing-in-Gmail). - Vous pouvez utiliser une adresse e-mail aléatoire qui n'existe même pas, mais veillez à refuser l'authentification à deux facteurs (2FA) lorsque vous vous connectez sur un appareil de test par la suite. ::: <img src="/assets/shared/img/57c3a7c-apple_new_test_account.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Create**. ### Étape 2. Activer le mode développeur \{#step-2-enable-the-developer-mode\} :::note Ignorez cette étape si le mode développeur est **déjà activé** sur votre appareil de test ou si vous **n'avez pas de Mac**. ::: Vous aurez besoin d'un Mac avec Xcode installé et du câble de votre appareil de test : 1. Ouvrez Xcode sur votre Mac. Si vous souhaitez tester des achats intégrés avec TestFlight, il vous suffit d'avoir Xcode installé ; vous n'avez pas besoin d'y avoir une application. 2. Connectez votre appareil de test au Mac à l'aide du câble. 3. Sur votre appareil de test, allez dans **Settings > Privacy & Security > Developer Mode** et activez le **Developer Mode**. ### Étape 3. Télécharger l'application depuis TestFlight \{#step-3-download-the-app-from-testflight\} :::info Cette étape s'applique uniquement si vous testez avec TestFlight. Si vous compilez l'application dans Xcode, passez cette étape. ::: Pour savoir comment soumettre votre application à TestFlight, consultez la [documentation Apple](https://developer.apple.com/documentation/StoreKit/testing-in-app-purchases-with-sandbox#Prepare-for-sandbox-testing). Avant de télécharger l'application TestFlight, assurez-vous d'être connecté avec votre compte Apple de production sur votre appareil de test. Téléchargez ensuite l'application à tester depuis TestFlight. :::danger N'ouvrez pas l'application une fois téléchargée. Passez directement aux étapes suivantes. Si vous l'avez ouverte par accident, supprimez-la de votre appareil de test et téléchargez-la à nouveau. Sinon, votre historique d'achats risque de ne pas être vierge, et les tests d'achats intégrés généreront des erreurs. ::: ### Étape 4. Passer au compte de test Sandbox \{#step-4-switch-to-sandbox-test-account\} <Details> <summary>Vous n'utilisez pas de Mac ? Voici une astuce pour vous</summary> Si vous ne travaillez pas sur macOS, vous ne pouvez pas passer à un compte sandbox via Xcode. Vous pouvez toutefois le faire directement sur votre appareil de test : 1. Accédez à **Settings > Your Apple Account > Media & Purchases** sur votre appareil de test. 2. Sélectionnez **Sign Out** dans le menu contextuel. 3. Ouvrez l'application téléchargée depuis TestFlight et essayez d'acheter un produit. 4. Lorsqu'on vous demande de vous connecter, entrez les identifiants de votre compte sandbox pour basculer vers l'environnement sandbox. </Details> Pour passer à votre compte sandbox : 1. Rendez-vous dans **Settings > Your Apple Account > Media & Purchases** sur votre appareil de test. 2. Sélectionnez **Sign Out** dans le menu contextuel. 3. Accédez à **Settings > Developer**. Si l'option **Developer** n'est pas disponible, assurez-vous de l'avoir [activée à l'étape 2](#step-2-enable-the-developer-mode). <img src="/assets/shared/img/devmode.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler vers le bas jusqu'à la section **Sandbox Apple Account** et appuyez sur **Sign In**. <img src="/assets/shared/img/sandbox-acc.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Connectez-vous avec vos identifiants de compte Apple Sandbox. ### Étape 5. Effacer l'historique des achats \{#step-5-clear-purchase-history\} Si vous venez de créer un nouveau compte de test Sandbox et de basculer vers celui-ci, vous pouvez ignorer cette étape, car elle ne s'applique qu'aux tests répétés utilisant le même compte de test Sandbox. 1. Rendez-vous dans **Settings > Developer > Sandbox Apple Account** sur votre appareil de test. 2. Sélectionnez **Manage** dans le menu contextuel. 3. Accédez à **Account Settings** et appuyez sur **Clear Purchase History**. :::danger Cette étape est obligatoire chaque fois que vous recommencez les tests avec le même compte de test Sandbox. Dans ce cas, vous devrez également [vous déconnecter de votre compte de test Sandbox](#step-4-switch-to-sandbox-test-account), puis vous reconnecter pour vider le cache de l'historique des achats sur l'appareil de test. ::: ### Étape 6. Compiler dans Xcode et lancer l'application \{#step-6-build-in-xcode-and-run\} :::info Cette étape s'applique uniquement si vous testez avec un build Xcode. Si vous utilisez TestFlight, ignorez cette étape. ::: 1. Connectez votre appareil de test à votre Mac. 2. Ouvrez Xcode. 3. Cliquez sur **Run** dans la barre d'outils ou choisissez **Product > Run** pour compiler et lancer l'application sur l'appareil connecté. Si la compilation réussit, Xcode lancera l'application sur votre appareil et ouvrira une session de débogage dans la zone de débogage. Votre application est maintenant prête pour les tests sur l'appareil. ### Étape 7. Effectuer un achat test \{#step-7-make-test-purchase\} Ouvrez l'application et effectuez votre achat test via un paywall. Une fois terminé, consultez l'article sur la [validation des achats test](validate-test-purchases) pour vérifier vos résultats. ### Étape 8. Continuer à tester \{#step-8-keep-testing\} Votre environnement de test est maintenant prêt. Si vous souhaitez le tester à nouveau, [effacez l'historique des achats du compte sandbox](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings/). ## Problèmes lors des tests \{#testing-issues\} Voici les problèmes courants que vous pouvez rencontrer lors du test d'une application. ### Problèmes avec TestFlight \{#testflight-issues\} Vous ne pouvez pas effacer votre historique d'achats **si vous utilisez TestFlight sans compte de test Sandbox**, ce qui entraîne divers problèmes et des résultats de test erronés. Si vous avez oublié par inadvertance de [passer au compte de test Sandbox](#step-4-switch-to-sandbox-test-account) et que vous avez ouvert l'application ne serait-ce qu'une fois, TestFlight associe votre historique d'achats à votre compte Apple de production, ce qui provoque des problèmes inattendus. Pour remédier à cela, suivez ces étapes : 1. Supprimez l'application de l'appareil de test. 2. Suivez les étapes pour les [tests Sandbox](#sandbox-testing). :::note Il est important de ne pas seulement réinstaller l'application, mais aussi de passer au compte de test Sandbox, d'effacer l'historique des achats et de la lancer avec le compte de test Sandbox. ::: ### Problèmes liés aux niveaux d'accès partagés \{#shared-access-levels-issues\} Si vous répétez les tests avec le même compte de test Sandbox, vous pourriez rencontrer un comportement inattendu avec les [niveaux d'accès partagés](sharing-paid-access-between-user-accounts) pour l'utilisateur de test. Pour vérifier si l'utilisateur dispose d'un niveau d'accès hérité, accédez à [Profiles & Segments](https://app.adapty.io/profiles/users) depuis l'Adapty Dashboard et ouvrez le profil de l'utilisateur. <img src="/assets/shared/img/profile-access-level-origin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si l'utilisateur dispose d'un niveau d'accès hérité, suivez ces étapes pour obtenir des résultats de test précis : 1. Supprimez le profil parent. 2. Retirez l'application de l'appareil de test. 3. [Téléchargez l'application depuis TestFlight](#step-3-download-the-app-from-testflight). 4. [Passez au compte de test Sandbox](#step-4-switch-to-sandbox-test-account). 5. [Effacez l'historique des achats](#step-5-clear-purchase-history). 6. [Ouvrez l'application et effectuez votre achat test](#step-7-make-test-purchase). :::note Effacer l'historique des achats, c'est ce qui réinitialise l'achat côté store. Supprimer le profil parent ne fait que supprimer l'enregistrement côté Adapty. Pour comprendre pourquoi un compte réutilisé conserve l'accès et quelles actions de réinitialisation fonctionnent réellement, consultez [Réinitialiser l'abonnement d'un testeur](#resetting-a-testers-subscription). ::: ### Mise à jour de l'application dans TestFlight \{#updating-app-in-testflight\} Si l'application TestFlight a été mise à jour : 1. Supprimez l'application de l'appareil de test. 2. [Téléchargez l'application depuis TestFlight](#step-3-download-the-app-from-testflight). 3. [Passez au compte de test Sandbox](#step-4-switch-to-sandbox-test-account). 4. [Effacez l'historique des achats](#step-5-clear-purchase-history). 5. [Ouvrez l'application et effectuez votre achat test](#step-7-make-test-purchase). ## Réinitialiser l'abonnement d'un testeur \{#resetting-a-testers-subscription\} Dans l'environnement sandbox, un achat est lié au **compte sandbox Apple**, pas au profil Adapty. Les actions effectuées sur le profil — suppression ou modification de son niveau d'accès — ne suppriment pas l'achat du compte store. Au prochain réinstallation ou synchronisation, le SDK rattache la même transaction, et le testeur retrouve l'accès. Le tableau ci-dessous indique ce que chaque action de réinitialisation modifie et ce que le testeur voit ensuite. | Action | Profil Adapty | Compte sandbox Apple | Accès du testeur après | | :-------------------------------------------------------------------------------- | :------------------------------------------------------ | :--------------------- | :------------------------------------------------------------------------------------------------- | | Supprimer le profil depuis l'Adapty Dashboard | Supprimé | Intact | **Revient** — à la réinstallation, un nouveau profil rattache la même chaîne de transactions | | Supprimer le profil via l'[API Delete profile](api-adapty/operations/deleteProfile) | Supprimé | Intact | **Revient** — même comportement que la suppression depuis le Dashboard | | Ajouter une date d'expiration passée via **Add access level** | Écrasé à la prochaine synchronisation | Intact | **Revient** au prochain renouvellement — l'abonnement actif réapplique une date d'expiration future | | Appeler l'[API Revoke access level](api-adapty/operations/revokeAccessLevel) | Expire immédiatement, déclenche `access_level_updated` (`is_active=false`) | Intact | **Revient** au prochain renouvellement ou à la réinstallation — pas une réinitialisation sandbox fiable | | Annuler l'abonnement dans le compte sandbox | Aucun changement direct | Abonnement annulé | Les renouvellements s'arrêtent, l'accès prend fin à l'expiration de la période en cours, et le testeur peut racheter le produit | | Se connecter avec un nouveau compte sandbox Apple | Nouveau profil | Nouveau compte vide | **Propre** — recommandé pour les tests répétés | ### Réinitialiser un testeur dans un état vierge \{#reset-a-tester-to-a-clean-state\} Pour tester le flux d'achat plusieurs fois, utilisez un nouveau compte sandbox Apple pour chaque test plutôt que de réinitialiser le profil. Suivez l'[Étape 1](#step-1-create-sandbox-test-account-in-app-store-connect) pour créer le compte et l'[Étape 4](#step-4-switch-to-sandbox-test-account) pour y basculer sur l'appareil. Si vous réutilisez un compte sandbox existant, [effacez d'abord son historique d'achats](#step-5-clear-purchase-history) — supprimer le profil Adapty ne l'efface pas. ### Supprimer l'accès d'un testeur existant \{#remove-access-from-an-existing-tester\} Pour supprimer l'accès d'un testeur, n'antidatez pas la date d'expiration et n'appelez pas l'API Revoke access level. En sandbox, l'abonnement se renouvelle automatiquement toutes les quelques minutes. Chaque renouvellement restaure une date d'expiration future sur la même chaîne de transaction, donc l'accès est rétabli de lui-même. L'API Revoke access level déclenche bien un événement `access_level_updated` (`is_active=false`), mais le prochain renouvellement l'écrase. Pour vraiment révoquer l'accès, annulez l'abonnement côté store. Sur l'appareil de test, allez dans **Settings > Developer > Sandbox Apple Account**, sélectionnez **Manage**, puis annulez l'abonnement. Les renouvellements cessent et l'accès prend fin à l'expiration de la période en cours. ### Pourquoi supprimer le profil rétablit l'accès \{#why-deleting-the-profile-brings-access-back\} Quand un testeur réinstalle l'application, Adapty reçoit l'historique des achats du compte sandbox et associe la nouvelle installation à l'achat existant. L'achat est lié au compte du store, pas au profil que vous avez supprimé. - **Profils anonymes** : Une réinstallation sans `customer_user_id` hérite toujours du niveau d'accès du compte store, quelle que soit votre configuration de [partage d'accès payant](sharing-paid-access-between-user-accounts). - **Profils identifiés** : Le transfert de l'accès vers un nouveau `customer_user_id` dépend de votre configuration de partage d'accès payant. Pour comprendre comment Adapty relie ces profils en chaîne, consultez [Comment fonctionnent les profils](how-profiles-work#parent-and-inheritor-profiles). ## Tester les abonnements \{#test-subscriptions\} Lorsque vous testez votre application avec un compte de test Sandbox, vous pouvez définir le taux de renouvellement des abonnements pour chaque testeur dans le sandbox. Pour en savoir plus sur la modification des taux de renouvellement des abonnements, consultez la [documentation officielle d'Apple](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings). Par défaut, les abonnements se renouvellent jusqu'à 12 fois avant de s'arrêter, selon le calendrier suivant : | Durée de l'abonnement | 1 semaine | 1 mois | 2 mois | 3 mois | 6 mois | 1 an | | :------------------------------------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- | | Vitesse de renouvellement | 3 minutes | 5 minutes | 10 minutes | 15 minutes | 30 minutes | 1 heure | | Durée de la relance de facturation | 10 minutes | 10 minutes | 10 minutes | 10 minutes | 10 minutes | 10 minutes | | Durée du délai de grâce de facturation | 3 minutes | 5 minutes | 5 minutes | 5 minutes | 5 minutes | 5 minutes | :::note Gardez à l'esprit que les transactions de test peuvent prendre jusqu'à 10 minutes pour apparaître dans le [flux d'événements](validate-test-purchases). ::: Utilisez le sandbox pour vérifier que votre application et votre backend gèrent correctement les renouvellements, les nouvelles tentatives de facturation et les délais de grâce — et non pour prédire le calendrier de renouvellement en production. Le calendrier accéléré et plafonné décrit ci-dessus ne correspond pas à la production. Pour rejouer des transactions sur votre serveur à des fins de test backend, utilisez l'[API Set transaction](api-adapty/operations/setTransaction). ## Tester les offres \{#test-offers\} Pour que l'éligibilité fonctionne correctement, il est nécessaire de supprimer tous les reçus d'achat de l'utilisateur avant de tester les offres. La méthode la plus fiable consiste à utiliser un [compte de test Sandbox](#step-1-create-sandbox-test-account-in-app-store-connect) entièrement nouveau. Tester plusieurs fois avec le même compte de test Sandbox peut entraîner des comportements inattendus. :::danger Si vous testez plusieurs fois avec le même compte de test Sandbox, veillez à [effacer l'historique des achats](#step-5-clear-purchase-history) pour éviter tout problème d'éligibilité. ::: --- # File: local-sk-files --- --- title: "Test StoreKit dans Xcode" description: "Testez les achats dans l'environnement sandbox pour garantir des transactions fluides." --- Le test StoreKit dans Xcode vous permet de tester les achats intégrés localement sans configurer de compte sandbox. Pour ce type de test, vous devez : 1. [Créer un produit dans Adapty](quickstart-products) et lui attribuer un **App Store product ID**. 2. Dans Xcode, créer un [fichier de configuration StoreKit](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode) local et y ajouter un produit. L'ID produit doit être identique à l'**App Store product ID** dans Adapty. 3. Ajouter le fichier de configuration StoreKit à votre schéma de build et compiler l'application. Lancez-la sur l'émulateur ou sur votre appareil. ## Dois-je utiliser le test StoreKit dans Xcode ? \{#should-i-use-storekit-testing-in-xcode\} Cette méthode de test est la plus pratique si vous êtes un développeur d'application qui souhaite tester le build à la volée ou tester différents scénarios d'achat grâce aux fonctionnalités de Xcode. Toutefois, gardez à l'esprit que ce type de test est local : aucune modification n'apparaîtra sur l'Adapty Dashboard. Avant de lancer votre application en production, nous vous recommandons de tester le [fonctionnement avec les profils](ios-quickstart-identify) dans l'[environnement sandbox](test-purchases-in-sandbox). Vous **devriez** utiliser le test StoreKit si vous souhaitez : - Tester la logique d'achat - Reproduire différents scénarios d'achat avec les outils Xcode (ex. : paiement annulé ou remboursement) - Tester avec l'émulateur Vous **ne devriez pas** utiliser le test StoreKit si vous souhaitez : - Tester la logique liée aux profils - Vérifier si vos actions dans l'application apparaissent dans l'Adapty Dashboard - Partager votre application avec des équipes non-développeurs pour les tests ## Étape 1. Créer un fichier de configuration StoreKit \{#step-1-create-a-storekit-configuration-file\} Pour créer un fichier de configuration StoreKit dans Xcode : 1. Cliquez sur **File > New > File from template**. Sélectionnez ensuite **StoreKit Configuration File** et cliquez sur **Next**. 2. Donnez-lui un nom. Selon que vous avez déjà des produits dans App Store Connect : - Sélectionnez **Sync this file with an app in App Store Connect** : pour créer un fichier de configuration contenant tous vos produits App Store Connect, afin de les tester localement. - Ne sélectionnez pas **Sync this file with an app in App Store Connect** : pour créer un fichier de configuration vide dans lequel vous devrez ajouter des produits manuellement. Cliquez sur **Next**. 3. N'ajoutez pas votre application comme cible. Poursuivez simplement. Si vous travaillez avec des produits synchronisés depuis App Store Connect, passez à l'[Étape 2](#step-2-add-the-configuration-file-to-the-build-scheme). 4. Si vos produits ne sont pas synchronisés depuis App Store Connect, cliquez sur **+** en bas à gauche et sélectionnez un type de produit. 5. Saisissez un nom de groupe d'abonnement et cliquez sur **Next**. 6. Saisissez un nom de référence. Dans le champ **Product ID**, entrez l'**App Store product ID** de votre produit dans Adapty. 7. Configurez le prix, les offres et les autres paramètres du produit dans le fichier de configuration. Vous pouvez aussi y ajouter d'autres produits. ## Étape 2. Ajouter le fichier de configuration au schéma de build \{#step-2-add-the-configuration-file-to-the-build-scheme\} Pour compiler l'application avec ce fichier de configuration, vous devez l'ajouter à un schéma de build. La bonne pratique consiste à séparer les schémas de test et de production ; nous vous suggérons donc de créer un nouveau schéma dédié aux tests : 1. En haut, cliquez sur le nom de votre application et sélectionnez **New scheme**. 2. Saisissez un nom pour le schéma et cliquez sur **OK**. 3. Cliquez à nouveau sur le nom de l'application et sélectionnez **Edit scheme**. Dans **StoreKit configuration**, sélectionnez votre fichier de configuration local pour qu'il soit utilisé lors du build. ## Étape 3. Compiler & tester \{#step-3-build--test\} Vous pouvez maintenant compiler l'application et tester les achats intégrés sans vous connecter au backend de l'App Store. Vous pouvez acheter des produits et obtenir des niveaux d'accès localement. Ces modifications ne seront pas répercutées dans l'Adapty Dashboard, mais vous pourrez tout de même tester le déverrouillage des fonctionnalités payantes en local. [En savoir plus](https://developer.apple.com/documentation/xcode/testing-in-app-purchases-with-storekit-transaction-manager-in-code) sur les autres fonctionnalités disponibles avec le test StoreKit dans Xcode. --- # File: testing-on-android --- --- title: "Tester les achats intégrés dans Google Play Store" description: "Testez les achats d'abonnements sur Android avec Adapty." --- Tester les achats intégrés (IAP) dans votre application Android est une étape essentielle avant de la publier. Le test en sandbox est un moyen sûr et efficace de tester les IAP sans facturer vos utilisateurs. Dans ce guide, nous vous accompagnons pas à pas pour tester les IAP en sandbox sur le Google Play Store pour Android. :::note **Les transactions sandbox sont exclues de tous les graphiques analytiques.** Elles apparaissent tout de même sur les pages de profil individuelles et dans le flux d'événements. ::: ## Environnement de test \{#testing-environment\} Pour garantir des performances optimales de votre application Android, il est recommandé de la tester sur un vrai appareil plutôt que sur un émulateur. Bien que nous ayons réussi à tester sur des émulateurs, Google recommande l'utilisation d'un vrai appareil. Si vous décidez d'utiliser un émulateur, assurez-vous qu'il dispose de Google Play. Cela vous aidera à vérifier que votre application fonctionne correctement. ## 1. Configurer un compte de test pour tester l'application \{#1-set-up-test-account-for-app-testing\} Pour faciliter les tests lors des phases avancées du développement, vous devez configurer un utilisateur de test pour les achats intégrés. Cet utilisateur sera le premier compte avec lequel vous vous connecterez sur votre appareil de test Android. Notez que le compte principal d'un appareil Android ne peut être modifié qu'en effectuant une réinitialisation d'usine, ce qui efface toutes vos données. Il est donc important de configurer correctement votre compte de test afin d'éviter d'avoir à effectuer cette réinitialisation. :::important La façon de configurer un compte de test dépend de l'appareil que vous utilisez : - Si vous avez un appareil de test dédié, créez un **compte de test séparé (un nouveau compte Gmail)**. - Si vous n'avez pas d'appareil de test dédié, vous pouvez utiliser votre **compte personnel** et activer temporairement le **License testing** pour ce compte. - Si vous n'avez pas du tout d'appareil Android, vous pouvez **créer un compte de test séparé et l'utiliser avec un émulateur**. Cette approche n'est toutefois pas recommandée, car elle ne permet pas de détecter tous les problèmes potentiels liés aux vrais appareils. ::: ## 2. Activer le License testing \{#2-enable-license-testing\} Une fois votre compte de test configuré, vous devez paramétrer le test de licence pour votre application. Pour ce faire, suivez ces étapes : 1. Dans la barre latérale de la Google Play Console, accédez à **Settings** et sélectionnez **License testing** dans la section **Monetization**. <img src="/assets/shared/img/android-license-testing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez une liste de testeurs de licence existante ou créez-en une nouvelle. <img src="/assets/shared/img/android-testers.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Ajoutez le compte que vous utiliserez pour les tests à la liste et enregistrez les modifications. Si des membres de votre équipe doivent également tester l'application, vous pouvez ajouter leurs adresses e-mail à la liste afin que l'accès soit accordé à l'ensemble du groupe. <img src="/assets/shared/img/android-list.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 3. Créer une piste fermée et y ajouter le compte de test \{#3-create-closed-track-and-add-test-account-to-it\} Pour commencer les tests, vous devez publier une version signée de votre application sur une piste fermée : 1. Ouvrez votre application et sélectionnez **Test and release > Testing > Closed testing** dans le menu. Cliquez ensuite sur **Create track**. <img src="/assets/shared/img/android-closed-testing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Saisissez le nom de la piste de test fermée et cliquez sur **Create track**. 3. Ajoutez une liste de testeurs à la piste. 4. Dans la section **How testers join your test**, copiez le lien et envoyez-le à l'appareil connecté avec le compte de test. Ouvrez le lien sur votre appareil de test pour désigner l'utilisateur comme testeur. <img src="/assets/shared/img/android-link.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning Tenez compte des points suivants pour garantir le bon déroulement des tests : - L'ouverture de l'URL d'inscription marque votre compte Play pour les tests. Si vous ne réalisez pas cette étape, les produits ne se chargeront pas. - Les développeurs utilisent souvent un ID d'application différent pour leurs builds de test. Cela peut poser des problèmes, car Google Play Services utilise l'ID d'application pour retrouver vos achats intégrés. - Il arrive qu'un utilisateur de test soit autorisé à acheter des consommables, mais pas des abonnements, si l'appareil de test n'a pas de code PIN. Cela peut se manifester par un message cryptique « Something went wrong ». Assurez-vous que l'appareil de test dispose d'un code PIN et qu'il est connecté au Google Play Store. ::: ## 4. Charger un APK signé sur la piste fermée \{#4-upload-a-signed-apk-to-the-closed-track\} Générez un APK signé ou utilisez Android App Bundle pour charger un APK signé sur la piste fermée que vous venez de créer. Vous n'avez même pas besoin de déployer la version. Il suffit de charger l'APK. Vous trouverez plus d'informations à ce sujet dans [cet](https://support.google.com/googleplay/android-developer/answer/9859348?visit_id=638929100639477968-3849460621&rd=1) article d'assistance. :::important Si votre application est nouvelle, vous devrez peut-être la rendre disponible dans votre pays ou région. Pour ce faire, accédez à **Testing > Closed testing**, cliquez sur votre piste de test, puis allez dans **Countries/regions** pour ajouter les pays et régions souhaités. ::: ## 5. Tester les achats intégrés \{#5-test-in-app-purchases\} Après avoir chargé l'APK, attendez quelques minutes que la version soit traitée. Ensuite, ouvrez votre appareil de test et connectez-vous avec le compte e-mail que vous avez ajouté à la liste des testeurs. Vous pouvez alors tester les achats intégrés comme vous le feriez sur une application en production. <img src="/assets/shared/img/a8d2da9-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## En savoir plus \{#read-more\} Consultez les ressources suivantes pour en savoir plus sur les tests d'achats intégrés dans les applications Android : - [Périodes de renouvellement en sandbox](https://developer.android.com/google/play/billing/test#subs) - [Tester les achats uniques](https://developer.android.com/google/play/billing/test#one-time) --- # File: validate-test-purchases --- --- title: "Valider les achats test" description: "Validez les achats test dans Adapty pour garantir des transactions sans accroc." --- Avant de publier votre application mobile en production, il est essentiel de tester minutieusement les achats intégrés. Consultez nos articles [Tester les achats intégrés sur l'Apple App Store](test-purchases-in-sandbox) et [Tester les achats intégrés sur le Google Play Store](testing-on-android) pour des instructions détaillées. Une fois les tests lancés, vous devez vérifier que les achats test se déroulent correctement. À chaque achat test effectué sur votre appareil mobile, consultez la transaction correspondante dans le [**Event Feed**](https://app.adapty.io/event-feed) de l'Adapty Dashboard. Si l'achat n'apparaît pas dans le **Event Feed**, c'est qu'Adapty ne le suit pas. ## L'achat test est réussi \{#test-purchase-is-successful\} Si l'achat test est réussi, son événement de transaction s'affiche dans le **Event Feed** : <img src="/assets/shared/img/9ade2d5-event_feed_sandbox.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si les transactions fonctionnent comme prévu, passez à la [Liste de vérification avant publication](release-checklist), puis procédez à la publication de l'application. ## L'achat test a échoué \{#test-purchase-is-not-successful\} Si aucun événement de transaction n'apparaît dans les 10 minutes ou si vous rencontrez une erreur dans l'application mobile, consultez le [Dépannage](troubleshooting-test-purchases) ainsi que les articles sur la gestion des erreurs [pour iOS](ios-sdk-error-handling), [pour Android](android-sdk-error-handling), [pour React Native](react-native-handle-errors), [pour Flutter](error-handling-on-flutter-react-native-unity), [pour Unity](unity-handle-errors) et [Kotlin Multiplatform](kmp-handle-errors) pour trouver des solutions. <img src="/assets/shared/img/31a79b2-no_events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: troubleshooting-test-purchases --- --- title: "Résolution des problèmes d'achats test" description: "Résolvez les problèmes d'achats test dans Adapty et corrigez les erreurs courantes de transactions intégrées." --- Si vous rencontrez des problèmes de transactions, assurez-vous d'abord d'avoir suivi toutes les étapes de la [checklist de mise en production](release-checklist). Si c'est déjà le cas et que les problèmes persistent, suivez les recommandations ci-dessous pour les résoudre : ## Une erreur est retournée dans l'application mobile \{#an-error-is-returned-in-the-mobile-app\} Consultez la liste des erreurs pour votre plateforme : [pour iOS](ios-sdk-error-handling), [pour Android](android-sdk-error-handling), [pour React Native](react-native-troubleshoot-purchases), [Flutter](error-handling-on-flutter-react-native-unity) et [Unity](unity-troubleshoot-purchases), puis suivez nos recommandations pour résoudre le problème. ## La transaction est absente du fil d'événements bien qu'aucune erreur ne soit retournée dans l'application mobile \{#transaction-is-absent-from-the-event-feed-although-no-error-is-returned-in-the-mobile-app\} Pour résoudre ce problème, vérifiez les points suivants : 1. **Pour iOS** : Assurez-vous d'utiliser un appareil réel plutôt qu'un simulateur. 2. Vérifiez que le `Bundle ID`/`Package name` de votre application correspond à celui indiqué dans les [**App settings**](https://app.adapty.io/settings/general). 3. Vérifiez que la `PUBLIC_SDK_KEY` de votre application correspond à la **Public SDK key** dans l'Adapty Dashboard : [**App settings** -> onglet **General** -> section **API keys**](https://app.adapty.io/settings/general). 4. Assurez-vous d'utiliser un compte sandbox et non un [fichier de configuration StoreKit local](local-sk-files). Si vous avez utilisé un fichier de configuration StoreKit local pour des tests précédents, vérifiez qu'il n'est pas utilisé dans le build actuel. ## Aucun événement n'est présent dans mon profil de test \{#no-event-is-present-in-my-testing-profile\} C'est un comportement normal. Un nouveau profil utilisateur est automatiquement créé dans Adapty lorsque : - Un utilisateur lance votre application pour la première fois - Un utilisateur se déconnecte de votre application **Pourquoi cela se produit :** Toutes les transactions et tous les événements sont liés au profil qui a généré la première transaction. Cela permet de conserver l'intégralité de l'historique des transactions (essais, achats, renouvellements) rattaché au même profil. **Ce que vous verrez :** De nouveaux enregistrements de profil (appelés « profils non originaux ») peuvent apparaître sans événements, mais conserveront les niveaux d'accès. Vous pourrez voir des événements `access_level_updated`. C'est un comportement attendu. **Pour les tests :** Afin d'éviter la création de plusieurs profils, créez un nouveau compte de test (Sandbox Apple ID) à chaque fois que vous réinstallez l'application. Pour plus de détails, consultez [Création de profil](how-profiles-work#profile-creation). Voici un exemple de profil non original. Notez l'absence d'événements dans l'**User history** et la présence d'un niveau d'accès. <img src="/assets/shared/img/98d0dad-non-original_profile.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Les prix ne reflètent pas les prix réels définis dans App Store Connect \{#prices-do-not-reflect-the-actual-prices-set-in-app-store-connect\} Dans les environnements Sandbox et TestFlight (qui utilise l'environnement sandbox pour les achats intégrés), l'important est de vérifier que le flux d'achat fonctionne correctement, et non l'exactitude des prix. Il est à noter que l'API d'Apple peut parfois fournir des données incorrectes, notamment lorsque des régions différentes sont configurées pour les appareils ou les comptes. Les prix provenant directement du store sans que le backend Adapty n'intervienne d'aucune façon sur ceux-ci, vous pouvez ignorer toute imprécision de prix lors des tests d'achats via Adapty. Privilégiez donc le test du flux d'achat lui-même plutôt que l'exactitude des prix, afin de vous assurer qu'il fonctionne comme prévu. ## L'heure de la transaction dans le fil d'événements est incorrecte \{#the-transaction-time-in-the-event-feed-is-incorrect\} Le **Event Feed** utilise le fuseau horaire défini dans les **App Settings**. Pour aligner le fuseau horaire des événements sur votre heure locale, ajustez le **Reporting timezone** dans [**App settings** -> onglet **General**](https://app.adapty.io/settings/general). ## Les paywalls et les produits prennent beaucoup de temps à charger \{#paywalls-and-products-take-a-long-time-to-load\} Ce problème peut survenir si votre compte de test possède un historique de transactions long. Nous vous recommandons vivement de créer un nouveau compte de test à chaque fois, comme indiqué dans notre section [Créer un compte de test Sandbox (Sandbox Apple ID) dans App Store Connect](test-purchases-in-sandbox#step-1-create-sandbox-test-account-in-app-store-connect). Si vous ne pouvez pas créer de nouveau compte, vous pouvez effacer l'historique des transactions de votre compte actuel en suivant ces étapes sur votre appareil iOS : 1. Ouvrez **Settings** et appuyez sur **App Store**. 2. Appuyez sur votre **Sandbox Apple ID**. 3. Dans la fenêtre contextuelle, sélectionnez **Manage**. 4. Sur la page **Account Settings**, appuyez sur **Clear Purchase History**. Pour plus de détails, consultez la [documentation Apple Developer](https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox). --- # File: test-devices --- --- title: "Appareils de test" description: "Découvrez comment gérer les appareils de test dans Adapty pour des tests d'application efficaces." --- À des fins de test, vous pouvez désigner votre appareil comme appareil de test, ce qui désactive la mise en cache et garantit que vos modifications sont immédiatement prises en compte. :::note Les appareils de test sont pris en charge à partir de versions spécifiques du SDK : - iOS : 2.11.1 - Android : 2.11.3 - React Native : 2.11.1 La prise en charge de Flutter et Unity sera ajoutée ultérieurement. ::: ## Marquer votre appareil comme appareil de test \{#mark-your-device-as-test\} 1. Ouvrez les [**App settings**](https://app.adapty.io/settings/general) dans l'Adapty Dashboard. 2. Faites défiler jusqu'à la section **Test devices** dans l'onglet **General**. <img src="/assets/shared/img/14c581d-test_device_add.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur le bouton **Add test device**. <img src="/assets/shared/img/f86d5e2-test_users_add_device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la fenêtre **Add test device**, renseignez : | Champ | Description | |:-----------------------------------------| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Test device name** | Nom du ou des appareils de test, à titre de référence. | | **ID used to identify this test device** | Choisissez le type d'identifiant que vous souhaitez utiliser pour identifier le ou les appareils de test. Suivez nos recommandations dans la section [Quel identifiant utiliser](test-devices#which-identifier-you-should-use) ci-dessous pour choisir la meilleure option. | | **ID value** | Saisissez la valeur de l'identifiant. | 5. N'oubliez pas de cliquer sur le bouton **Add test device** pour enregistrer les modifications. ## Quel identifiant utiliser \{#which-identifier-you-should-use\} Plusieurs identifiants permettent d'identifier un appareil. Voici nos recommandations : - **Customer User ID** pour les appareils iOS et Android si vous <InlineTooltip tooltip="identifiez vos utilisateurs dans Adapty">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. C'est le meilleur choix, surtout si vous avez plusieurs appareils de test pour un même compte dans votre application. Si le Customer User ID est utilisé comme **ID used to identify this test device**, tous les appareils associés à ce compte seront marqués comme appareils de test. - **IDFA (iOS)** et **Advertising ID (Android)** : Ces identifiants publicitaires sont idéaux pour les appareils iOS et Android respectivement, si vous demandez déjà le consentement de vos utilisateurs pour y accéder. Même si vous disposez d'un Customer User ID, vous pouvez préférer les identifiants publicitaires si vous changez de compte dans votre application lors des tests. Par ailleurs, ces identifiants sont utiles lorsqu'un même compte possède à la fois des appareils de test et des appareils personnels, et que vous ne souhaitez pas que les appareils personnels soient marqués comme appareils de test. D'autres options existent, comme l'Adapty Profile ID, l'IDFV et l'Android ID, moins pratiques mais utilisables si vous ne pouvez pas recourir au Customer User ID, à l'IDFA ou à l'Advertising ID. Passons en revue toutes les options possibles en détail. ### Identifiants pour toutes les plateformes \{#identifiers-for-all-platforms\} | Identifiant | Utilisation | |----------|-----| | Customer User ID | <p>Un identifiant unique que vous définissez pour identifier vos utilisateurs dans votre système. Il peut s'agir de l'e-mail de l'utilisateur, de votre identifiant interne ou de toute autre chaîne. Pour utiliser cette option, vous devez <InlineTooltip tooltip="Identifier vos utilisateurs dans Adapty">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>.</p><p></p><p>C'est le meilleur choix pour identifier un appareil de test, surtout si vous utilisez plusieurs appareils pour le même compte. Tous les appareils associés à ce compte seront considérés comme des appareils de test.</p> | | Adapty profile ID | <p>Un identifiant unique pour le [profil utilisateur](profiles-crm) dans Adapty.</p><p></p><p>Utilisez-le si vous ne pouvez pas utiliser le Customer User ID, l'IDFA pour iOS ou l'Advertising ID pour Android. Notez que l'Adapty Profile ID peut changer si vous réinstallez l'application ou vous reconnectez.</p> | #### Comment obtenir le Customer User ID et l'Adapty profile ID \{#how-to-obtain-customer-user-id-and-adapty-profile-id\} Ces deux identifiants sont disponibles dans les détails du **Profile** sur l'Adapty Dashboard : 1. Retrouvez le profil de l'utilisateur dans l'onglet [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Pour identifier le bon profil, effectuez un type de transaction rare. Ainsi, lorsque la transaction apparaît dans l'[**Event Feed**](https://app.adapty.io/event-feed), vous pourrez l'identifier facilement. ::: 2. Copiez les valeurs des champs **Customer user ID** et **Adapty ID** dans les détails du profil : <img src="/assets/shared/img/345d308-test_users_CUID_adapty_ID.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Identifiants Apple \{#apple-identifiers\} | Identifiant | Utilisation | |----------|-----| | IDFA | <p>L'Identifier for Advertisers (IDFA) est un identifiant unique attribué par Apple à l'appareil d'un utilisateur.</p><p></p><p>C'est le choix idéal pour les appareils iOS car il ne change jamais de lui-même, bien que vous puissiez le réinitialiser manuellement.</p><p>**Remarque** : depuis le déploiement d'iOS 14.5, les annonceurs doivent demander le consentement de l'utilisateur pour accéder à l'IDFA. Assurez-vous de demander ce consentement dans votre application et de l'avoir accordé sur votre appareil de test.</p> | | IDFV | L'Identifier for Vendors (IDFV) est un identifiant alphanumérique unique attribué par Apple à toutes les applications d'un même éditeur/fournisseur sur un seul appareil. Il peut changer si vous réinstallez ou mettez à jour votre application. | #### Comment obtenir l'IDFA \{#how-to-obtain-the-idfa\} Apple ne fournit pas l'IDFA par défaut. Obtenez-le depuis l'attribution du profil dans l'Adapty Dashboard : 1. Retrouvez le profil de l'utilisateur dans l'onglet [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Pour identifier le bon profil, effectuez un type de transaction rare. Ainsi, lorsque la transaction apparaît dans l'[**Event Feed**](https://app.adapty.io/event-feed), vous pourrez l'identifier facilement. ::: 2. Ouvrez les détails du profil et copiez la valeur du champ **IDFA** dans la section **Attributes** : <img src="/assets/shared/img/ce4a63f-test_users_idfa.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Vous pouvez également [trouver une application sur l'App Store qui vous affichera votre IDFA](https://www.apple.com/us/search/idfa?src=globalnav). #### Comment obtenir l'Identifier for Vendors (IDFV) \{#how-to-obtain-the-identifier-for-vendors-idfv\} Pour obtenir l'IDFV, demandez à votre développeur de le récupérer à l'aide de la méthode suivante dans votre application et d'afficher l'identifiant reçu dans vos logs ou votre panneau de débogage. ```swift showLineNumbers title="Swift" UIDevice.current.identifierForVendor ``` ### Identifiants Google \{#google-identifiers\} | Identifiant | Utilisation | |----------|-----| | Advertising ID | <p>L'Advertising ID est un identifiant unique attribué par Google à l'appareil d'un utilisateur.</p><p>C'est le choix idéal pour les appareils Android car il ne change jamais de lui-même, bien que vous puissiez le réinitialiser manuellement.</p><p> **Remarque** : pour l'utiliser, désactivez l'option **Opt out of Ads Personalization** dans vos paramètres **Ads** si vous utilisez Android 12 ou une version supérieure.</p>| | Android ID | L'Android ID est un identifiant unique pour chaque combinaison de clé de signature d'application, d'utilisateur et d'appareil. Disponible sur Android 8.0 et versions ultérieures. | #### Comment obtenir l'Advertising ID \{#how-to-obtain-advertising-id\} Pour trouver l'identifiant publicitaire de votre appareil : 1. Ouvrez l'application **Settings** sur votre appareil Android. 2. Appuyez sur **Google**. 3. Sélectionnez **Ads** sous **Services**. Votre identifiant publicitaire s'affiche en bas de l'écran. #### Comment obtenir l'Android ID \{#how-to-obtain-android-id\} Pour obtenir l'Android ID, demandez à votre développeur de récupérer l'[ANDROID_ID](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID) à l'aide de la méthode suivante dans votre application et d'afficher l'identifiant reçu dans vos logs ou votre panneau de débogage. ```kotlin showLineNumbers title="Kotlin/Java" android.provider.Settings.Secure.getString(contentResolver, android.provider.Settings.Secure.ANDROID_ID); ``` --- # File: release-checklist --- --- title: "Release checklist" description: "Suivez la checklist de publication d'Adapty pour garantir une mise à jour fluide de votre application." --- Nous sommes ravis que vous ayez choisi d'utiliser Adapty ! Nous espérons que l'intégration s'est bien passée. Ce guide vous accompagne étape par étape pour vous assurer que votre application est prête à être publiée sur les stores et que le flux de monétisation fonctionne correctement. ## Prérequis avant de commencer \{#pre-flight-essentials\} Ce dont vous avez besoin avant de démarrer la validation : - Un vrai appareil avec un compte sandbox - Accès à l'Adapty Dashboard - Accès à App Store Connect / Google Play Console :::note Bien que les achats sandbox puissent fonctionner sur des simulateurs, les vrais appareils sont nécessaires pour tester tous les flux, notamment les fenêtres de paiement et les invites biométriques. ::: <Button id="test-purchases-in-sandbox"> Guide de test pour App Store </Button> <Button id="testing-on-android"> Guide de test pour Google Play </Button> ## Validations universelles \{#universal-validations\} - [ ] **Connexion au store** : Assurez-vous d'avoir connecté Adapty à l'App Store et/ou Google Play : - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **Livraison des événements d'abonnement** : Confirmez que les notifications serveur sont configurées : - [ ] [Notifications serveur App Store](enable-app-store-server-notifications) - [ ] [Notifications développeur en temps réel (RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **Identification du profil** : Validez la logique d'identification des utilisateurs et assurez-vous que les achats sont associés au bon profil : - [ ] [Vérifiez que la logique d'identification dans le code de votre application correspond à votre cas d'usage](ios-quickstart-identify) - [ ] [Assurez-vous de comprendre la logique parent/héritier pour le partage d'accès payant entre les profils utilisateurs](sharing-paid-access-between-user-accounts) - [ ] **Offres** : Si vous avez des offres promotionnelles App Store dans l'application, assurez-vous d'avoir [ajouté votre clé d'achat intégré](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) à la fois dans le champ principal et dans la section **App Store promotional offers**. - [ ] **Collecte de données** : Assurez-vous de respecter la confidentialité : - [ ] Si vous devez vous conformer à des réglementations sur la vie privée comme le RGPD ou le CCPA, ou si votre application est destinée aux enfants, contrôlez si vous [activez la collecte et le partage de l'IDFA et de l'IP](sdk-installation-ios#data-policies). - [ ] Si votre application utilise AppTrackingTransparency, assurez-vous d'[envoyer le statut d'autorisation à Adapty](ios-deal-with-att). - [ ] **Labels de confidentialité** : [En savoir plus](apple-app-privacy) sur les données collectées par Adapty et les indicateurs à définir pour la revue. ## Validations des achats \{#purchase-validations\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Avant le lancement, assurez-vous que les achats intégrés fonctionnent correctement dans votre application et que votre paywall est prêt pour la revue du store. La façon dont vous validez les achats intégrés dépend de la manière dont vous les implémentez : - Vous affichez un paywall créé avec le Paywall Builder d'Adapty - Vous avez implémenté votre propre paywall et utilisez la méthode `makePurchase` pour gérer les achats - Vous utilisez Adapty en mode observateur (avec le Paywall Builder d'Adapty ou votre propre paywall) <Tabs groupId="paywall" queryString> <TabItem value="builder" label="Adapty Paywall Builder" default> **Objectif** : Adapty affiche le paywall, les utilisateurs peuvent acheter des produits, l'accès se déverrouille et le flux de restauration fonctionne. - [ ] Votre application [affiche le paywall](ios-present-paywalls) depuis le même placement que celui que vous allez déployer. - [ ] Le paywall s'affiche à l'écran. Si le chargement prend trop de temps (par exemple, si vous ou vos utilisateurs avez une connexion instable), envisagez d'[ajuster votre politique de récupération](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). - [ ] Le paywall correspond à la variante attendue (audience/langue si applicable). Vous pouvez [modifier la priorité de l'audience](change-audience-priority) si nécessaire. - [ ] Les produits et les prix s'affichent sur le paywall. Notez que l'API d'Apple peut occasionnellement fournir des prix inexacts lors des tests (notamment avec différentes configurations de région), donc privilégiez le test du fonctionnement du flux d'achat plutôt que la précision des prix, car Adapty n'a pas d'influence sur les prix du store. - [ ] L'achat sandbox se termine avec succès. Le callback d'achat réussi est bien reçu. - [ ] L'accès se déverrouille et persiste. Confirmez que [l'accès payant est accordé en fonction du profil Adapty actuel](ios-check-subscription-status#connect-profile-with-paywall-logic). - [ ] Après l'achat, le profil Adapty a un niveau d'accès actif. - [ ] Les fonctionnalités payantes se déverrouillent quand le profil contient ce niveau d'accès (pas seulement au moment du callback d'achat). - [ ] La restauration des achats fonctionne. Quand vous réinstallez l'application ou l'installez sur un nouvel appareil, la restauration automatique des achats fonctionne conformément au paramètre [Partage d'accès payant](sharing-paid-access-between-user-accounts). Si vous n'avez pas d'authentification backend, les achats sont restaurés automatiquement quel que soit le paramètre. Dans les autres cas, assurez-vous que les utilisateurs peuvent restaurer leurs achats après avoir réinstallé l'application. - [ ] Exigences pour la revue du store : - [ ] Le bouton **Restore purchases** est présent sur le paywall. Vous pouvez l'ajouter dans le Paywall Builder, et il traitera automatiquement les restaurations d'achats lorsqu'il est tapé. - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis l'écran du paywall, et cliquer sur ces liens les ouvre dans un navigateur. </TabItem> <TabItem value="makepurchase" label="Custom paywall (makePurchase)" default> **Objectif** : Vous affichez l'interface ; Adapty gère les achats, les mises à jour de profil et les restaurations. - [ ] Les identifiants de produits ne sont pas codés en dur dans votre code. Vous ne codez en dur que les identifiants de [placement](placements). - [ ] Votre application [récupère les produits](fetch-paywalls-and-products) depuis le même placement que celui que vous allez déployer. - [ ] La liste des produits se charge correctement. Si le chargement prend trop de temps (par exemple, si vous ou vos utilisateurs avez une connexion instable), envisagez d'[ajuster votre politique de récupération](fetch-paywalls-and-products#fetch-paywall-information). - [ ] Les produits récupérés correspondent à la variante attendue (audience/langue si applicable). Vous pouvez [modifier la priorité de l'audience](change-audience-priority) si nécessaire. - [ ] Les produits et les prix s'affichent sur le paywall. Notez que l'API d'Apple peut occasionnellement fournir des prix inexacts lors des tests (notamment avec différentes configurations de région), donc privilégiez le test du fonctionnement du flux d'achat plutôt que la précision des prix, car Adapty n'a pas d'influence sur les prix du store. - [ ] L'achat sandbox avec [makePurchase](making-purchases) se termine avec succès : - [ ] Le résultat d'achat réussi est bien géré. - [ ] Les résultats en attente/échoués/annulés sont gérés correctement. - [ ] Si vous [utilisez un Remote Config](present-remote-config-paywalls), ses valeurs sont correctement transmises à votre paywall. - [ ] Quand un paywall est affiché, la méthode [`logShowFlow` (iOS SDK v4+) / `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) est appelée. - [ ] L'achat sandbox se termine avec succès. Le callback d'achat réussi est bien reçu. - [ ] L'accès se déverrouille et persiste. Confirmez que [l'accès payant est accordé en fonction du profil Adapty actuel](ios-check-subscription-status#connect-profile-with-paywall-logic). - [ ] Après l'achat, le profil Adapty a un niveau d'accès actif. - [ ] Les fonctionnalités payantes se déverrouillent quand le profil contient ce niveau d'accès (pas seulement au moment du callback d'achat). - [ ] La restauration des achats fonctionne. Quand vous réinstallez l'application ou l'installez sur un nouvel appareil, la restauration automatique des achats fonctionne conformément au paramètre [Partage d'accès payant](sharing-paid-access-between-user-accounts). Si vous n'avez pas d'authentification backend, les achats sont restaurés automatiquement quel que soit le paramètre. Dans les autres cas, assurez-vous que les utilisateurs peuvent restaurer leurs achats après avoir réinstallé l'application. - [ ] Exigences pour la revue du store : - [ ] Le bouton **Restore purchases** est accessible et [gère les restaurations](restore-purchase). - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis l'écran du paywall, et cliquer sur ces liens les ouvre dans un navigateur. </TabItem> <TabItem value="observer" label="Observer mode"> **Objectif** : Vous gérez les achats, les mises à jour de profil et les restaurations vous-même ; Adapty reçoit les rapports de transactions. - [ ] **Votre application effectue les achats via votre propre flux d'achat** (StoreKit / BillingClient / backend) : - [ ] L'achat sandbox réussit dans l'interface du store. - [ ] Les résultats en attente/échoués/annulés sont gérés correctement dans votre application. - [ ] **Les transactions sont signalées à Adapty**. - [ ] Le mode observateur est [activé dans le code de votre application](implement-observer-mode). - [ ] L'achat apparaît dans le fil d'événements Adapty. - [ ] Les renouvellements, annulations et remboursements sont reflétés au fil du temps (le cas échéant). - [ ] **Les vues de paywall sont suivies**. La méthode [`logShowFlow` (iOS SDK v4+) / `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) est appelée lorsqu'un paywall est affiché. - [ ] **La restauration des achats fonctionne pour votre implémentation**. La réinstallation de l'application ou le changement d'appareil restaure correctement l'accès. - [ ] **Exigences pour la revue du store** : - [ ] L'action **Restore purchases** est accessible et déclenche votre flux de restauration. - [ ] Les Conditions d'utilisation et la Politique de confidentialité sont accessibles depuis le paywall ou l'écran d'achat et s'ouvrent dans un navigateur. </TabItem> </Tabs> Si vous avez des questions sur l'intégration du SDK Adapty, utilisez le chatbot IA en bas à droite ou contactez-nous à [support@adapty.io](mailto:support@adapty.io). --- # File: submit-app-to-app-store --- --- title: "Soumettre votre app iOS à l'App Store" description: "Importez votre build dans App Store Connect et soumettez votre app iOS d'abonnement pour examen par Apple." --- Une fois votre intégration Adapty testée et fonctionnelle, vous êtes prêt à importer votre build dans App Store Connect et à soumettre votre app pour examen par Apple. :::tip Avant de soumettre, assurez-vous d'avoir complété la [checklist de mise en production](release-checklist) pour vérifier votre intégration Adapty, les flux d'achat et les exigences de révision du store. ::: ## Importer votre build dans App Store Connect \{#upload-your-build-to-app-store-connect\} ### Étape 1. Archiver votre app dans Xcode et l'importer dans App Store Connect \{#step-1-archive-your-app-in-xcode-and-upload-it-to-app-store-connect\} 1. Dans Xcode, définissez la destination du build sur **Any iOS Device (arm64)**. <img src="/assets/shared/img/build-target.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 2. Sélectionnez **Product** > **Archive** dans la barre de menu supérieure. <img src="/assets/shared/img/xcode-archive.webp" style={{ border: '1px solid #727272', width: '500px', display: 'block', margin: '0 auto' }} /> 3. Attendez la fin du processus d'archivage. La fenêtre **Organizer** s'ouvre automatiquement. Sélectionnez votre archive et cliquez sur **Distribute App**. <img src="/assets/shared/img/distribute-app.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 4. Choisissez **App Store Connect** comme méthode de distribution. Suivez les instructions pour finaliser l'importation. :::note L'importation peut échouer si des ressources requises sont manquantes, comme une icône d'app ou un écran de lancement. Consultez le journal d'erreurs Xcode pour plus de détails. ::: <img src="/assets/shared/img/distribution-method.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> ### Étape 2. Vérifier le build dans App Store Connect \{#step-2-check-the-build-in-app-store-connect\} 1. Rendez-vous sur [App Store Connect](https://appstoreconnect.apple.com) et ouvrez votre app. 2. Faites défiler jusqu'à la section **Build**. Vérifiez que le build que vous venez d'importer y apparaît. :::note Il peut s'écouler quelques minutes avant que le build apparaisse dans App Store Connect après l'importation. ::: <img src="/assets/shared/img/app-store-build.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> ## Soumettre votre app et vos produits pour examen \{#submit-your-app-and-products-for-review\} Une fois le build visible dans la section **Build**, associez vos abonnements intégrés et soumettez l'app pour examen par Apple. ### Étape 1. Associer les produits à la soumission \{#step-1-attach-products-to-the-submission\} Chaque abonnement doit avoir le statut **Ready to Submit** dans App Store Connect avant de pouvoir l'associer. Si un abonnement est encore à l'état brouillon ou qu'il manque des métadonnées, il n'apparaîtra pas dans la liste. 1. Sur la même page, faites défiler jusqu'à la section **In-App Purchases and Subscriptions**. 2. Cliquez sur **Select in-app purchases or subscriptions**. <img src="/assets/shared/img/app-store-select-products.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 3. Sélectionnez tous les produits à inclure dans cette soumission et cliquez sur **Done**. ### Étape 2. Soumettre pour examen \{#step-2-submit-for-review\} 1. Remplissez tous les champs obligatoires de la page (description, captures d'écran, mots-clés, etc.). 2. Dans la section **App Store Version Release**, indiquez si vous souhaitez publier votre app automatiquement, manuellement ou selon un calendrier après approbation. 3. Cliquez sur **Add for Review**, puis sur **Submit to App Review**. Apple examine les apps en 1 à 2 jours, mais les délais peuvent varier. ## Vérifier votre app en production \{#verify-your-app-in-production\} Après approbation de votre app par Apple : 1. Effectuez un achat réel (ou attendez que votre premier utilisateur achète). 2. Ouvrez le [**Event Feed**](https://app.adapty.io/event-feed) dans l'Adapty Dashboard et vérifiez que les événements de transactions en production apparaissent. 3. Vérifiez que les événements d'abonnement (renouvellements, annulations) s'écoulent correctement — cela dépend de la configuration des [notifications serveur de l'App Store](enable-app-store-server-notifications). Si les événements en production n'apparaissent pas, vérifiez votre [configuration de connexion à l'App Store](app-store-connection-configuration). ## Prochaines étapes \{#next-steps\} Votre app est en ligne. Commencez à développer vos revenus d'abonnement : - **[Tests A/B](ab-tests)** : Expérimentez différents paywalls pour trouver ce qui convertit le mieux. - **[Analytics](charts)** : Suivez les métriques d'abonnement comme le MRR, le taux de désabonnement et la conversion. - **Intégrations** : Envoyez les événements d'abonnement vers des plateformes d'[analytics](analytics-integration) et d'[attribution](attribution-integration). --- # File: general --- --- title: "App settings" description: "Explorez les paramètres généraux et les configurations dans Adapty pour une utilisation optimale." --- Vous pouvez accéder à l'onglet General de la page App Settings pour gérer le comportement, l'apparence et le partage des revenus de votre application. Vous pouvez y personnaliser le nom et l'icône de votre application, gérer vos clés SDK et API Adapty, définir votre statut dans le programme Small Business et choisir le fuseau horaire pour les analyses et les graphiques de votre application. ## 1. Détails de l'application \{#1-app-details\} <img src="/assets/shared/img/8fa2929-CleanShot_2023-04-21_at_15.16.222x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Choisissez un nom et une icône uniques qui représentent votre application dans l'interface Adapty. Notez que le nom et l'icône de l'application n'auront aucun effet sur le nom et l'icône de l'application dans l'App Store ou Google Play. Veillez également à sélectionner une catégorie d'application appropriée qui reflète fidèlement le but et le contenu de votre application. Cela aidera les utilisateurs à découvrir votre application et à s'assurer qu'elle apparaît dans les bonnes catégories du store. ## 2\. Membre du programme Small Business et frais de service réduits \{#2-member-of-small-business-program-and-reduced-service-fee\} <img src="/assets/shared/img/825e2be-CleanShot_2023-04-19_at_13.43.292x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si votre organisation est inscrite au [programme Small Business](app-store-small-business-program) d'Apple ou au [programme de frais de service réduits](google-reduced-service-fee) de Google, vos applications bénéficient d'une commission de store réduite. Informez Adapty si votre application est inscrite à un programme de commission réduite. Pour garantir des calculs corrects, précisez le statut de ces programmes dans la section "Reduced Store Fee". Le paramètre de frais réduits ne s'applique qu'aux transactions futures. Modifiez votre statut **avant** qu'il entre en vigueur, et Adapty ajustera le taux de commission. :::warning * Si vous prolongez votre participation à un programme de frais réduits, **ajoutez une période d'éligibilité supplémentaire**. * Si vous perdez votre adhésion au programme, **modifiez la date d'expiration** de votre période d'éligibilité actuelle. ::: Les articles suivants approfondissent ce sujet : * [App Store Small Business Program](app-store-small-business-program) * [Google Reduced Service Fee](google-reduced-service-fee) ## 3\. Fuseau horaire de reporting \{#3-reporting-timezone\} <img src="/assets/shared/img/47227f9-CleanShot_2023-04-19_at_13.45.302x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Choisissez le fuseau horaire correspondant à l'emplacement de votre organisation, ou là où les analyses et graphiques de votre application sont les plus pertinents. Nous recommandons d'utiliser le même fuseau horaire que votre compte App Store Connect ou Google Play Console pour assurer la cohérence. Notez que ce paramètre de fuseau horaire n'affecte pas les intégrations tierces dans le système Adapty, qui utilisent le fuseau horaire UTC. Vous pouvez accéder aux paramètres de fuseau horaire dans la section Reported timezone de l'onglet General de la page App Settings. Vous pouvez également choisir d'appliquer le même fuseau horaire à toutes les applications de votre compte Adapty en cochant la case correspondante. ## 4\. Définition des installations pour les analyses \{#4-installs-definition-for-analytics\} Choisissez ce qui est défini comme un nouvel événement d'installation dans les analyses : | Base | Description | |------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | New device_ids | <p>(Recommandé) Chaque installation de l'application depuis le store sur un appareil est comptabilisée comme une nouvelle installation. Cela inclut les premières installations et les réinstallations.</p><p>Les installations sont comptées par identifiant d'appareil et ne sont pas affectées par l'authentification de l'utilisateur. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application ne génère pas d'événements d'installation supplémentaires.</p><p>Par exemple, si la même application est installée sur 5 appareils différents, vous verrez 5 installations dans les analyses.</p> | | New customer_user_ids | <p>Cette option est destinée aux applications qui <InlineTooltip tooltip="identifient les utilisateurs dans Adapty">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Unity](unity-identifying-users), [Kotlin Multiplatform](kmp-quickstart-identify), [Capacitor](capacitor-quickstart-identify)</InlineTooltip>. </p><p>Pour les utilisateurs connectés, seule la première installation associée à un identifiant utilisateur client est comptabilisée comme une installation. Les installations sur des appareils supplémentaires ne sont pas comptées comme de nouvelles installations. </p><p>Les utilisateurs anonymes (utilisateurs qui ne se sont pas connectés) ne sont pas comptabilisés dans les analyses. </p><p>La réinstallation de l'application ou une nouvelle connexion ne crée pas d'installations supplémentaires.</p> <p>Les stores d'applications et les plateformes d'attribution (comme App Store Connect, Google Play Console et AppsFlyer) utilisent une approche basée sur les appareils pour compter les installations. Si vous comptez les installations par identifiants utilisateur client dans Adapty, les chiffres d'installation peuvent différer de ceux de ces services externes.</p><p>⚠️ Si vous n'identifiez pas les utilisateurs dans Adapty, aucune installation ne sera comptée avec cette option activée.</p> | | New profiles in Adapty | (Héritage) Chaque installation, réinstallation et profil anonyme créé lors de déconnexions est comptabilisé comme une nouvelle installation. | Gardez à l'esprit que cette option n'affecte que la page [**Analytics**](https://app.adapty.io/analytics) et n'a pas d'impact sur la page [**Overview**](https://app.adapty.io/overview), où vous pouvez configurer la vue séparément. ## 5. Logique d'augmentation de prix sur l'App Store \{#5-app-store-price-increase-logic\} Pour maintenir des données précises et éviter les écarts entre les analyses Adapty et les résultats d'App Store Connect, il est important de sélectionner l'option appropriée lors de l'ajustement des configurations liées aux augmentations de prix dans App Store Connect. Vous pouvez donc choisir la logique qui sera appliquée aux augmentations de prix d'abonnement dans Adapty : <img src="/assets/shared/img/b766c8b-CleanShot_2023-07-18_at_19.28.18_22x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **Le prix d'abonnement pour les utilisateurs existants est conservé :** En sélectionnant cette option, le prix actuel sera maintenu pour vos abonnés existants, même si vous modifiez le prix dans App Store Connect. Cela signifie que les abonnés existants continueront à être facturés au prix d'abonnement d'origine. - **Lorsque le prix d'abonnement est modifié dans App Store Connect, il change également pour les abonnés existants :** Si vous choisissez cette option, toute modification de prix effectuée dans App Store Connect sera également appliquée à vos abonnés existants. Cela signifie que les abonnés existants seront facturés au nouveau prix reflétant la tarification mise à jour dans App Store Connect. :::warning Il est important de prendre en compte que l'option sélectionnée n'affecte pas seulement les analyses dans Adapty, mais impacte également les intégrations et le comportement global de gestion des transactions. ::: Assurez-vous de sélectionner l'option qui correspond à votre approche souhaitée pour la gestion des prix d'abonnement pour les abonnés existants. Cela contribuera à maintenir des données précises et une synchronisation entre les analyses Adapty et les résultats obtenus depuis App Store Connect. ## 6. Partage de l'accès payant entre les comptes utilisateurs \{#6-sharing-paid-access-between-user-accounts\} :::link Article principal : [Partage de l'accès payant entre les comptes utilisateurs](sharing-paid-access-between-user-accounts) ::: Le paramètre **Sharing paid access between user accounts** détermine ce que fait Adapty lorsque plusieurs [profils utilisateurs](identifying-users) tentent d'accéder au même achat. Vous pouvez spécifier un paramètre de partage d'accès distinct pour l'[environnement sandbox](test-purchases-in-sandbox). **Activé (par défaut)** Les utilisateurs identifiés (ceux qui ont un [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) peuvent partager le même [niveau d'accès](access-level) fourni par Adapty si leur appareil est connecté au même identifiant Apple/Google. C'est utile quand un utilisateur réinstalle l'application et se connecte avec un autre e-mail — il conserve tout de même l'accès à son achat précédent. Avec cette option, plusieurs utilisateurs identifiés peuvent partager le même niveau d'accès. Même si le niveau d'accès est partagé, toutes les transactions passées et futures sont enregistrées comme événements dans le Customer User ID d'origine afin de maintenir des analyses cohérentes et conserver un historique de transactions complet — y compris les périodes d'essai, les achats d'abonnement, les renouvellements, etc., liés au même profil. **Transférer l'accès au nouvel utilisateur** Les utilisateurs identifiés peuvent continuer à accéder au [niveau d'accès](access-level) fourni par Adapty, même s'ils se connectent avec un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) différent ou réinstallent l'application, tant que l'appareil est connecté au même identifiant Apple/Google. Contrairement à l'option précédente, Adapty transfère l'achat entre les utilisateurs identifiés. Cela garantit que le contenu acheté est disponible, mais un seul utilisateur peut y avoir accès à la fois. Par exemple, si UserA achète un abonnement et que UserB se connecte sur le même appareil et restaure les transactions, UserB obtient l'accès à l'abonnement, et celui-ci est révoqué pour UserA. Si l'un des utilisateurs (le nouveau ou l'ancien) n'est pas identifié, le niveau d'accès sera tout de même partagé entre ces profils dans Adapty. Bien que le niveau d'accès soit transféré, toutes les transactions passées et futures sont enregistrées comme événements dans le Customer User ID d'origine afin de maintenir des analyses cohérentes et conserver un historique de transactions complet — y compris les périodes d'essai, les achats d'abonnement, les renouvellements, etc., liés au même profil. Après être passé à **Transférer l'accès au nouvel utilisateur**, les niveaux d'accès ne seront pas transférés entre les profils immédiatement. Le processus de transfert pour chaque niveau d'accès spécifique est déclenché uniquement lorsqu'Adapty reçoit un événement du store, comme un renouvellement d'abonnement, une restauration ou lors de la validation d'une transaction. **Désactivé** Le premier profil d'utilisateur identifié à obtenir un niveau d'accès le conservera indéfiniment. C'est la meilleure option si votre logique métier exige que les achats soient liés à un seul Customer User ID. Notez que les niveaux d'accès sont tout de même partagés entre les utilisateurs anonymes. Vous pouvez « délier » un achat en [supprimant le profil de l'utilisateur propriétaire](https://adapty.io/docs/fr/api-adapty/operations/deleteProfile). Après la suppression, le niveau d'accès devient disponible pour le premier profil utilisateur qui le réclame, qu'il soit anonyme ou identifié. La désactivation du partage ne concerne que les nouveaux utilisateurs. Les abonnements déjà partagés entre utilisateurs continueront de l'être même après la désactivation de cette option. :::warning Apple et Google exigent que les achats intégrés soient partagés ou transférés entre utilisateurs car ils s'appuient sur l'identifiant Apple/Google pour y associer l'achat. Sans partage, la restauration des achats risque de ne pas fonctionner lors des réinstallations ultérieures. La désactivation du partage peut empêcher les utilisateurs de retrouver l'accès après connexion. Nous recommandons de désactiver le partage uniquement si vos utilisateurs **sont tenus de se connecter** avant d'effectuer un achat. Dans le cas contraire, un utilisateur identifié pourrait acheter un abonnement, se connecter à un autre compte et perdre définitivement l'accès. ::: ### Quel paramètre choisir ? \{#which-setting-should-i-choose\} | Mon application... | Option à choisir | | ------------------------------------------------------------ | ------------------------------------------------------------ | | N'a pas de système de connexion et utilise uniquement les identifiants de profil anonymes d'Adapty. | Utilisez l'option par défaut, car les niveaux d'accès sont toujours partagés entre les identifiants de profil anonymes pour les trois options. | | Dispose d'un système de connexion optionnel et permet aux clients d'effectuer des achats avant de créer un compte. | Choisissez **Transférer l'accès au nouvel utilisateur** pour garantir que les clients qui achètent sans compte pourront toujours restaurer leurs transactions ultérieurement. | | Exige que les clients créent un compte avant d'acheter, mais permet de lier les achats à plusieurs Customer User ID. | Choisissez **Transférer l'accès au nouvel utilisateur** pour garantir qu'un seul Customer User ID a accès à la fois, tout en permettant aux utilisateurs de se connecter avec un autre Customer User ID sans perdre leur accès payant. | | Exige que les clients créent un compte avant d'acheter, avec des règles strictes liant les achats à un seul Customer User ID. | Choisissez **Désactivé** pour garantir que les transactions ne sont jamais transférées entre comptes. | ## 7. Clés SDK et API \{#7-sdk-and-api-keys\} Utilisez une clé SDK publique pour intégrer les SDK Adapty dans votre application, et une clé secrète pour accéder à l'API serveur d'Adapty. Vous pouvez générer de nouvelles clés ou révoquer les clés existantes selon vos besoins. Pour créer des tokens pour le CLI développeur, accédez à **Settings → Developer API**. Voir [Authentication](developer-cli-authentication). ## 8. Appareils de test \{#8-test-devices\} Spécifiez les appareils à utiliser pour les tests afin de s'assurer qu'ils reçoivent des mises à jour instantanées pour les modifications de paywall ou de placement, en contournant les délais de mise en cache. Pour plus d'informations, consultez [Testing devices](test-devices). ## 9. Adhérence de variation inter-placement \{#9-cross-placement-variation-stickiness\} Définissez combien de temps après la fin d'un test un utilisateur continue à voir les variantes du test. Cela affecte la précision des analyses et l'expérience utilisateur — car présenter à un utilisateur une offre différente de celle qu'il a déjà vue peut influencer sa décision d'achat. La période d'adhérence maximale et par défaut est de 90 jours. :::warning Tenez compte des points suivants : - La modification de ce paramètre affectera tous les utilisateurs qui ont précédemment reçu une variante. Ils seront immédiatement éligibles à un nouveau paywall lorsqu'ils verront un placement, ce qui peut fausser les résultats de vos tests A/B en cours. - Si la période d'adhérence est expirée pour un utilisateur, il peut recevoir un nouveau paywall ou test A/B. Cependant, même dans ce cas, il ne pourra jamais faire partie d'un autre test inter-placement. ::: ## 10. Supprimer l'application \{#10-delete-the-app\} Si vous n'avez plus besoin d'une application, vous pouvez la supprimer d'Adapty. :::warning Veuillez noter que cette action est irréversible et que vous ne pourrez pas restaurer l'application ni ses données. ::: --- # File: ios-settings --- --- title: "Identifiants Apple App Store" description: "Configurez les paramètres iOS dans Adapty pour une gestion fluide des abonnements." --- Pour configurer les identifiants App Store et assurer le bon fonctionnement du SDK iOS Adapty, rendez-vous dans l'onglet [iOS SDK](https://app.adapty.io/settings/ios-sdk) de la page App Settings dans l'Adapty Dashboard. Configurez ensuite les paramètres suivants : <img src="/assets/shared/img/3d4087e-CleanShot_2023-06-26_at_13.27.042x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> | Champ | Description | |----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Bundle ID** | L'[identifiant bundle](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id) de votre application. | | **In-app purchase API (StoreKit 2)** | [Clés](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) permettant l'authentification sécurisée et la validation des requêtes d'historique des transactions d'achats intégrés. | | **App Store Server Notifications** | URL utilisée pour activer les [notifications serveur à serveur](enable-app-store-server-notifications) depuis l'App Store, afin de surveiller et de répondre aux changements de statut des abonnements des utilisateurs. | | **App Store Promotional Offers** | Clés d'abonnement pour créer des [offres promotionnelles](generate-in-app-purchase-key) dans Adapty pour des produits spécifiques. | | **Apple app ID** | L'identifiant de votre application sur l'App Store. Pour le trouver, ouvrez la page de votre application dans App Store Connect, accédez à la page **App Information** depuis le menu de gauche et copiez l'**Apple ID**. | | **App Store Connect shared secret (LEGACY)** | <p>**Clé legacy pour le SDK Adapty antérieur à la v2.9.0**</p><p></p><p>[Une clé](app-store-connection-configuration#step-5-enter-app-store-shared-secret) pour la validation des reçus et la prévention des fraudes dans votre application.</p> | --- # File: android-settings --- --- title: "Identifiants Google Play Store" description: "Configurez les paramètres Android dans Adapty pour une gestion fluide des abonnements." --- Pour que le SDK Android Adapty fonctionne, vous devez configurer plusieurs paramètres. <img src="/assets/shared/img/f6d76ec-app-settings_android.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> | Champ | Description | | :------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Package name** | Le Package name est l'identifiant unique de votre application dans le Google Play Store. Il est requis pour le fonctionnement de base d'Adapty, notamment le traitement des abonnements. | | **Service account key file** | [Clés](create-service-account) permettant une authentification sécurisée et la validation des achats. | | **Google Play RTDN topic name** | URL utilisée pour activer les [notifications serveur à serveur](enable-real-time-developer-notifications-rtdn) depuis le Play Store afin de surveiller et de réagir aux changements de statut des abonnements des utilisateurs. | --- # File: google-play-store-connection-configuration --- --- title: "Configurer l'intégration Google Play Store" description: "Configurez la connexion Google Play Store dans Adapty pour une gestion fluide des achats intégrés." --- Cette section décrit le processus d'intégration de votre application mobile distribuée via Google Play avec Adapty. Vous devrez saisir les données de configuration de votre application depuis le Play Store dans l'Adapty Dashboard. Cette étape est indispensable pour valider les achats et recevoir les mises à jour d'abonnement depuis le Play Store dans Adapty. Vous pouvez effectuer cette démarche lors de l'onboarding initial ou apporter des modifications ultérieurement dans les **App Settings** de l'Adapty Dashboard. :::danger La modification de la configuration n'est acceptable qu'avant la publication de votre application mobile intégrant les paywalls Adapty. Toute modification après la publication cassera l'intégration et les paywalls cesseront de s'afficher dans votre application. ::: ## Étape 1. Renseigner le nom de package \{#step-1-provide-package-name\} Le nom de package est l'identifiant unique de votre application dans le Google Play Store. Il est nécessaire au fonctionnement de base d'Adapty, notamment pour le traitement des abonnements. 1. Ouvrez la [Google Play Developer Console](https://play.google.com/console/u/0/developers). 2. Sélectionnez l'application dont vous avez besoin de l'identifiant. La fenêtre **Dashboard** s'ouvre. <img src="/assets/shared/img/7889edb-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Trouvez l'identifiant produit sous le nom de l'application et copiez-le. 4. Ouvrez les [**App settings**](https://app.adapty.io/settings/android-sdk) depuis le menu supérieur d'Adapty. <img src="/assets/shared/img/b00066c-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Dans l'onglet **Android SDK** de la fenêtre **App settings**, collez le **Package name** copié. ## Étape 2. Importer le fichier de clé de compte \{#step-2-upload-the-account-key-file\} 1. Importez le fichier de clé privée du compte de service au format JSON, que vous avez créé à l'étape [Créer un fichier de clé de compte de service](create-service-account), dans la zone **Service account key file**. <img src="/assets/shared/img/20fdba1-service_key_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> N'oubliez pas de cliquer sur le bouton **Save** pour confirmer les modifications. **Étape suivante** - [Activer les notifications en temps réel pour les développeurs (RTDN) dans la Google Play Console](enable-real-time-developer-notifications-rtdn) --- # File: enable-real-time-developer-notifications-rtdn --- --- title: "Activer les notifications développeur en temps réel (RTDN) dans Google Play Console" description: "Restez informé des événements critiques et maintenez la précision des données en activant les Real-time Developer Notifications (RTDN) dans la Google Play Console pour Adapty. Découvrez comment configurer les RTDN pour recevoir des mises à jour instantanées sur les remboursements et d'autres événements importants depuis le Play Store" --- La configuration des notifications développeur en temps réel (RTDN) est essentielle pour garantir la précision des données : elle vous permet de recevoir instantanément les mises à jour du Play Store, notamment les informations sur les remboursements et d'autres événements. ## Activer les notifications \{#enable-notifications\} 1. Assurez-vous que **Google Cloud Pub/Sub** est activé. Ouvrez [ce lien](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) et sélectionnez votre projet d'application. Si vous n'avez pas encore activé **Google Cloud Pub/Sub**, vous devez le faire ici. <img src="/assets/shared/img/pubsub.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Accédez à [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) depuis le menu supérieur d'Adapty et copiez le contenu du champ **Enable Pub/Sub API** situé à côté du titre **Google Play RTDN topic name**. <img src="/assets/shared/img/a72ff2d-copy_topic.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note Si le contenu du champ **Enable Pub/Sub API** est dans un format incorrect (le format correct commence par `projects/...`), consultez la section [Corriger le format incorrect du champ Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) pour obtenir de l'aide. ::: 3. Ouvrez la [Google Play Console](https://play.google.com/console/), choisissez votre application et accédez à **Monetize with Play** -> **Monetization setup**. Dans la section **Google Play Billing**, cochez la case **Enable real-time notifications**. 4. Collez le contenu du champ **Enable Pub/Sub API** que vous avez copié dans les **App Settings** d'Adapty dans le champ **Topic name**. 5. Cliquez sur **Save changes** dans la Google Play Console. <img src="/assets/shared/img/e55ba0e-paste_topic_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Tester les notifications \{#test-notifications\} Pour vérifier que vous êtes bien abonné aux notifications développeur en temps réel : 1. Enregistrez les modifications dans les paramètres de la Google Play Console. 2. Sous **Topic name** dans la Google Play Console, cliquez sur **Send test notification**. <img src="/assets/shared/img/rtdn-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Accédez à [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) dans Adapty. Si une notification de test a été envoyée, vous verrez son statut au-dessus du nom du sujet. <img src="/assets/shared/img/rtdn-adapty-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Corriger le format incorrect du champ Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\} Si le contenu du champ **Enable Pub/Sub API** est dans un format incorrect (le format correct commence par `projects/...`), suivez ces étapes pour diagnostiquer et résoudre le problème : ### 1. Vérifier l'activation de l'API et les autorisations \{#1-verify-api-enablement-and-permissions\} Assurez-vous soigneusement que toutes les API requises sont activées et que les autorisations sont correctement accordées au compte de service. Même si vous avez déjà effectué ces étapes, il est important de les refaire pour vous assurer qu'aucune sous-étape n'a été manquée. Répétez les étapes des sections suivantes : 1. [Activer les API développeur dans la Google Play Console](enabling-of-devepoler-api) 2. [Créer un compte de service dans la Google Cloud Console](create-service-account) 3. [Accorder des autorisations au compte de service dans la Google Play Console](grant-permissions-to-service-account) 4. [Générer le fichier de clé du compte de service dans la Google Play Console](create-service-account-key-file) 5. [Configurer l'intégration Google Play Store](google-play-store-connection-configuration) ### 2. Ajuster les politiques de domaine \{#2-adjust-domain-policies\} Modifiez les politiques **Domain restricted contacts** et **Domain restricted sharing** : 1. Ouvrez la [Google Cloud Console](https://console.cloud.google.com/) et sélectionnez le projet dans lequel vous avez créé le compte de service pour gérer votre application. 2. Dans la section **Quick Access**, choisissez **IAM & Admin**. <img src="/assets/shared/img/google-cloud-IAM-and-Admin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans le panneau de gauche, choisissez **Organization Policies**. 4. Recherchez la politique **Domain restricted contacts**. <img src="/assets/shared/img/google-cloud-policy-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur le bouton représentant des points de suspension dans la colonne **Actions** et choisissez **Edit policy**. 6. Dans la fenêtre de modification de la politique : 1. Sous **Policy source**, sélectionnez le bouton radio **Override parent's policy**. 2. Sous **Policy enforcement**, sélectionnez le bouton radio **Replace**. 3. Sous **Rules**, cliquez sur le bouton **ADD A RULE**. <img src="/assets/shared/img/google-cloud-edit-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Sous **New rule** -> **Policy values**, choisissez **Allow All**. <img src="/assets/shared/img/google-cloud-allow-all-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **SET POLICY**. 7. Répétez les étapes 4 à 6 pour la politique **Domain restricted sharing**. Ensuite, recréez le contenu du champ **Enable Pub/Sub API** situé à côté du titre **Google Play RTDN topic name**. Le champ aura désormais le format correct. Veillez à remettre **Policy source** sur **Inherit parent's policy** pour les politiques modifiées une fois que vous avez activé avec succès les Real-time Developer Notifications (RTDN). ## Transfert des événements bruts \{#raw-events-forwarding\} Il peut arriver que vous souhaitiez tout de même recevoir les événements S2S bruts de Google. Pour continuer à les recevoir tout en utilisant Adapty, ajoutez simplement votre endpoint dans le champ **URL for forwarding raw Google events** et nous vous transmettrons les événements bruts tels quels depuis Google. <img src="/assets/shared/img/e388892-001774-September-22-GhkjOFbT.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- **Prochaine étape** Configurez le SDK Adapty pour : - [Android](sdk-installation-android) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: apple-search-ads --- --- title: "Apple Ads" description: "Intégrez Apple Ads avec Adapty pour optimiser les conversions d'abonnements." --- :::important L'intégration Apple Ads dans **App settings** est utilisée uniquement pour l'analyse de base et pour les intégrations SplitMetrics Acquire et Asapty. [Adapty Ads Manager](adapty-ads-manager) utilise une connexion distincte. Connectez votre compte Apple Ads dans [Adapty Ads Manager](adapty-ads-manager-get-started). ::: Adapty vous permet d'obtenir des données d'attribution depuis Apple Ads et d'analyser vos métriques avec une segmentation par campagne et par mot-clé. Adapty collecte automatiquement les données d'attribution pour Apple Ads via son SDK et le framework AdServices. Une fois l'intégration Apple Ads configurée, Adapty commencera à recevoir les données d'attribution d'Apple Ads. Vous pouvez consulter ces données directement sur la page des profils. <img src="/assets/shared/img/ba4a3e9-CleanShot_2023-08-21_at_15.14.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Configurer l'intégration \{#set-up-integration\} ### Connecter Adapty au framework AdServices \{#connect-adapty-to-the-adservices-framework\} Apple Ads via [AdServices](https://developer.apple.com/documentation/adservices) nécessite une configuration dans l'Adapty Dashboard, et vous devrez également l'activer côté application. Pour configurer Apple Ads via le framework AdServices avec Adapty, suivez ces étapes : #### Étape 1 : Obtenir la clé publique \{#step-1-obtain-public-key\} Dans l'Adapty Dashboard, rendez-vous dans [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads) Repérez la clé publique pré-générée (Adapty génère une paire de clés pour vous) et copiez-la. <img src="/assets/shared/img/baa5998-CleanShot_2023-08-21_at_14.55.542x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Si vous utilisez un service alternatif ou votre propre solution pour l'attribution Apple Ads, vous pouvez importer votre propre clé privée. ::: #### Étape 2 : Configurer la gestion des utilisateurs sur Apple Ads \{#step-2-configure-user-management-on-apple-ads\} Dans votre [compte Apple Ads](https://ads.apple.com/app-store), accédez à la page **Settings > User Management**. Pour qu'Adapty puisse récupérer les données d'attribution, vous devez inviter un autre compte Apple ID et lui accorder un accès API Account Manager. Vous pouvez utiliser n'importe quel compte auquel vous avez accès ou en créer un nouveau à cet effet. L'essentiel est que vous puissiez vous connecter à Apple Ads avec cet Apple ID. <img src="/assets/shared/img/ec183b2-kdjsfldsfjkdsfdfd.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### Étape 3 : Générer les identifiants API \{#step-3-generate-api-credentials\} Connectez-vous ensuite au compte nouvellement ajouté dans Apple Ads. Dans l'interface Apple Ads, accédez à Settings -> API. Collez la clé publique copiée précédemment dans le champ prévu à cet effet. Générez de nouveaux identifiants API. #### Étape 4 : Configurer Adapty avec les identifiants Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\} Copiez les champs Client ID, Team ID et Key ID depuis les paramètres Apple Ads. Dans l'Adapty Dashboard, collez ces identifiants dans les champs correspondants. <img src="/assets/shared/img/7356113-CleanShot_2023-08-21_at_15.08.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Connecter votre application au réseau AdServices \{#connect-your-app-to-the-adservices-network\} Une fois que vous avez terminé [la configuration du framework AdServices](#connect-adapty-to-the-adservices-framework), Adapty commence automatiquement à collecter les données d'attribution Apple Search Ad. Vous n'avez pas besoin d'ajouter de code SDK. Pour les applications iOS, ces données d'attribution auront **toujours** la priorité sur les données provenant d'autres sources. Si ce comportement n'est pas souhaité, *désactivez* l'attribution ASA en suivant les instructions ci-dessous. ## Désactiver l'intégration \{#disable-integration\} Pour désactiver l'attribution Apple Search Ads, ouvrez l'onglet [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) et désactivez le bouton **Receive Apple Search Ads attribution**. <img src="/assets/shared/img/asa-disable.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning Veuillez noter que la désactiver arrêtera complètement la réception des données analytiques ASA. Par conséquent, ASA ne sera plus utilisé dans les analyses ni envoyé aux intégrations. De plus, SplitMetrics Acquire et Asapty cesseront de fonctionner, car ils dépendent de l'attribution ASA pour fonctionner correctement. L'attribution reçue avant cette modification ne sera pas affectée. ::: ## Téléverser vos propres clés \{#uploading-your-own-keys\} :::note Facultatif Ces étapes ne sont pas nécessaires pour l'attribution Apple Ads, uniquement pour travailler avec d'autres services comme Asapty ou votre propre solution. ::: Vous pouvez utiliser votre propre paire de clés publique-privée si vous faites appel à d'autres services ou à votre propre solution pour l'attribution ASA. ### Étape 1 \{#step-1\} Générez une clé privée dans le Terminal ```text showLineNumbers title="Text" openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem ``` Importez-la dans Adapty Settings -> Apple Ads (bouton Upload private key) ### Étape 2 Générez la clé publique dans le Terminal ```text showLineNumbers title="Text" openssl ec -in private-key.pem -pubout -out public-key.pem ``` Vous pouvez utiliser cette clé publique dans les paramètres Apple Ads de votre compte avec le rôle API Account Manager. Vous pouvez ainsi utiliser les valeurs Client ID, Team ID et Key ID générées pour Adapty et d'autres services. --- # File: account --- --- title: "Détails du compte et facturation" description: "Gérez votre compte Adapty et optimisez les paramètres pour un meilleur suivi des abonnements." --- La page **Account** vous permet de gérer votre profil, les membres de l'équipe et la facturation. La page comporte trois onglets : - [Général](#general-settings) - [Abonnement et facturation](#subscription--billing) - [Membres](#members) Pour accéder aux paramètres de votre compte, cliquez sur **Account** en haut à droite ou rendez-vous sur [app.adapty.io/account](https://app.adapty.io/account). <img src="/assets/shared/img/account-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Paramètres généraux \{#general-settings\} L'onglet General contient votre profil, les paramètres du compte, les préférences d'affichage et la configuration des rapports. - **Profile** : Saisissez votre prénom, nom de famille et le nom de votre entreprise. Le nom de l'entreprise peut comporter jusqu'à 256 caractères. - **Account settings** : Consultez votre adresse e-mail enregistrée et modifiez votre mot de passe. - **Date & Time formats** : Choisissez comment les dates et les heures s'affichent dans Adapty : - **American format** : January 31, 2022 et heure au format 12 heures (AM/PM) - **European format** : 31 January, 2022 et heure au format 24 heures (16:00) - **Email reports** : Configurez des rapports quotidiens, hebdomadaires ou mensuels pour une ou toutes vos applications. Recevez des rapports récapitulatifs pour toutes les applications à la fois, ou obtenez un rapport détaillé pour chaque application sélectionnée. <img src="/assets/shared/img/account-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Abonnement & Facturation \{#subscription--billing\} L'onglet **Subscription & Billing** vous permet de gérer vos informations de paiement et votre accès aux fonctionnalités : - Ajouter ou mettre à jour vos coordonnées de paiement - Consulter les informations de facturation - Acheter des fonctionnalités payantes supplémentaires En savoir plus sur les [fonctionnalités et les tarifs](https://adapty.io/pricing). ## Membres \{#members\} Vous pouvez gérer les membres de votre équipe dans les paramètres de votre compte. Pour ajouter des membres, invitez-les par e-mail et assignez-leur un rôle. Pour en savoir plus sur la gestion des membres de l'équipe et leurs droits d'accès, consultez [cette page](members-settings). --- # File: members-settings --- --- title: "Membres" description: "Gérez les paramètres et les permissions des membres dans le tableau de bord d'Adapty." --- :::note Cette page concerne les membres du tableau de bord Adapty Si vous souhaitez attribuer différents niveaux d'accès aux utilisateurs de votre application, consultez [Niveau d'accès](access-level). ::: Le système de membres du tableau de bord Adapty vous permet d'accorder différents niveaux d'accès à Adapty et de spécifier les applications pour chaque membre. ## Rôles \{#roles\} Les rôles suivants sont disponibles pour les membres dans le tableau de bord Adapty : | Rôle | Accès à la facturation | Ajouter des membres | Modifier tout | Accès à toutes les sections | |-------------|------------------------|---------------------|---------------|-----------------------------| | Owner | ✅ | ✅ | ✅ | ✅ | | Admin | ❌ | ✅ | ✅ | ✅ | | Developer | ❌ | ❌ | ✅ | ❌ | | Viewer | ❌ | ❌ | ❌ | ✅ | | Support | ❌ | ❌ | ❌ | ❌ | | ASA manager | ❌ | ❌ | ❌ | ❌ | - **Owner :** Le Owner est le créateur d'origine du compte Adapty et détient le niveau d'accès et de contrôle le plus élevé. Les Owners ont un accès complet à la facturation Adapty, ce qui leur permet de gérer les informations de paiement et les plans d'abonnement. De plus, seuls les Owners et les Admins peuvent spécifier l'accès aux applications pour les nouveaux membres. Il ne peut y avoir qu'un seul Owner par compte Adapty. - **Admin :** Les membres ayant le rôle Admin ont un accès complet aux applications choisies. Ils peuvent effectuer diverses tâches de gestion, notamment créer et modifier des paywalls, réaliser des tests A/B, analyser les données et gérer les membres au sein de ces applications. - **Developer :** Les membres ayant le rôle Developer ont un accès complet à toutes les entités, à l'exception des analyses et des membres du compte. Ils n'ont pas accès aux paramètres de facturation. Ce rôle est destiné à ceux qui configurent les paywalls, les tests A/B et d'autres entités et intègrent Adapty dans votre application, mais ne doivent pas voir les données financières. - **Viewer :** Les membres ayant le rôle Viewer ont un accès en lecture seule aux applications choisies. Ils peuvent consulter les informations, mais ne peuvent pas créer ni modifier des paywalls, des tests A/B et d'autres fonctionnalités, inviter de nouveaux utilisateurs, créer de nouvelles applications ni modifier les paramètres de l'application. - **Support :** Les membres ayant le rôle Support n'ont accès qu'aux profils d'utilisateurs dans les applications choisies. Ils ne peuvent toutefois pas effectuer des actions telles qu'ajouter de nouveaux membres ou accéder à d'autres sections d'Adapty. Ce rôle convient particulièrement aux équipes d'assistance ou aux personnes qui doivent aider les clients avec des questions liées aux abonnements ou le dépannage. - **ASA manager** : Les membres ayant le rôle ASA manager n'ont accès qu'au tableau de bord [Adapty Ads Manager](adapty-ads-manager). ## Ajouter un membre \{#add-a-member\} Dans Adapty, vous pouvez inviter jusqu'à 256 membres. L'ajout de nouveaux membres est gratuit. :::note Vous pouvez uniquement inviter des adresses e-mail qui ne sont pas encore enregistrées dans Adapty. Si votre collègue possède un compte indépendant, invitez une autre adresse e-mail ou contactez le support Adapty pour supprimer son compte existant. ::: Pour ajouter un membre : 1. Cliquez sur **Account** en haut à droite et ouvrez l'onglet **Members**. 2. Cliquez sur **Invite member**. <img src="/assets/shared/img/invite-member.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Saisissez l'adresse e-mail du membre. 4. Sélectionnez un [rôle](#roles) dans la liste. 5. Sélectionnez les applications auxquelles accorder l'accès. 6. (Facultatif) Activez **Always allow access to new apps** pour accorder automatiquement l'accès aux futures applications. 7. Cliquez sur **Save**. <img src="/assets/shared/img/add-member.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Transférer la propriété du compte \{#transfer-account-ownership\} Si vous devez transférer la **propriété du compte** dans son ensemble, contactez notre équipe d'assistance à [support@adapty.io](mailto:support@adapty.io). Si vous devez transférer la **propriété de l'application**, consultez le [guide dédié](transfer-apps) pour plus d'informations. --- # File: apple-platform-resources --- --- title: "Ressources pour la plateforme Apple" description: "Explorez les ressources de la plateforme Apple pour optimiser la monétisation et la gestion des abonnements de votre application." --- Adapty propose des SDK et des intégrations adaptés aux plateformes Apple, simplifiant le développement des achats intégrés, des abonnements, des paywalls et des tests A/B. Utilisez les ressources suivantes pour tirer le meilleur parti d'Adapty sur Apple. ### Configuration initiale dans App Store Connect \{#initial-configuration-in-app-store-connect\} 1. [Générer une clé d'achat intégré dans App Store Connect](generate-in-app-purchase-key) ### Configuration des produits et offres dans App Store Connect \{#products-and-offers-configuration-in-app-store-connect\} 1. [Produit dans l'App Store](app-store-products) 2. [Offres dans l'App Store](app-store-offers) ### Informations complémentaires \{#additional-information\} 1. [Configurer App Store Connect](set-up-app-store-connect) 2. [Confidentialité des applications Apple](apple-app-privacy) 3. [Partage familial Apple](apple-family-sharing) 4. [Programme App Store pour les petites entreprises](app-store-small-business-program) --- # File: set-up-app-store-connect --- --- title: "Configurer App Store Connect" description: "Un guide pour les développeurs débutants expliquant comment s'inscrire au programme Apple Developer et configurer App Store Connect pour les achats intégrés." --- Si vous **développez votre première app iOS**, vous devez configurer votre compte Apple Developer et App Store Connect avant d'intégrer Adapty. :::note Si vous avez déjà un compte Apple Developer et une app enregistrée dans App Store Connect, vous pouvez passer ce guide et aller directement à [Intégration initiale avec l'App Store](initial_ios). ::: ## Étape 1. S'inscrire au programme Apple Developer \{#step-1-enroll-in-apple-developer-program\} Pour distribuer des apps sur l'App Store et vendre des achats intégrés, vous devez rejoindre l'[Apple Developer Program](https://developer.apple.com/programs/). ### Choisir le type d'inscription \{#choose-enrollment-type\} Apple propose deux types d'inscription : | | Individuel | Organisation | |--------------------------------------|------------------------|-------------------------------------| | **Pour qui** | Développeurs solo | Entreprises, équipes, associations | | **Nécessite un numéro D-U-N-S** | Non | Oui | | **Apps publiées sous** | Votre nom personnel | Le nom de votre organisation | | **Gestion d'équipe** | Non disponible | Disponible | :::tip Si vous vous inscrivez en tant qu'organisation, vous avez besoin d'un **numéro D-U-N-S** — un identifiant d'entreprise unique à neuf chiffres fourni par Dun & Bradstreet. Vous pouvez [vérifier si votre organisation en possède déjà un](https://developer.apple.com/enroll/duns-lookup/) ou en demander un nouveau — le lien se trouve en bas de la page de recherche. La réception d'un numéro D-U-N-S peut prendre jusqu'à 5 jours ouvrables. ::: ### S'inscrire \{#enroll\} 1. Rendez-vous sur la [page d'inscription au programme Apple Developer](https://developer.apple.com/programs/enroll/). 2. Connectez-vous avec votre Apple ID. Si vous n'en avez pas, créez-en un d'abord. 3. Suivez les étapes correspondant à votre type d'inscription (individuel ou organisation). 4. Payez les frais annuels. Une fois votre inscription traitée par Apple, vous accédez à [App Store Connect](https://appstoreconnect.apple.com). L'inscription prend généralement jusqu'à 48 heures. Pour les organisations, cela peut prendre plus longtemps si une vérification D-U-N-S est requise. ## Étape 2. Configurer votre app dans App Store Connect \{#step-2-set-up-your-app-in-app-store-connect\} Avant de pouvoir vendre des achats intégrés, effectuez la configuration initiale dans App Store Connect. Cela comprend la signature des contrats, l'ajout de vos coordonnées bancaires et l'enregistrement de votre app. ### Signer le contrat Paid Applications Agreement \{#sign-the-paid-applications-agreement\} Apple exige que vous signiez le Paid Applications Agreement avant de pouvoir vendre sur l'App Store. Cela s'applique aussi bien aux apps payantes qu'aux achats intégrés dans les apps gratuites. 1. Rendez-vous sur la page **Business** dans [App Store Connect](https://appstoreconnect.apple.com/business). 2. Trouvez le contrat **Paid Apps** et cliquez sur **Review and Agree**. 3. Complétez les informations requises : - **Banking information** : Ajoutez un compte bancaire sur lequel Apple enverra vos revenus. - **Tax information** : Remplissez les formulaires fiscaux pour les pays où vous souhaitez vendre. - **Contact information** : Renseignez vos coordonnées. :::important Vous devez compléter les trois sections (bancaire, fiscale, contact) pour que le contrat devienne actif. Tant que le contrat n'est pas actif, vous ne pouvez pas vendre d'achats intégrés. ::: ### Créer un Bundle ID \{#create-a-bundle-id\} Un Bundle ID identifie votre app de façon unique dans l'écosystème Apple. Vous en avez besoin pour enregistrer votre app dans App Store Connect et pour configurer l'intégration Adapty. 1. Ouvrez le [portail Apple Developer](https://developer.apple.com/account). 2. Accédez à **Certificates, Identifiers & Profiles** → **Identifiers**. 3. Cliquez sur **+** pour enregistrer un nouvel identifiant. 4. Sélectionnez **App IDs** et cliquez sur **Continue**. 5. Sélectionnez **App** comme type et cliquez sur **Continue**. 6. Remplissez les champs : - **Description** : Un nom pour vous aider à identifier ce Bundle ID (ex. : « My Subscription App »). - **Bundle ID** : Choisissez **Explicit** et saisissez un identifiant unique au format domaine inversé (ex. : `com.yourcompany.yourapp`). 7. Dans la section **Capabilities**, faites défiler vers le bas et cochez **In-App Purchase**. 8. Cliquez sur **Continue**, puis sur **Register**. ### Enregistrer votre app dans App Store Connect \{#register-your-app-in-app-store-connect\} 1. Rendez-vous sur la page **Apps** dans [App Store Connect](https://appstoreconnect.apple.com/apps). 2. Cliquez sur **+** → **New App**. 3. Remplissez les champs obligatoires : - **Platforms** : Sélectionnez **iOS**. - **Name** : Le nom de votre app tel qu'il apparaîtra sur l'App Store. - **Primary language** : La langue par défaut des métadonnées de votre app. - **Bundle ID** : Sélectionnez le Bundle ID créé à l'étape précédente. - **SKU** : Un identifiant unique pour votre app (non visible par les utilisateurs). Par exemple, `my_subscription_app_2025`. 4. Cliquez sur **Create**. Votre app est maintenant enregistrée dans App Store Connect et prête pour l'intégration Adapty. ## Et ensuite \{#whats-next\} - [Intégration initiale avec l'App Store](initial_ios) : Connectez votre app App Store à Adapty - [Intégration du SDK](quickstart-sdk) : Intégrez le SDK Adapty dans le code de votre app - [Tests en sandbox](test-purchases-in-sandbox) : Testez vos achats intégrés avant la mise en ligne - [Soumettre votre app iOS à l'App Store](submit-app-to-app-store) : Uploadez votre build et soumettez-le pour la revue Apple - [Programme Small Business de l'App Store](app-store-small-business-program) : Réduisez votre commission App Store de 30 % à 15 % --- # File: app-store-products --- --- title: "Produit dans l'App Store" description: "Gérez efficacement les produits App Store grâce aux outils d'abonnement d'Adapty." --- Cette page vous guide dans la création d'un produit dans App Store Connect. Même si ces informations ne concernent pas directement les fonctionnalités d'Adapty, elles constituent une ressource utile si vous rencontrez des difficultés lors de la création de produits dans votre compte App Store Connect. Pour créer un produit qui sera lié à Adapty : 1. Ouvrez **App Store Connect**. Accédez à la section [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/148c3b5-subscriptions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Si vous n'avez pas encore créé de groupe d'abonnements, cliquez sur le bouton **Create** sous le titre **Subscription Groups** pour démarrer le processus. Les [groupes d'abonnements](https://developer.apple.com/help/app-store-connect/manage-subscriptions/offer-auto-renewable-subscriptions) dans App Store Connect permettent de catégoriser et de gérer vos produits, offrant aux utilisateurs la possibilité de passer facilement d'une offre à l'autre. Notez qu'il n'est pas possible de créer un abonnement en dehors d'un groupe. 3. Dans la fenêtre **Create Subscription Group** qui s'ouvre, saisissez un nom pour le nouveau groupe d'abonnements dans le champ **Reference Name**. Ce nom de référence est une étiquette ou un identifiant défini par vous pour distinguer et gérer les différents groupes d'abonnements au sein de votre application. Le nom de référence n'est pas visible par les utilisateurs ; il est destiné à votre usage interne et à votre organisation. Il vous permet d'identifier et de référencer facilement des groupes d'abonnements spécifiques lors de leur gestion dans l'interface App Store Connect. Cela s'avère particulièrement utile si vous proposez plusieurs offres d'abonnement ou souhaitez les catégoriser d'une façon cohérente avec la structure de votre application. <img src="/assets/shared/img/3f93c44-create_subscription_group.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur le bouton **Create** pour confirmer la création du groupe d'abonnements. 5. Le groupe d'abonnements est créé et s'ouvre. Vous pouvez maintenant créer des abonnements dans ce groupe. Cliquez sur le bouton **Create** sous le titre **Subscriptions**. Si vous ajoutez un nouvel abonnement à un groupe existant, cliquez sur le bouton **Plus** à côté du titre **Subscriptions**. <img src="/assets/shared/img/22fc643-add_subscription.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Dans la fenêtre **Create Subscription** qui s'ouvre, saisissez le nom de l'abonnement dans le champ **Reference Name** et son code unique dans le champ **Product ID**. Le Reference Name est un identifiant exclusif dans App Store Connect pour votre abonnement intégré. Il n'est pas visible par vos utilisateurs sur l'App Store. Nous recommandons d'utiliser une description claire et lisible qui représente précisément l'abonnement que vous souhaitez créer. Ce nom ne doit pas dépasser 64 caractères. Le Product ID est un identifiant alphanumérique unique, indispensable pour accéder à votre produit pendant la phase de développement et pour le synchroniser avec Adapty. Seuls les caractères alphanumériques, les points et les underscores sont autorisés dans le Product ID. <img src="/assets/shared/img/04aca55-create_subscription.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur le bouton **Create** pour confirmer la création de l'abonnement. 8. L'abonnement est créé et s'ouvre. Sélectionnez maintenant la durée de l'abonnement dans la liste **Subscription Duration**. Même si la durée est déjà indiquée dans le nom de l'abonnement, pensez bien à renseigner le champ **Subscription Duration**. <img src="/assets/shared/img/f56cf0f-subscription_duration.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Il est maintenant temps de configurer le prix de l'abonnement. Pour ce faire, cliquez sur le bouton **Add Subscription Price** sous le titre Subscription Prices. Vous devrez peut-être faire défiler la page vers le bas pour le trouver. 10. Dans la fenêtre **Subscription Price** qui s'ouvre, sélectionnez le pays de référence dans la liste **Country or Region** et la devise de base dans la liste **Price**. Apple calculera ensuite automatiquement les prix pour l'ensemble des 175 pays ou régions à partir de ce prix de base et des taux de change en vigueur. <img src="/assets/shared/img/de1cec8-subscription_price.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 11. Cliquez sur le bouton **Next**. Dans la fenêtre **Price by Country or Region** qui s'ouvre, vous voyez les prix recalculés automatiquement pour tous les pays. Vous pouvez les modifier si vous le souhaitez. <img src="/assets/shared/img/2a047a6-price_by_country.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 12. Après avoir mis à jour les prix régionaux, cliquez sur le bouton **Next** en bas de la fenêtre. 13. Dans la fenêtre **Confirm Subscription Price?** qui s'ouvre, vérifiez attentivement les prix finaux. Pour les corriger, vous pouvez cliquer sur le bouton **Back** pour revenir à la fenêtre **Price by Country or Region** et les modifier. Lorsque les prix vous conviennent, cliquez sur le bouton **Confirm**. <img src="/assets/shared/img/d2b2031-confirm_prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 14. Après avoir fermé la fenêtre **Confirm Subscription Price?**, pensez à cliquer sur le bouton **Save** dans la fenêtre de votre abonnement. Sans cela, l'abonnement ne sera pas créé et toutes les données saisies seront perdues. Notez que les étapes décrites jusqu'ici portent sur la configuration d'un abonnement auto-renouvelable. Cependant, si vous souhaitez configurer d'autres types d'achats intégrés, cliquez sur l'onglet **In-App Purchases** dans la barre latérale, plutôt que sur « Subscriptions ». Vous accéderez ainsi à la section où vous pouvez gérer et créer différents types d'achats intégrés. <img src="/assets/shared/img/5663d85-in-app_purchases.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Ajouter des produits à Adapty \{#add-products-to-adapty\} Une fois vos achats intégrés, abonnements et offres ajoutés dans App Store Connect, l'étape suivante consiste à [ajouter ces produits à Adapty](create-product). --- # File: apple-app-privacy --- --- title: "Confidentialité des apps Apple" description: "Comprenez les politiques de confidentialité des apps Apple et leur impact sur votre app d'abonnement." --- Apple exige une déclaration de confidentialité pour toutes les nouvelles apps et mises à jour d'apps, à la fois dans la section **App Privacy** d'App Store Connect et sous forme de fichier manifeste de l'app. Adapty est une dépendance tierce de votre app, vous devez donc indiquer comment vous utilisez Adapty en lien avec les données utilisateur. ## Manifeste de confidentialité des apps Apple \{#apple-app-privacy-manifest\} Le [fichier manifeste de confidentialité](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests), nommé `PrivacyInfo.xcprivacy`, décrit quelles données privées votre app utilise et pourquoi. En tant que propriétaire d'app, vous devez créer un fichier manifeste pour votre app. De plus, si vous intégrez des SDK supplémentaires, assurez-vous que les fichiers manifestes de ceux figurant dans la liste des [SDK nécessitant un manifeste de confidentialité et une signature](https://developer.apple.com/support/third-party-SDK-requirements/) sont bien inclus. Lorsque vous compilez votre app, Xcode fusionnera tous ces fichiers manifestes en un seul. Bien qu'Adapty ne figure pas dans la liste des [SDK nécessitant un manifeste de confidentialité et une signature](https://developer.apple.com/support/third-party-SDK-requirements/), les versions 2.10.2 et supérieures du SDK Adapty l'incluent pour votre commodité. Pensez à mettre à jour le SDK pour obtenir le manifeste. Bien qu'Adapty ne nécessite aucune donnée à inclure dans le fichier manifeste (également appelé rapport de confidentialité de l'app), si vous utilisez le `customerUserId` d'Adapty à des fins de suivi, vous devez le spécifier dans votre fichier manifeste comme suit : 1. Ajoutez un dictionnaire au tableau `NSPrivacyCollectedDataTypes` dans votre fichier d'informations de confidentialité. 2. Ajoutez les clés `NSPrivacyCollectedDataType`, `NSPrivacyCollectedDataTypeLinked` et `NSPrivacyCollectedDataTypeTracking` au dictionnaire. 3. Ajoutez la chaîne `NSPrivacyCollectedDataTypeUserID` (identifiant du type de données `UserID` dans la [liste des catégories et types de données à déclarer dans le fichier manifeste](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Describe-the-data-your-app-or-third-party-SDK-collects)) pour la clé `NSPrivacyCollectedDataType` dans votre dictionnaire `NSPrivacyCollectedDataTypes`. 4. Ajoutez `true` pour les clés `NSPrivacyCollectedDataTypeTracking` et `NSPrivacyCollectedDataTypeLinked` dans votre dictionnaire `NSPrivacyCollectedDataTypes`. 5. Utilisez la chaîne `NSPrivacyCollectedDataTypePurposeProductPersonalization` comme valeur pour la clé `NSPrivacyCollectedDataTypePurposes` dans votre dictionnaire `NSPrivacyCollectedDataTypes`. Si vous ciblez vos paywalls vers des audiences avec des attributs personnalisés, réfléchissez attentivement aux attributs que vous utilisez et vérifiez s'ils correspondent aux [catégories et types de données à déclarer dans le fichier manifeste](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests). Si c'est le cas, répétez les étapes ci-dessus pour chaque type de données. Après avoir déclaré tous les types et catégories de données que vous collectez, créez le rapport de confidentialité de votre app comme décrit dans la [documentation Apple](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Create-your-apps-privacy-report). ## Déclaration de confidentialité des apps Apple dans App Store Connect \{#apple-app-privacy-disclosure-in-app-store-connect\} 1. Dans [App Store Connect](https://appstoreconnect.apple.com/), ouvrez votre app et accédez à **App Privacy**. Cliquez sur **Get Started**. <img src="/assets/shared/img/app-privacy-get-started.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez **Yes, we collect data from this app** et cliquez sur **Next**. <img src="/assets/shared/img/app-privacy-data-collection.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Types de données \{#data-types\} Le tableau ci-dessous liste les types de données qu'Apple vous demande de déclarer et indique lesquels sont requis par Adapty. **Cela ne couvre qu'Adapty.** Si votre app collecte des données supplémentaires via d'autres SDK ou votre propre code, sélectionnez également ces types de données. ✅ = Requis par Adapty 👀 = Peut être requis \(voir les détails ci-dessous\) ❌ = Non requis par Adapty — à sélectionner si votre app collecte ces données par d'autres moyens | Type de données | Requis | Remarque | |-------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Identifiants | ✅ | <p>Si vous identifiez les utilisateurs avec un customerUserId, sélectionnez « User ID ».</p><p></p><p>Adapty collecte l'IDFA, vous devez donc sélectionner « Device ID ».</p> | | Achats | ✅ | Adapty collecte l'historique des achats des utilisateurs. | | Informations de contact, dont nom, numéro de téléphone ou adresse e-mail | 👀 | Requis si vous transmettez des données personnelles comme le nom, le numéro de téléphone ou l'adresse e-mail via la méthode **`updateProfile`**. | | Données d'utilisation | 👀 | Si vous utilisez des SDK d'analyse tels qu'Amplitude, Mixpanel, AppMetrica ou Firebase, cela peut être requis. | | Localisation | ❌ | Adapty ne collecte pas de données de localisation précise. À sélectionner si votre app les collecte. | | Santé & Remise en forme | ❌ | Adapty ne collecte pas de données de santé ou de remise en forme. À sélectionner si votre app les collecte. | | Informations sensibles | ❌ | Adapty ne collecte pas d'informations sensibles. À sélectionner si votre app en collecte. | | Contenu utilisateur | ❌ | Adapty ne collecte pas de contenu utilisateur. À sélectionner si votre app en collecte. | | Diagnostics | ❌ | Adapty ne collecte pas de données de diagnostic. À sélectionner si votre app en collecte. | | Historique de navigation | ❌ | Adapty ne collecte pas l'historique de navigation. À sélectionner si votre app le collecte. | | Historique de recherche | ❌ | Adapty ne collecte pas l'historique de recherche. À sélectionner si votre app le collecte. | | Contacts | ❌ | Adapty ne collecte pas les listes de contacts. À sélectionner si votre app les collecte. | | Informations financières | ❌ | Adapty ne collecte pas d'informations financières. À sélectionner si votre app en collecte. | ### Types de données requis \{#required-data-types\} #### Achats \{#purchases\} Lors de l'utilisation d'Adapty, vous devez déclarer que votre app collecte l'**historique des achats**. <img src="/assets/shared/img/feb3b9f-CleanShot_2023-08-25_at_12.32.552x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### Identifiants \{#identifiers\} Lors de l'utilisation d'Adapty, vous devez déclarer les identifiants suivants : - **Device ID** — Adapty collecte l'IDFA. - **User ID** — requis si vous identifiez les utilisateurs avec **`customerUserId`**. <img src="/assets/shared/img/93f3daa-CleanShot_2023-08-25_at_12.35.272x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Utilisation des données \{#data-usage\} Après avoir enregistré les **types de données**, vous devrez indiquer comment les données sont utilisées : 1. Cliquez sur **Set up purchase history** dans le bloc **Purchases**. <img src="/assets/shared/img/purchase-privacy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Lorsqu'Apple vous demande comment les données d'historique des achats sont utilisées, sélectionnez les options suivantes pour Adapty : - **Analytics** — Adapty utilise l'historique des achats pour les analyses de revenus, les cohortes et les métriques. - **Product Personalization** — Adapty utilise les données d'achat pour la segmentation des audiences et le ciblage des paywalls. - **App Functionality** — Adapty valide les achats, gère les niveaux d'accès et suit le statut des abonnements. Sélectionnez des finalités supplémentaires si votre app utilise les données d'achat d'autres façons (par exemple, si vous envoyez des événements d'achat à des plateformes publicitaires via les intégrations Adapty). <img src="/assets/shared/img/purchase-history.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Next**. 4. Pour **Device ID** et **User ID** (si utilisé) : 1. Cliquez sur **Set up user/device ID** dans le bloc **User/Device ID**. 2. Lorsqu'Apple vous demande comment les données d'identifiant sont utilisées, sélectionnez les options suivantes pour Adapty : - **App Functionality** — Adapty utilise les identifiants pour gérer les profils utilisateur, associer les achats et suivre les niveaux d'accès. Si vous envoyez des données d'attribution à des plateformes tierces via les intégrations Adapty (comme AppsFlyer ou Adjust), sélectionnez également **Third-Party Advertising**. Sélectionnez des finalités supplémentaires si votre app utilise les identifiants d'autres façons. <img src="/assets/shared/img/user-id-privacy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Next**. --- # File: apple-family-sharing --- --- title: "Apple family sharing" description: "Activez Apple Family Sharing dans Adapty pour prendre en charge les abonnements partagés." --- Le partage familial Apple permet de distribuer des achats intégrés entre les membres d'une famille. Pour les utilisateurs d'applications orientées groupe, comme les services de streaming vidéo ou les applications pour enfants, c'est un moyen pratique de partager un abonnement sans avoir à communiquer son identifiant Apple. En permettant à jusqu'à cinq membres de la famille d'utiliser un abonnement, le [Partage familial](https://developer.apple.com/documentation/storekit/supporting-family-sharing-in-your-app) peut améliorer l'engagement et la fidélisation des utilisateurs de votre application. Dans ce guide, nous expliquerons comment activer le Partage familial pour vos abonnements et comment Adapty gère les achats partagés au sein d'une famille. Pour commencer, rendez-vous sur [App Store Connect](https://appstoreconnect.apple.com/). Le Partage familial est désactivé par défaut pour tous les achats intégrés, nouveaux comme existants. Vous devez donc l'activer individuellement pour chacun d'eux. Pour ce faire, accédez à la **page de votre application**, naviguez jusqu'à la page de l'achat intégré concerné, puis sélectionnez l'option **Turn On** dans la section Family Sharing. Gardez à l'esprit qu'une fois le Partage familial activé pour un produit, **il ne peut plus être désactivé**, car cela perturberait l'expérience des utilisateurs qui ont déjà partagé l'abonnement avec leur famille. Notez également que seuls les produits non consommables et les abonnements peuvent être partagés. <img src="/assets/shared/img/6db165a-CleanShot_2023-03-28_at_17.15.342x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Dans la fenêtre modale qui s'affiche, cliquez simplement sur le bouton **Confirm** pour finaliser la configuration. La section Family Sharing devrait alors afficher le message « This subscription can be shared by everyone in a family group. », confirmant que l'abonnement est désormais activé pour le Partage familial et peut être partagé avec jusqu'à cinq membres de la famille. Adapty prend en charge le Partage familial sans aucune configuration supplémentaire de votre part. Il vous suffit de [configurer vos produits](app-store-products) depuis l'App Store : une fois le **Partage familial** activé dans App Store Connect, il sera automatiquement disponible dans **Adapty** et vous sera transmis sous forme d'événement via le webhook. :::note Le Partage familial n'est pas pris en charge dans l'environnement sandbox. ::: À noter que lorsqu'un utilisateur achète un abonnement et le partage avec les membres de sa famille, un **délai pouvant aller jusqu'à une heure** s'écoule avant que celui-ci ne soit disponible pour eux. Apple a prévu ce délai pour laisser à l'utilisateur le temps de changer d'avis et d'annuler le partage s'il le souhaite. En revanche, lors du renouvellement d'un abonnement, aucun délai n'est appliqué. Lorsqu'un utilisateur achète un produit intégré partageable en famille, la transaction apparaît dans son reçu comme d'habitude, mais avec l'ajout d'un nouveau champ `in_app_ownership_type` ayant la valeur `PURCHASED`. De plus, une nouvelle transaction est créée pour chaque membre de la famille, avec un `web_order_line_item_id` et un `original_transaction_id` différents de ceux de l'achat d'origine, ainsi qu'un champ `in_app_ownership_type` ayant la valeur `FAMILY_SHARED`. Pour garantir un calcul précis des revenus, seules les transactions dont le champ `in_app_ownership_type` a la valeur `PURCHASED` sont comptabilisées dans les analyses Adapty. Les transactions `FAMILY_SHARED` sont exclues des métriques de revenus et de conversion. **Événements envoyés pour les transactions de Partage familial.** Les transactions `FAMILY_SHARED` ne déclenchent qu'un événement **Access level updated**. Les événements d'abonnement par produit ne sont pas déclenchés pour les membres de la famille. | Événement | `FAMILY_SHARED` | `PURCHASED` | | --- | --- | --- | | **Access level updated** | Oui | Oui | | **Subscription started** | Non | Oui | | **Trial started** | Non | Oui | | **Subscription renewed** | Non | Oui | | **Subscription expired** | Non | Oui | | **Subscription refunded** | Non | Oui | | **Billing issue detected** | Non | Oui | Si vos analyses en aval se basent sur **Subscription started**, les membres de la famille n'y apparaîtront pas. Utilisez **Access level updated** pour détecter les membres de la famille actifs. Pour identifier les autres membres de la famille dans Adapty, vous pouvez les retrouver dans les détails de l'événement. Commencez par localiser la transaction d'achat familial d'origine, puis examinez les détails de l'événement correspondant en recherchant le même produit, la même date d'achat et la même date d'expiration. En analysant ces détails, vous pourrez identifier les autres transactions d'adhésion familiale associées à l'achat d'origine. --- # File: app-store-small-business-program --- --- title: "App Store Small Business Program" description: "Comprendre le programme Small Business d'Apple, son impact sur vos revenus et les analyses Adapty" --- :::link Pour le programme équivalent sur le Play Store, consultez [Google Reduced Service Fee](google-reduced-service-fee). ::: Les organisations dont les revenus annuels sur l'App Store ne dépassent pas 1 million USD peuvent participer au [programme Small Business](https://developer.apple.com/app-store/small-business-program/) d'Apple. En vous inscrivant, le taux de commission standard de 30 % est réduit à **15 %**. Les membres du programme doivent **modifier leurs paramètres Adapty** pour garantir des calculs de revenus corrects et un traitement approprié des événements d'intégration. Cet article décrit : * [Comment configurer Adapty](#configure-adapty) si votre application est inscrite au programme Small Business * [Comment s'inscrire au programme](#apply-for-the-program) pour réduire votre commission sur le store ## Configurer Adapty \{#configure-adapty\} Adapty peut appliquer le taux de commission réduit à vos [analyses](analytics) et [événements d'intégration](analytics-integration). Pour l'activer, indiquez votre statut dans le programme Small Business pour chaque application. :::warning Configurez votre statut SBP dans Adapty **dès que vous recevez l'approbation**. Les modifications tardives ne peuvent pas réécrire les événements webhook déjà envoyés ([détails](#retroactive-setting-changes)). ::: 1. Ouvrez [**App Settings** → **General**](https://app.adapty.io/account) 2. Repérez la section **Small Business Program**. 3. Cliquez sur **Add period**. 4. Sélectionnez la date de début de l'adhésion. 5. Sélectionnez une date de fin, ou activez la case **At the current moment** pour prolonger ce statut indéfiniment. Si vous [perdez votre éligibilité](#losing-eligibility) à l'avenir, vous pourrez modifier la date de fin. 6. Cliquez sur **Apply**. Si votre organisation reste éligible au programme, son adhésion est reconduite pour l'année civile suivante. Mais le statut d'adhésion ne s'applique **qu'à la plage de dates que vous spécifiez**. * Cliquez sur **Add period** pour ajouter une nouvelle période d'adhésion. * Pour prolonger ce statut indéfiniment, activez la case **At the current moment**. Pour vérifier votre configuration, ouvrez le [graphique Revenus](revenue) et sélectionnez **Proceeds after store commission**. Vérifiez que les revenus affichés reflètent bien le taux de commission réduit. ## S'inscrire au programme \{#apply-for-the-program\} ### Conditions d'éligibilité \{#eligibility-requirements\} Apple détermine l'éligibilité au SBP en fonction de vos **revenus annuels** — les ventes de l'année civile précédente **après** déduction de la commission du store et des taxes. Pour être éligible, les revenus annuels de votre organisation et de ses <InlineTooltip tooltip="Comptes Développeur Associés">Comptes dans lesquels vous ou votre organisation détenez la majorité des parts (>50 %) ou avez un pouvoir de décision.</InlineTooltip> ne doivent pas dépasser 1 million USD au total. Les organisations nouvellement créées sont automatiquement éligibles pour s'inscrire au programme. ### Avant de vous inscrire \{#before-you-apply\} Assurez-vous de : - Être le titulaire du compte dans l'Apple Developer Program - Avoir accepté le dernier contrat Paid Applications dans App Store Connect - Pouvoir lister tous vos Comptes Développeur Associés ### Inscription \{#enrollment\} 1. Rendez-vous sur la [page d'inscription au programme App Store Small Business](https://developer.apple.com/app-store/small-business-program/). 2. Cliquez sur **Enroll** et connectez-vous avec votre compte Apple Developer. 3. Vérifiez les informations pré-remplies (nom, e-mail, Team ID) et soumettez. ### Examen \{#review\} Le processus d'examen peut prendre plus d'un mois. Si vous êtes éligible, vous recevrez un e-mail d'approbation d'Apple. Une fois approuvé, un délai d'attente s'applique. La commission réduite entre en vigueur le 15e jour de la [prochaine période fiscale](https://adapty.io/apple-fiscal-calendar/) d'Apple. Elle ne s'applique pas aux transactions antérieures. ### Perte d'éligibilité \{#losing-eligibility\} Lorsque vos revenus totaux pour l'année civile en cours dépassent 1 million USD, vous perdez votre adhésion au programme et Apple commence à appliquer la commission standard de 30 %. :::important Si votre entreprise quitte le programme Small Business, **modifiez immédiatement la date de sortie** dans vos paramètres. Sinon, Adapty continuera à calculer la commission au taux réduit. ::: Vous pouvez vous réinscrire au programme **l'année suivant** celle où vos revenus annuels repassent sous le seuil d'1 million USD. Consultez les [conditions officielles du programme](https://developer.apple.com/app-store/small-business-program/) pour plus de détails. ## Modifications rétroactives des paramètres \{#retroactive-setting-changes\} Lorsque vous modifiez votre statut de commission réduite dans Adapty avec une date d'effet rétroactive, le nouveau taux de commission apparaît dans les données d'Adapty selon des calendriers différents : | Où le taux apparaît | Ce qui se passe après la modification du taux | | --- | --- | | Tableau de bord Analytics (Revenue, Proceeds, MRR, ARR) | Adapty applique le nouveau taux sous 24 heures, lors du recalcul quotidien. | | Exports S3, GCS et BigQuery | Adapty applique le nouveau taux lors du prochain export planifié. | | Événements webhook déjà envoyés | Adapty ne peut pas modifier les événements webhook après leur envoi. Ils conservent l'ancien taux. | Si votre entrepôt de données stocke des revenus issus d'événements webhook, ces enregistrements conservent l'ancien taux de commission. Pour réconcilier vos données, récupérez la période concernée depuis le tableau de bord Analytics, ou générez un nouvel export vers S3, GCS ou BigQuery. --- # File: google-platform-resources --- --- title: "Ressources de la plateforme Google" description: "Explorez les ressources de la plateforme Google pour optimiser la gestion des abonnements dans votre application." --- Adapty propose des SDK et des intégrations adaptés aux plateformes Google, simplifiant le développement des achats intégrés, des abonnements, des paywalls et des tests A/B. Utilisez les ressources suivantes pour tirer le meilleur parti d'Adapty sur les plateformes Google. ### Configuration initiale dans la Google Play Console \{#initial-configuration-in-google-play-console\} 1. [Activer les API développeur dans la Google Play Console](enabling-of-devepoler-api) 2. [Créer un compte de service dans la Google Cloud Console](create-service-account) 3. [Générer un fichier de clé de compte de service](create-service-account-key-file) 4. [Accorder des autorisations à un compte de service dans la Google Play Console](grant-permissions-to-service-account) ### Configuration des produits et offres dans la Google Play Console \{#products-and-offers-configuration-in-google-play-console\} 1. [Créer des produits pour votre application mobile](android-products) 2. [Créer des offres pour les produits](google-play-offers) ### Informations complémentaires \{#additional-information\} 1. [Confidentialité des données Google Play](google-play-data-safety) 2. [Confidentialité des applications Apple](apple-app-privacy) 3. [Frais de service réduits Google](google-reduced-service-fee) --- # File: android-products --- --- title: "Produit dans le Play Store" description: "Gérez vos produits Android avec Adapty, simplifiez les achats intégrés et optimisez vos stratégies de monétisation." --- Cette page explique comment créer un produit dans le Play Store. Même si ces informations ne concernent pas directement Adapty, elles constituent une ressource utile si vous rencontrez des difficultés lors de la création de produits dans la Google Play Console. Un produit désigne un article numérique ou un service que vous proposez dans votre application sur le Play Store, généralement disponible à l'achat. Cela comprend les achats intégrés tels que les achats uniques, les abonnements ou d'autres contenus numériques que les utilisateurs peuvent acquérir au sein de votre application. Dans le [système de facturation de Google](https://developer.android.com/google/play/billing/compatibility), les abonnements peuvent inclure plusieurs plans de base, chacun proposant différentes remises ou offres. Cette structure repose sur trois composants principaux : - **Abonnements :** ils représentent des ensembles d'avantages dont les utilisateurs peuvent profiter pendant une période définie (les articles vendus). Par exemple, un « niveau Gold » offrant des fonctionnalités premium aux abonnés. - **Plans de base :** ils représentent des configurations spécifiques de périodes de facturation, de types de renouvellement et de prix (la façon dont les articles sont vendus). Par exemple, « annuel avec renouvellement automatique » ou « mensuel prépayé ». - **Offres :** il s'agit de remises disponibles pour les utilisateurs éligibles, qui modifient le prix du plan de base. Par exemple, « essai gratuit de 14 jours pour les nouveaux utilisateurs ». ## Comment créer un produit dans le Play Store ? \{#how-to-create-a-product-in-play-store\} Un produit désigne un article numérique ou un service que vous proposez dans votre application, généralement disponible à l'achat. Cela comprend les achats intégrés tels que les achats uniques, les abonnements ou d'autres contenus numériques que les utilisateurs peuvent acquérir au sein de votre application. Pour configurer un produit sur Android : 1. Ouvrez la section [**Monetize** -> **Subscriptions**](https://console.cloud.google.com/iam-admin/serviceaccounts) ou [**Monetize** -> **In-app products**](https://console.cloud.google.com/iam-admin/serviceaccounts) dans le menu de gauche de la Google Play Console. <img src="/assets/shared/img/6eff1d1-subscription_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le bouton **Create subscription**. <img src="/assets/shared/img/af7fe02-create_subscription_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Create subscription** qui s'ouvre, saisissez l'identifiant de l'abonnement dans le champ **Product ID** et le nom de l'abonnement dans le champ **Name**. Le Product ID doit être unique, commencer par un chiffre ou une lettre minuscule, et peut également contenir des underscores (\_) et des points (.). Il sert à accéder à votre produit pendant le développement et à le synchroniser avec Adapty. Une fois qu'un Product ID est attribué à un produit dans la Google Play Console, il ne peut pas être réutilisé pour d'autres applications, même si le produit est supprimé. Pour nommer votre Product ID, il est conseillé de suivre un format standardisé. Nous recommandons une approche plus concise en nommant le produit `<nom de l'abonnement>.<niveau d'accès>`. Vous pouvez ensuite contrôler la durée et la fréquence de facturation via des plans de base, par exemple hebdomadaire, mensuel, etc. Le Name est uniquement à titre indicatif ; il sera visible sur votre fiche Google Play Store, vous pouvez donc utiliser n'importe quel nom descriptif. Il est limité à 55 caractères. 4. Cliquez sur le bouton **Create** pour confirmer la création de l'abonnement. :::note Produits d'abonnement Google Play dans Adapty Les produits Adapty correspondent aux plans de base des abonnements Google Play, car ce sont les produits que les clients peuvent acheter. Adapty gère automatiquement la migration des abonnements Google Play existants avec leurs plans de base correspondants, sans aucune action de votre part. Cependant, lorsque vous ajoutez un nouveau produit dans Adapty, vous devrez fournir à la fois l'ID du plan de base et l'ID du produit. ::: ### Créer un plan de base \{#create-a-base-plan\} Pour les produits d'abonnement, vous devez ajouter un plan de base. Les plans de base définissent la période de facturation, le prix et le type de renouvellement que les clients choisissent pour votre abonnement. Notez que les clients n'achètent pas directement un produit d'abonnement — ils achètent toujours un plan de base au sein d'un abonnement. Pour créer un plan de base : 1. Ouvrez la section [**Monetize** -> **Subscriptions**](https://console.cloud.google.com/iam-admin/serviceaccounts) dans le menu de gauche de la Google Play Console. Repérez ensuite l'abonnement auquel vous souhaitez ajouter un plan de base. 2. Cliquez sur le bouton **View subscription** à côté de l'abonnement. <img src="/assets/shared/img/4072a2a-subscriptions_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Une fois les détails de l'abonnement affichés, cliquez sur le bouton **Add base plan** sous le titre **Base plans and offers**. Vous devrez peut-être faire défiler la page vers le bas pour le trouver. <img src="/assets/shared/img/b493b60-add_base_plan.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la fenêtre **Add base plan** qui s'ouvre, saisissez un identifiant unique pour le plan de base dans le champ **Plan ID**. Il doit commencer par un chiffre ou une lettre minuscule, et peut contenir des chiffres (0-9), des lettres minuscules (a-z) et des tirets (-), puis remplissez les champs obligatoires. <img src="/assets/shared/img/8146763-CleanShot_2023-07-20_at_16.51.412x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Indiquez les prix par région. <img src="/assets/shared/img/8b26e1d-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Cliquez sur le bouton **Save** pour finaliser la configuration. 7. Cliquez sur le bouton **Activate** pour activer le plan de base. Gardez à l'esprit que dans Adapty, les produits d'abonnement ne peuvent avoir qu'un seul plan de base avec une durée et un type de renouvellement cohérents. ### Produits de secours \{#fallback-products\} :::warning Prise en charge des plans de base non rétrocompatibles Les versions plus anciennes des SDK Adapty ne prennent pas en charge les fonctionnalités de Google Billing Library v5+, notamment les plans de base multiples par produit d'abonnement et les offres. Seuls les plans de base marqués comme **[rétrocompatibles](https://support.google.com/googleplay/android-developer/answer/12124625?hl=en#backwards_compatible)** dans la Google Play Console sont accessibles avec ces versions du SDK. Notez qu'un seul plan de base par abonnement peut être marqué comme rétrocompatible. ::: <img src="/assets/shared/img/b5e70cb-CleanShot_2023-07-20_at_17.03.252x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Pour exploiter pleinement les configurations et fonctionnalités d'abonnement Google améliorées dans Adapty, nous offrons la possibilité de configurer un produit de secours rétrocompatible. Ce produit de secours est utilisé exclusivement pour les applications utilisant des versions plus anciennes du SDK Adapty. Lors de la création de produits Google Play, vous pouvez désormais indiquer si le produit doit être marqué comme rétrocompatible dans la Play Console. Adapty utilise cette information pour déterminer si le produit peut être acheté par des versions plus anciennes du SDK (versions 2.5 et inférieures). Supposons que vous ayez un abonnement nommé `subscription.premium` proposant deux plans de base : hebdomadaire (rétrocompatible) et mensuel. Si vous ajoutez le produit `subscription.premium:weekly` dans Adapty, vous n'avez pas besoin d'indiquer un produit rétrocompatible. En revanche, pour le produit `subscription.premium:monthly`, vous devrez en spécifier un. Ne pas le faire pourrait entraîner un achat involontaire du produit `subscription.premium:weekly` dans la bibliothèque de facturation Google v4. Pour résoudre ce problème, vous devez créer un produit distinct dont le plan de base est également mensuel et marqué comme rétrocompatible. Cela garantit que les utilisateurs qui choisissent l'option `subscription.premium:monthly` seront facturés correctement à la fréquence prévue. ## Ajouter des produits dans Adapty \{#add-products-to-adapty\} Une fois que vous avez terminé d'ajouter vos achats intégrés, abonnements et offres dans l'App Store Connect, l'étape suivante consiste à [ajouter ces produits dans Adapty](create-product). --- # File: google-play-data-safety --- --- title: "Google Play Data Safety" description: "Assurez la conformité avec les politiques de confidentialité des données Google Play dans Adapty." --- La section Data Safety disponible sur Google Play offre aux développeurs d'applications une méthode simple pour informer les utilisateurs sur les données collectées ou partagées par leur application, ainsi que pour mettre en avant les mesures essentielles de confidentialité et de sécurité. Ces informations permettent aux utilisateurs de faire des choix plus éclairés au moment de sélectionner les applications à télécharger et à utiliser. Voici un guide succinct sur les données collectées par Adapty pour vous aider à fournir les informations requises à Google Play. ## Collecte et sécurité des données \{#data-collection-and-security\} <img src="/assets/shared/img/3508c24-image4.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Votre application collecte-t-elle ou partage-t-elle l'un des types de données utilisateur requis ?** Sélectionnez « Oui », car Adapty collecte l'historique d'achats des clients. **Toutes les données utilisateur collectées par votre application sont-elles chiffrées en transit ?** Sélectionnez « Oui », car Adapty chiffre les données en transit. **Proposez-vous aux utilisateurs un moyen de demander la suppression de leurs données ?** Si vous sélectionnez « Oui », assurez-vous que vos clients ont un moyen de contacter votre équipe d'assistance pour demander la suppression de leurs données. Vous pourrez supprimer le client directement depuis le tableau de bord Adapty ou via l'API REST. ## Types de données \{#data-types\} Voici la liste des types de données que Google exige pour la déclaration. Nous avons précisé si Adapty collecte chaque type de données concerné. | Type de données | Détails | | :------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Localisation | Non collectée par Adapty | | Santé et Forme physique | Non collectée par Adapty | | Photos et Vidéos | Non collectée par Adapty | | Fichiers et Documents | Non collectée par Adapty | | Calendrier | Non collectée par Adapty | | Contacts | Non collectée par Adapty | | Contenu utilisateur | Non collectée par Adapty | | Historique de navigation | Non collectée par Adapty | | Historique de recherche | Non collectée par Adapty | | Informations et performances de l'app | Non collectée par Adapty | | Navigation web | Non collectée par Adapty | | Coordonnées | Non collectée par Adapty | | Informations financières | Adapty collecte l'historique d'achats des utilisateurs | | Informations personnelles et identifiants | Adapty collecte l'identifiant utilisateur et d'autres informations d'identification, notamment le nom, l'adresse e-mail, le numéro de téléphone, etc., si vous les transmettez explicitement au SDK Adapty. | | Identifiants d'appareil et autres | Adapty collecte des données sur l'identifiant d'appareil. | ## Utilisation et traitement des données \{#data-usage-and-handling\} ### Identifiants utilisateur \{#user-ids\} **1. Ces données sont-elles collectées, partagées, ou les deux ?** Ces données sont collectées par Adapty. Si vous utilisez des intégrations entre Adapty et des tiers qui ne sont pas considérés comme des prestataires de services, vous devrez peut-être également déclarer « Partagées » ici. **2. Ces données sont-elles traitées de manière éphémère ?** Sélectionnez « Non ». **3. Ces données sont-elles obligatoires pour votre application, ou les utilisateurs peuvent-ils choisir de ne pas les partager ?** La collecte de ces données est obligatoire et ne peut pas être désactivée. <img src="/assets/shared/img/2c60161-image5.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **4. Pourquoi ces données utilisateur sont-elles collectées ? / Pourquoi ces données utilisateur sont-elles partagées ?** Cochez les cases « Fonctionnalité de l'application » et « Analytique ». <img src="/assets/shared/img/07a3c9e-image2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Informations financières \{#financial-info\} Si vous utilisez Adapty, vous devez déclarer que votre application collecte des informations sur l'« Historique des achats » dans la section Types de données de la Google Play Console. <img src="/assets/shared/img/1057870-image7.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Identifiants d'appareil ou autres \{#device-or-other-ids\} <img src="/assets/shared/img/d10f132-CleanShot_2023-03-01_at_17.55.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/ccb1a2a-image5.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étapes suivantes \{#next-steps\} Une fois vos sélections de confidentialité des données effectuées, Google affichera un aperçu de la section confidentialité de votre application. Si vous avez opté pour « Informations financières » et « Identifiants d'appareil ou autres » comme indiqué précédemment, vos informations de confidentialité devraient ressembler à l'exemple suivant. <img src="/assets/shared/img/e8d9b73-image3.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si vous êtes prêt à soumettre votre application à l'examen, consultez notre document [Liste de vérification avant lancement](release-checklist) pour obtenir des conseils supplémentaires sur la préparation de votre application à la soumission. --- # File: google-reduced-service-fee --- --- title: "Frais de service réduits Google" description: "Comprenez les frais de service réduits de Google, leur impact sur vos revenus et les analyses d'Adapty" --- :::link Pour le programme App Store correspondant, consultez [Programme pour les petites entreprises de l'App Store](app-store-small-business-program). ::: Le [programme de frais de service réduits](https://support.google.com/googleplay/android-developer/answer/112622?hl=en) de Google Play réduit la commission sur vos premiers 1 million USD de revenus annuels, la faisant passer de 30 % à **15 %**. Les revenus dépassant 1 million USD au cours de la même année civile sont facturés au taux standard de 30 %. :::note Depuis le 1er janvier 2022, Google applique 15 % sur tous les abonnements à renouvellement automatique, indépendamment de ce programme. Les frais de service réduits profitent principalement aux achats intégrés hors abonnement et aux applications payantes. ::: Les membres du programme doivent **modifier leurs paramètres Adapty** pour garantir des calculs de revenus corrects et une gestion appropriée des événements d'intégration. Cet article décrit : * [Comment configurer Adapty](#configure-adapty) si votre application est inscrite au programme de frais de service réduits * [Comment s'inscrire au programme](#enroll-in-the-program) si vous souhaitez réduire votre commission store ## Configurer Adapty \{#configure-adapty\} Adapty peut appliquer le taux de commission réduit à vos [analyses](analytics) et [événements d'intégration](analytics-integration). Pour activer cette option, indiquez votre statut de frais de service réduits pour chaque application. :::warning Configurez votre statut de frais de service réduits dans Adapty **dès votre inscription**. Les modifications tardives ne peuvent pas réécrire les événements webhook déjà envoyés ([détails](#retroactive-setting-changes)). ::: 1. Ouvrez [**App Settings** → **General**](https://app.adapty.io/account). 2. Repérez la section **Reduced Service Fee**. 3. Cliquez sur **Add period**. 4. Sélectionnez la date de début de l'adhésion. 5. Sélectionnez une date de fin, ou activez la case **At the current moment** pour prolonger ce statut indéfiniment. Si vos [revenus annuels dépassent 1 million USD](#exceeding-the-threshold), vous pouvez modifier la date de fin. 6. Cliquez sur **Apply**. Le statut d'adhésion s'applique uniquement **à la plage de dates que vous spécifiez**. Le programme se réinitialise à chaque année civile. * Cliquez sur **Add period** pour ajouter une nouvelle période d'adhésion. * Pour prolonger ce statut indéfiniment, activez la case **At the current moment**. Pour vérifier votre configuration, ouvrez le [graphique Revenue](revenue) et sélectionnez **Proceeds after store commission**. Confirmez que les revenus affichés reflètent bien le taux de commission réduit. ## S'inscrire au programme \{#enroll-in-the-program\} ### Conditions d'éligibilité \{#eligibility-requirements\} Google détermine l'éligibilité en fonction de vos **revenus annuels** sur l'ensemble des comptes de votre <InlineTooltip tooltip="Groupe de comptes">Un groupe de comptes de développeur dont les revenus sont comptabilisés ensemble. Vous devez désigner votre compte de développeur comme compte de développeur principal et y associer tous les comptes liés.</InlineTooltip>. Le taux de 15 % s'applique au premier 1 million USD de revenus annuels combinés. Tout revenu dépassant ce seuil est facturé à 30 %. ### Avant de vous inscrire \{#before-you-enroll\} Assurez-vous de : - Avoir un [profil de paiement](https://support.google.com/googleplay/android-developer/answer/10632485) configuré - Pouvoir répertorier tous vos comptes de développeur associés ### Inscription \{#enrollment\} 1. Rendez-vous sur la [Google Play Console](https://play.google.com/console/). 2. Créez un groupe de comptes et définissez votre compte de développeur comme compte de développeur principal. 3. Associez tous les comptes de développeur liés au groupe. 4. Acceptez les conditions du programme de frais de service réduits. Une fois ces étapes effectuées, Google vous inscrit automatiquement. Il n'y a pas de vérification manuelle ni d'e-mail de confirmation. Pour des instructions détaillées, consultez le [guide d'inscription](https://support.google.com/googleplay/android-developer/answer/10632485) de Google. ### Dépassement du seuil \{#exceeding-the-threshold\} Lorsque vos revenus annuels combinés dépassent 1 million USD, Google facture 30 % sur la part excédant le seuil pour le reste de cette année civile. :::important Si vos revenus annuels dépassent 1 million USD, **modifiez immédiatement la date de fin** dans vos paramètres Adapty. Sinon, Adapty continuera à calculer la commission au taux réduit. ::: Le programme se réinitialise à chaque année civile. Si vos revenus dépassent 1 million USD une année, le taux de 15 % s'applique automatiquement à nouveau à votre premier 1 million USD l'année suivante. Aucune nouvelle inscription n'est nécessaire. Consultez les [conditions officielles du programme](https://support.google.com/googleplay/android-developer/answer/112622?hl=en) pour plus de détails. ## Modifications rétroactives des paramètres \{#retroactive-setting-changes\} Lorsque vous modifiez votre statut de commission réduite dans Adapty avec une date d'effet rétroactive, le nouveau taux de commission apparaît dans les données d'Adapty selon des calendriers différents : | Où le taux apparaît | Ce qui se passe après la modification du taux | | --- | --- | | Tableau de bord Analytics (Revenue, Proceeds, MRR, ARR) | Adapty applique le nouveau taux sous 24 heures, lors du recalcul quotidien. | | Exports S3, GCS et BigQuery | Adapty applique le nouveau taux lors du prochain export planifié. | | Événements webhook déjà envoyés | Adapty ne peut pas modifier les événements webhook après leur envoi. Ils conservent l'ancien taux. | Si votre entrepôt de données stocke des revenus issus d'événements webhook, ces enregistrements conservent l'ancien taux de commission. Pour réconcilier vos données, récupérez la période concernée depuis le tableau de bord Analytics, ou générez un nouvel export vers S3, GCS ou BigQuery. --- # File: google-play-quota-increase --- --- title: "Demander une augmentation du quota de l'API Google Play Developer" description: "Demandez une augmentation du quota de l'API Google Play Developer si vous dépassez la limite par défaut lors d'imports historiques ou avec une large base d'abonnés." --- Adapty utilise l'[API Google Play Developer](https://developers.google.com/android-publisher) pour valider les achats et synchroniser les données d'abonnement. Le quota par défaut de cette API est de 3 000 requêtes par minute. Si votre application dépasse cette limite, Google vous envoie une notification par e-mail. Cela se produit fréquemment lors des [imports de données historiques](importing-historical-data-to-adapty) ou dans les applications avec un grand nombre d'abonnés actifs. Pour éviter toute interruption, demandez une augmentation de quota à Google avant d'effectuer un import important ou si vous avez reçu une notification de dépassement de quota. ## Avant de commencer \{#before-you-start\} Activez les [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn) si ce n'est pas encore fait. Les RTDN transmettent les mises à jour d'abonnement via des notifications push plutôt que par interrogation, ce qui réduit la consommation de l'API. Google peut rejeter les demandes d'augmentation de quota si les RTDN ne sont pas activées. ## Rassembler les informations nécessaires \{#gather-required-information\} Avant d'ouvrir le formulaire de demande, collectez les valeurs suivantes : - **Developer Account ID** : pour le trouver, dans la [Google Play Console](https://play.google.com/console/), accédez à **Settings > Developer account > Account details**. L'identifiant figure en haut de la page. - **Nom du package de l'application** : le nom de package de votre application Android (par exemple, `com.example.app`). Vous le trouverez dans la Google Play Console sur la page **Dashboard** de votre application. - **Numéro de projet Google Cloud** : pour le trouver, dans la [Google Cloud Console](https://console.cloud.google.com/), sélectionnez votre projet. Le numéro de projet se trouve sur la page **Dashboard**. ## Demander l'augmentation du quota \{#request-the-quota-increase\} 1. Ouvrez le [formulaire de demande d'augmentation du quota de l'API Google Play Developer](https://support.google.com/googleplay/android-developer/contact/apiqr). 2. Saisissez votre Developer Account ID, le nom du package de l'application et le numéro de projet Google Cloud. 3. Sélectionnez l'API et le compartiment de quota qui nécessite une augmentation. Si vous avez reçu un e-mail de Google concernant un dépassement de quota, il précise quel compartiment est concerné. 4. Dans le champ de justification, expliquez que vous utilisez un service tiers de gestion des abonnements qui nécessite un accès à l'API pour valider les achats et synchroniser les données d'abonnement. 5. Pour le quota demandé, indiquez la quantité dont vous avez besoin. Si vous n'êtes pas sûr du montant à demander, vérifiez votre utilisation actuelle dans la [Google Cloud Console](https://console.cloud.google.com/) sous **IAM & Admin > Quotas** (filtrez par « Google Play Android Developer API »), puis envoyez vos données d'utilisation et le nombre d'entrées historiques que vous prévoyez d'importer à [support@adapty.io](mailto:support@adapty.io) afin que nous puissions vous aider à déterminer le bon montant. 6. Soumettez le formulaire. Google traite généralement les demandes d'augmentation de quota en quelques jours ouvrables. --- # File: prepare-your-app-for-store-review --- --- title: "Préparer votre application pour la revue des stores" description: "Conseils pour faire approuver votre application sur l'App Store et le Google Play Store" --- Cet article décrit le processus que suivent les stores lors de l'examen des soumissions d'applications, et propose des conseils pour obtenir une approbation plus rapide. Il s'appuie sur les directives officielles de soumission : * [Directives de soumission App Store](https://developer.apple.com/app-store/review/guidelines/) * [Directives de soumission Google Play Store](https://play.google/developer-content-policy/) :::important Les deux stores suivent un processus de revue similaire. Lorsqu'une règle ne s'applique qu'à l'un d'eux, l'article le mentionne par son nom. ::: Les utilisateurs d'Adapty doivent porter une attention particulière aux problèmes de conformité liés aux [paywalls et aux achats intégrés](#iap-related-requirements). Ce sont parmi les raisons de rejet les plus fréquentes. ## Avant de commencer \{#before-you-begin\} Confirmez que votre application est prête pour la soumission. Adapty propose une [checklist de mise en production](release-checklist) pour préparer votre app à la publication. Le Google Play Store exige que les éditeurs qui publient pour la première fois [testent l'application](https://support.google.com/googleplay/android-developer/answer/14151465?hl=en) avant de la soumettre. Le test doit impliquer au moins 12 personnes et durer un minimum de 14 jours consécutifs. Cette exigence a été introduite en 2025 pour réduire le nombre d'applications défectueuses qui parviennent aux équipes de revue de Google. ## Vue d'ensemble du processus de revue \{#review-process-overview\} #### Étape 1 : Le filtrage automatisé \{#step-1-the-automated-screening\} L'App Store et le Google Play Store suivent tous deux un processus de revue en deux étapes. Immédiatement après la soumission, votre application passe par un scan automatisé qui peut prendre plusieurs heures. Les deux stores analysent votre application à la recherche de malwares, Google accordant une importance particulière à cette étape. Il recherche des indicateurs comportementaux d'activité malveillante, comme des contacts avec des serveurs suspects ou un accès injustifié aux données utilisateur. Si votre application est jugée potentiellement dangereuse, elle est signalée et transmise à un analyste en sécurité humain. La [documentation Google Play Protect](https://developers.google.com/android/play-protect/cloud-based-protections#machine-learning) contient une liste approximative des vérifications effectuées lors de cette étape. Les stores vérifient également la présence des métadonnées nécessaires, l'absence de dépendances dangereuses ou obsolètes, ainsi que l'intégrité de votre build. #### Étape 2 : La revue humaine \{#step-2-the-human-review\} Une fois que votre application a passé le filtrage automatisé, elle est examinée par un relecteur humain. Cette étape peut prendre jusqu'à plusieurs jours, selon la complexité de votre application et la file d'attente de revue en cours. Les applications qui traitent des données sensibles prennent plus longtemps à examiner. ## Exigences générales \{#general-requirements\} ### Stabilité \{#stability\} Les applications qui plantent pendant la revue sont rejetées. Les relecteurs peuvent intentionnellement simuler des conditions réseau instables, l'application doit donc être capable de les gérer correctement. ### Complétude \{#completeness\} Apple et Google imposent tous deux une exigence de *complétude* (« fonctionnalité minimale ») sur le contenu soumis aux stores. * Les espaces réservés, les écrans « bientôt disponible » et les fonctionnalités cassées entraînent des rejets pour les applications iOS. * Google est [plus flexible](https://support.google.com/googleplay/android-developer/answer/9898783?hl=en), notamment si votre application est en [Accès anticipé](https://knowledge.workspace.google.com/admin/users/access/turn-early-access-apps-on-or-off-for-users). * Les deux stores **rejettent les applications** qui ont peu ou pas de fonctionnalités. Cela inclut les applications qui affichent une seule image, un fichier PDF ou une page web. Le contenu manquant entre dans la même catégorie. * Si l'application ne fait pas ce que vous annoncez, elle sera rejetée. * Si vous configurez un achat intégré dans votre tableau de bord, mais ne l'incluez pas dans le build, l'application sera rejetée. ### Exactitude des métadonnées \{#metadata-accuracy\} Des informations trompeuses, inexactes ou incohérentes dans la description, les captures d'écran et autres métadonnées peuvent entraîner un rejet. N'utilisez pas votre fiche store pour promouvoir des fonctionnalités futures de l'application. Si l'application n'est pas destinée au grand public, le relecteur recherchera une documentation supplémentaire expliquant ses workflows. Incluez des instructions claires dans les métadonnées de l'application. ### Classification du contenu \{#content-rating\} Le contenu de votre application doit correspondre à la classification déclarée. ### Aspects légaux \{#legal-aspects\} * La politique de confidentialité de votre application doit être accessible depuis l'intérieur de l'application. Vous pouvez utiliser le [bouton lien](paywall-buttons#links) du Paywall Builder. * Exigez des utilisateurs qu'ils lisent et acceptent tout accord juridique **avant** qu'il entre en vigueur. * Signalez la présence de publicités dans votre application. Ne pas le faire peut entraîner un rejet. * Si votre application iOS inclut des achats intégrés, vous devez accepter le **Paid Apps Agreement** dans votre tableau de bord App Store Connect. ### Authentification \{#authentication\} Si une partie du contenu de votre application n'est accessible qu'après authentification, fournissez des identifiants d'accès valides au relecteur du store. L'impossibilité d'accéder à l'intégralité du contenu justifie un rejet. Si votre application permet aux utilisateurs de créer un compte, elle doit également leur permettre de le supprimer. Rediriger les utilisateurs vers un support par e-mail ou un site web ne satisfait pas cette exigence. ### Accès et confidentialité \{#access-and-privacy\} Les métadonnées de l'application doivent clairement indiquer la raison de chaque permission demandée. Les permissions les plus sensibles (par exemple, l'accès aux messages texte et aux journaux d'appels) peuvent nécessiter une démonstration vidéo. Le même principe s'applique aux données utilisateur sensibles : si vous les demandez, expliquez pourquoi. ## Exigences liées aux achats intégrés \{#iap-related-requirements\} Les violations de la politique commerciale font partie des raisons de rejet les plus fréquentes. Si les principales méthodes de monétisation de votre application sont les abonnements et les achats intégrés, elle fera l'objet d'un examen plus approfondi. ### Exigences relatives aux paywalls \{#paywall-requirements\} Les relecteurs d'applications attendent des paywalls simples et faciles à comprendre. Si vous êtes soupçonné de manipulation des utilisateurs, l'application est rejetée. Si plusieurs revues trouvent des preuves de pratiques trompeuses, votre compte peut être désactivé et votre application [suspendue](https://support.google.com/googleplay/android-developer/community-guide/287283557/app-suspended-for-repeated-rejections?hl=en). Google Play utilise un [système de pénalités](https://support.google.com/googleplay/android-developer/answer/9899234?hl=en) qui peut conduire à la suppression de toutes vos applications. Respectez les pratiques suivantes dans la conception de vos paywalls : - **Soyez transparent et direct.** Affichez le prix exact des produits, la fréquence de facturation, les avantages et les conditions d'annulation avant d'inviter l'utilisateur à acheter. Différenciez clairement les achats uniques et les produits nécessitant des paiements récurrents. Si un produit est accompagné d'un essai gratuit, indiquez clairement sa durée et ses conditions. N'utilisez pas un langage intentionnellement confus pour induire l'utilisateur en erreur. - **Soyez cohérent.** Les prix des produits doivent correspondre sur la fiche App Store, dans les écrans intégrés à l'application, les écrans de gestion des abonnements et le contenu marketing. Toute différence de prix, même minime, est un motif de rejet. Le Paywall Builder d'Adapty synchronise automatiquement les prix entre votre paywall et votre produit App Store Connect. Si votre paywall est codé manuellement, vous devez [récupérer le prix de chaque produit](fetch-paywalls-and-products) depuis son tableau de données. - **Affichez tous les niveaux de manière équitable.** Ne présélectionnez pas l'option la plus chère et ne cachez pas les moins chères. - **Évitez les « dark patterns ».** Ne créez pas de fausse urgence ou de rareté artificielle. Ne forcez pas les utilisateurs à effectuer des achats en rendant intentionnellement les fonctionnalités gratuites peu pratiques ou difficiles à trouver. ### Garantie d'accès \{#access-guarantee\} L'application doit garantir aux utilisateurs le droit d'accéder à leurs achats. * **Accès immédiat** Un achat réussi doit immédiatement débloquer l'accès au produit, sans délai visible. Les états intermédiaires d'autorisation de paiement ne doivent pas générer d'erreurs ni perturber l'expérience utilisateur. Un achat réussi doit immédiatement masquer le paywall. Si vous continuez à afficher le paywall après un achat, vous empêchez l'utilisateur d'accéder au contenu qu'il a payé. * **Restauration de l'accès** Un utilisateur doit pouvoir restaurer l'accès au produit depuis un nouvel appareil. Placez le bouton de restauration à un endroit visible. Si vous avez conçu votre paywall avec le [Flow Builder](adapty-flow-builder), le bouton de restauration déclenche automatiquement le processus de restauration. Si vous avez [implémenté un paywall manuellement](ios-implement-paywalls-manually), ajoutez du code qui appelle la méthode [restorePurchases](restore-purchase). Adapty restaurera le niveau d'accès de l'utilisateur, **sauf** si vous utilisez le SDK en [mode observateur](observer-vs-full-mode). L'application doit être capable de reconnaître les achats intégrés effectués depuis la page store du produit, ou ailleurs dans l'app store. ### Méthodes de paiement appropriées \{#appropriate-payment-methods\} Les deux stores interdisent la vente de biens physiques via les achats intégrés, et exigent la facturation en store pour la plupart des biens numériques. L'exigence de facturation en store ne s'applique pas dans certaines juridictions géographiques, notamment aux États-Unis et dans l'UE. Selon le pays, vous pourrez peut-être [contourner entièrement la facturation en store](https://support.google.com/googleplay/android-developer/answer/16497028), ou [présenter à l'utilisateur un choix](https://support.google.com/googleplay/android-developer/answer/13821247) entre la facturation via l'app store et une facturation alternative. Certaines catégories d'applications (comme les lecteurs de livres numériques ou les applications de rencontres) peuvent être éligibles à des méthodes de paiement alternatives même en dehors de ces régions. Consultez les directives officielles des stores pour plus de détails. :::tip Contrairement à [Google](https://support.google.com/googleplay/android-developer/answer/13821247), Apple ne propose pas de liste définitive des pays autorisant les méthodes de facturation alternatives. À mesure que de nouvelles juridictions adoptent des lois similaires, la disponibilité s'élargira. Lisez la documentation relative à votre pays en particulier avant de procéder. ::: Notez que les deux stores appliquent des directives pour les intégrations de fournisseurs de paiement, et continuent de prélever une commission sur les transactions effectuées via ces services. ## Gestion des rejets \{#handling-rejection\} Si votre application est rejetée, le relecteur indiquera quelle(s) directive(s) elle a violée. Lisez la directive en intégralité et corrigez le problème : * [Directives de soumission App Store](https://developer.apple.com/app-store/review/guidelines/) * [Directives de soumission Google Play Store](https://play.google/developer-content-policy/) Si vous estimez que le rejet est injustifié, vous avez le droit de le contester. Fournissez des preuves de conformité et contactez le store. * Ne mettez pas à jour l'application pendant son examen. * À chaque soumission, vous pouvez avoir un relecteur différent. Cela peut jouer en votre faveur ou contre vous. * Ne corrigez pas les problèmes un par un. Soumettez l'application à une nouvelle revue une fois que toutes les corrections sont en place. * Si Google Play a rejeté votre application pour des violations de politique, mettez à jour les données en question sur toutes les tracks, même celles en pause ou inactives. * Les revues suivantes prennent généralement moins de temps que la première. * Une revue accélérée peut être disponible pour les bugs critiques et les délais urgents — à utiliser avec parcimonie. ## Après la revue : surveillance continue \{#after-the-review-continuous-monitoring\} Les deux app stores continuent de surveiller votre application même après qu'elle a passé le processus de revue. Si la fonction de votre application change après approbation (par exemple, en raison d'un code chargé dynamiquement), elle sera signalée et dépubliée. Un afflux de retours négatifs des utilisateurs constitue également un motif d'examen supplémentaire. Entre 2024 et 2025, Google a [supprimé 47 % de ses applications du Play Store](https://techcrunch.com/2025/04/29/google-play-sees-47-decline-in-apps-since-start-of-last-year/) pour améliorer leur qualité moyenne. Abandonner votre application comporte également un risque. [Google](https://www.cnet.com/tech/mobile/google-play-store-will-hide-apps-that-havent-been-updated-in-years/) et [Apple](https://developer.apple.com/support/app-store-improvements/#:~:text=Developers%20of%20apps%20that%20have,launch%20will%20be%20removed%20immediately.) retirent tous deux des listes les applications qui ne reçoivent pas de mises à jour ou de téléchargements. ## Voir aussi \{#see-also\} * [Tests en sandbox](test-purchases-in-sandbox) * [Checklist de mise en production](release-checklist) --- # File: firebase-apps --- --- title: "Applications Firebase" description: "Intégrez Firebase avec Adapty pour améliorer l'analyse des utilisateurs et le suivi des abonnements pour votre application mobile." --- Cette page concerne l'intégration d'Adapty dans votre application si elle fonctionne sur Firebase. :::note Premiers pas Ce ne sont pas toutes les étapes nécessaires au fonctionnement d'Adapty, mais quelques conseils utiles pour l'intégration avec Firebase. Si vous souhaitez intégrer Adapty dans votre application, lisez d'abord le [Guide de démarrage rapide](quickstart). ::: ## Identification des utilisateurs \{#user-identification\} Si vous utilisez l'authentification Firebase, cet extrait de code peut vous aider à maintenir la synchronisation de vos utilisateurs entre Firebase et Adapty. Notez qu'il s'agit d'un simple exemple et que vous devez tenir compte des spécificités d'authentification de votre application. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS with Firebase" default> ```swift showLineNumbers @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Configure Adapty before Firebase Adapty.activate("YOUR_API_KEY") Adapty.delegate = self // Configure Firebase FirebaseApp.configure() // Add state change listener for Firebase Authentication Auth.auth().addStateDidChangeListener { (auth, user) in if let uid = user?.uid { // identify Adapty SDK with new Firebase user Adapty.identify(uid) { error in if let e = error { print("Sign in error: \(e.localizedDescription)") } else { print("User \(uid) signed in") } } } } return true } } extension AppDelegate: AdaptyDelegate { // MARK: - Adapty delegate func didReceiveUpdatedPurchaserInfo(_ purchaserInfo: PurchaserInfoModel) { // You can optionally post to the notification center whenever // purchaser info changes. // You can subscribe to this notification throughout your app // to refresh tableViews or change the UI based on the user's // subscription status NotificationCenter.default.post(name: NSNotification.Name(rawValue: "com.Adapty.PurchaserInfoUpdatedNotification"), object: purchaserInfo) } } ``` </TabItem> <TabItem value="kotlin" label="Android with Firebase" default> ```kotlin showLineNumbers class App : Application() { override fun onCreate() { super.onCreate() // Configure Adapty Adapty.activate(this, "YOUR_API_KEY") Adapty.setOnPurchaserInfoUpdatedListener(object : OnPurchaserInfoUpdatedListener { override fun onPurchaserInfoReceived(purchaserInfo: PurchaserInfoModel) { // handle any changes to subscription state } }) // Add state change listener for Firebase Authentication FirebaseAuth.getInstance().addAuthStateListener { auth -> val currentUserId = auth.currentUser?.uid if (currentUserId != null) { // identify Adapty SDK with new Firebase user Adapty.identify(currentUserId) { error -> if (error == null) { //success } } } else { Adapty.logout { } } } } } ``` </TabItem> </Tabs> --- # File: refund-saver --- --- title: "Refund Saver" description: "Utilisez Adapty Refund Saver pour minimiser les remboursements et maximiser vos revenus." --- Lorsqu'un utilisateur demande un remboursement, Apple mène une enquête. Pour décider **si le remboursement est justifié**, il demande au développeur des informations sur l'activité de cet utilisateur. Sans ces preuves, même un abonnement fortement utilisé sera probablement remboursé. Le **Refund Saver** répond automatiquement aux [demandes de consommation](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information-v1) d'Apple, protégeant vos revenus et **augmentant les chances de refus** des demandes injustifiées. Il fonctionne pour tous les types d'achats intégrés Apple — abonnements auto-renouvelables, abonnements uniques, consommables et non-consommables (y compris les produits à accès à vie). :::tip **Fidélisez vos abonnés avant qu'ils ne se désabonnent.** [Retention Messaging](retention-messaging) affiche un message personnalisé dans l'écran Annuler l'abonnement d'Apple — une raison de rester, juste au moment où l'abonné appuie sur Annuler. ::: ## Fonctionnement du Refund Saver \{#how-refund-saver-works\} 1. Lorsqu'un utilisateur initie une demande de remboursement, l'App Store envoie une notification demandant des détails sur la transaction et l'utilisation. Si vous **ignorez** ou **retardez** la réponse, Apple est susceptible d'**approuver le remboursement**. 2. Le Refund Saver d'Adapty traite automatiquement ces notifications en fournissant à Apple les données nécessaires. Cette automatisation réduit les risques de remboursements injustifiés, tout en vous faisant gagner du temps et en protégeant vos revenus. 3. Adapty enregistre chaque résultat — remboursé ou refusé. Ces données alimentent l'analytique du Refund Saver dans le Dashboard. :::info Avec Refund Saver, vous pouvez économiser jusqu'à 40 % des revenus issus des demandes de remboursement. ::: ## Conditions d'utilisation de Refund Saver \{#requirements-to-use-refund-saver\} Pour utiliser cette fonctionnalité, assurez-vous de remplir les conditions préalables suivantes : 1. **Mettez à jour votre politique de confidentialité dans App Store Connect :** La politique de confidentialité de votre application doit mentionner la collecte et l'utilisation des données de consommation. Cela permet aux utilisateurs de comprendre les pratiques de confidentialité de votre app avant de la télécharger. Consultez les [App Privacy Details d'Apple](https://developer.apple.com/app-store/app-privacy-details/) pour plus d'informations. 2. **Obtenez le consentement de l'utilisateur pour le partage de données dans votre application** : Apple exige que vous obteniez un consentement valide de l'utilisateur avant de partager ses données personnelles avec Apple. En tant que développeur, il vous incombe d'obtenir ce consentement puisque vous serez amené à partager des données utilisateur avec Apple. Consultez les [directives](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information) d'Apple pour plus de détails. 3. **Activez les notifications serveur V2 :** Assurez-vous que les notifications serveur V2 sont activées dans votre compte Apple Developer et correctement configurées dans Adapty, car les notifications V1 ne sont pas prises en charge. Si elles ne sont pas encore activées, suivez les étapes du guide [Activer les notifications serveur App Store](enable-app-store-server-notifications). ## Activer Refund Saver \{#turn-on-refund-saver\} 1. Ouvrez la section [Refund Saver](https://app.adapty.io/refund-saver) dans l'Adapty Dashboard. 2. Cliquez sur **Turn on Refund Saver** pour activer la fonctionnalité. ## Définir un comportement de remboursement par défaut \{#set-a-default-refund-behavior\} Apple permet aux développeurs de spécifier un résultat préférentiel pour chaque demande de remboursement lors de sa réponse. L'objectif de ce paramètre est de trouver le bon équilibre entre le refus et l'acceptation des demandes de remboursement, afin que seuls les remboursements légitimes soient accordés. Notez que ce paramètre sert uniquement à influencer le résultat, mais la décision finale reste celle d'Apple. Adapty prend en charge la définition de cette préférence, mais la même valeur sera appliquée à toutes les demandes de remboursement. 1. Pour modifier votre préférence, cliquez sur **Edit refund preference**. 2. Dans la fenêtre **Edit refund preference**, choisissez votre option **Default refund request preference** : | Option | Description | | -------------------------------------------- | ------------------------------------------------------------ | | Always decline | (par défaut) Il s'agit de l'option par défaut, qui donne généralement les meilleurs résultats pour minimiser les remboursements. | | Decline first refund request, grant all next | Pour chaque transaction rencontrée par Refund Saver, il demandera d'abord à Apple de refuser le remboursement. Cependant, si la même transaction réapparaît, Refund Saver recommandera toujours d'accorder le remboursement. Cette approche permet de limiter la frustration des utilisateurs face à des refus injustifiés — ils peuvent simplement faire une nouvelle demande et l'obtenir. | | Always refund | Suggère à Apple d'approuver chaque demande de remboursement. | | No preference | N'envoie aucune recommandation à Apple. Dans ce cas, Apple déterminera l'issue du remboursement en fonction de ses politiques internes et de l'historique de l'utilisateur, sans aucune influence de vos paramètres. Cette option offre l'approche la plus neutre. | ## Définir le comportement de remboursement pour un utilisateur spécifique dans le tableau de bord \{#set-refund-behavior-for-a-specific-user-in-the-dashboard\} Même si vous avez configuré le comportement par défaut de Refund Saver pour l'ensemble de l'application, vous pouvez définir des préférences individuelles pour des utilisateurs spécifiques. Dans l'Adapty Dashboard, vous pouvez le faire depuis le profil de l'utilisateur. Utilisez la section **Refund Saver Preferences** située en bas à gauche. :::note Les préférences par utilisateur remplacent le comportement par défaut au niveau de l'application — y compris le comportement « Refuser la première demande de remboursement, accorder toutes les suivantes ». ::: ## Définir le comportement de remboursement pour un utilisateur spécifique dans le SDK \{#set-refund-behavior-for-a-specific-user-in-the-sdk\} Vous pouvez définir la préférence de remboursement dans le code de votre application individuellement pour chaque installation en fonction des actions d'un utilisateur. Utilisez l'extrait ci-dessous pour définir la préférence : <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (3.4.1+)" default> ```swift showLineNumbers code do { try await Adapty.updateRefundPreference(<PREFERENCE_VALUE>) // possible values: .noPreference, .grant, .decline } catch { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter (3.4.0+)" default> ```javascript showLineNumbers code try { // possible values: AdaptyRefundPreference.noPreference, AdaptyRefundPreference.grant, AdaptyRefundPreference.decline await Adapty().updateRefundPreference(<PREFERENCE_VALUE>); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (3.4.0+)" default> ```typescript showLineNumbers try { await adapty.updateRefundPreference(<PREFERENCE_VALUE>); // possible values: RefundPreference.NoPreference, RefundPreference.Grant, RefundPreference.Decline } catch (error) { // handle the `AdaptyError` } ``` </TabItem> <TabItem value="unity" label="Unity (3.3.0+)" default> ```csharp showLineNumbers Adapty.UpdateAppStoreRefundPreference(<PREFERENCE_VALUE>, (error) => { if (error != null) { // handle the error return; } }); ``` </TabItem> </Tabs> :::note Vous pouvez également utiliser l'API côté serveur pour [définir une préférence de remboursement individuelle](api-adapty/operations/setRefundSaverSettings) : - Utilisez le SDK lorsque la configuration de la préférence est directement liée aux interactions client, par exemple lorsque les utilisateurs cliquent sur un bouton pour configurer leur préférence. - Utilisez l'API lorsque vous avez besoin d'effectuer un traitement côté serveur ou lorsque cela correspond mieux à l'architecture de votre application. ::: ## Obtenir le consentement de l'utilisateur \{#obtain-user-consent\} La manière dont vous recueillez le consentement de l'utilisateur pour le partage de données vous appartient, mais Apple exige un consentement valide avant tout partage de données personnelles. Apple recommande d'adopter une **approche opt-in**, qui consiste à afficher des invites dans l'application expliquant comment les données seront utilisées et demandant une action explicite de l'utilisateur pour donner son accord. Si un utilisateur ignore ou refuse l'invite, il n'est pas considéré comme ayant consenti. Pour plus de détails, consultez les [directives](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information) d'Apple. Si le consentement explicite n'est pas pratique pour votre application, vous pouvez envisager une **approche par opt-out**. Celle-ci consiste à inclure une clause de partage des données dans vos Conditions Générales d'Utilisation, indiquant que les utilisateurs acceptent le partage des données en acceptant les conditions. Veillez à expliquer clairement comment les utilisateurs peuvent révoquer leur consentement. Voici un exemple de clause pour l'approche par opt-out, incluant les types de données que vous pourriez partager. Il ne s'agit que d'un exemple destiné à vous guider dans la rédaction de votre propre texte. Il vous appartient de vous assurer que votre version finale est conforme à toutes les lois applicables et aux exigences d'Apple. *"Si nous recevons une demande de remboursement pour un achat intégré, nous pouvons fournir à Apple des informations sur l'activité d'achats intégrés de l'utilisateur. Cela peut inclure des informations telles que le temps écoulé depuis l'installation de l'application, la durée totale d'utilisation de l'application, un identifiant de compte anonyme, si l'achat intégré a été entièrement consommé, s'il incluait une période d'essai, le montant total dépensé et le montant total remboursé."* Selon l'approche choisie, définissez l'option **Default consent policy** dans le menu **Edit refund preferences** : <p> </p> | Option | Description | | ------- | ------------------------------------------------------------ | | Opt-out | (par défaut) Si Adapty ne connaît pas le statut de consentement de l'utilisateur, il suppose que le consentement **a été donné** et Refund Saver **partagera** les données liées aux remboursements avec Apple. | | Opt-in | Si Adapty ne connaît pas le statut de consentement de l'utilisateur, il suppose que le consentement **n'a pas été donné** et Refund Saver **ne partagera aucune** donnée avec Apple. C'est l'approche recommandée par Apple. | ## Mettre à jour le consentement de l'utilisateur dans le SDK \{#update-user-consent-in-the-sdk\} Pour indiquer à Adapty si un utilisateur donné a accordé son consentement, utilisez la méthode `updateCollectingRefundDataConsent`. La valeur est persistée côté serveur par profil, vous n'avez donc besoin de l'appeler que lorsque le consentement change. <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (3.4.1+)" default> ```swift showLineNumbers do { try await Adapty.updateCollectingRefundDataConsent(<CONSENT_VALUE>) // true = consent is explicitly provided, false = consent is explicitly revoked } catch { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter (3.4.0+)" default> ```dart showLineNumbers try { // true = user gave consent, false = user revoked consent await Adapty().updateCollectingRefundDataConsent(<CONSENT_VALUE>); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (3.4.0+)" default> ```typescript showLineNumbers try { await adapty.updateCollectingRefundDataConsent(<CONSENT_VALUE>); // true = consent is explicitly provided, false = consent is explicitly revoked } catch (error) { // handle the `AdaptyError` } ``` </TabItem> <TabItem value="unity" label="Unity (3.3.0+)" default> ```csharp showLineNumbers Adapty.UpdateAppStoreCollectingRefundDataConsent(<CONSENT_VALUE>, (error) => { if (error != null) { // handle the error return; } }); ``` </TabItem> </Tabs> :::note Vous pouvez également utiliser l'API côté serveur pour [définir une préférence de partage de données individuelle](api-adapty/operations/setRefundSaverSettings) : - Utilisez le SDK lorsque la configuration de la préférence est directement liée aux interactions client, par exemple lorsque les utilisateurs cliquent sur un bouton pour configurer leur préférence. - Utilisez l'API lorsque vous avez besoin d'effectuer un traitement côté serveur ou lorsque cela correspond mieux à l'architecture de votre application. ::: ## Vérifier le consentement de l'utilisateur \{#check-user-consent\} Vous pouvez vérifier le statut de consentement actuel d'un utilisateur à tout moment. Dans Adapty Dashboard, ouvrez simplement le profil de l'utilisateur et cherchez le paramètre **Allow data sharing** dans la section **Refund Saver Preferences** en bas à gauche. :::note Vous pouvez également utiliser l'API côté serveur pour [obtenir les préférences individuelles de remboursement et de partage](api-adapty/operations/getRefundSaverSettings). ::: ## Limitations \{#limitations\} - **App Store d'Apple uniquement :** Refund Saver est uniquement disponible pour les demandes de remboursement effectuées auprès de l'App Store d'Apple. Google Play ne propose pas d'analyse des données de consommation pour les remboursements. Les décisions de remboursement sur Google Play sont basées uniquement sur les politiques de Google et les informations fournies par l'utilisateur. - **Nécessite les notifications serveur V2 :** Refund Saver n'est pas compatible avec les notifications serveur App Store V1. Si vous utilisez actuellement V1 dans Adapty, vous devez passer à V2 — consultez le guide [Envoyer les notifications serveur App Store à Adapty](enable-app-store-server-notifications) pour plus de détails. Passer à V2 améliorera également vos analyses dans Adapty en fournissant des données plus précises et complètes. --- # File: meta-create-campaign --- --- title: "Faire de la publicité pour votre application dans Meta Ads" --- Dans ce guide étape par étape, vous apprendrez à créer et configurer des publicités pour votre application dans Meta, afin de les optimiser et de suivre facilement leurs performances. ## Comment les publicités Meta sont structurées \{#how-ads-in-meta-are-structured\} Pour faire de la publicité sur Meta Ads, vous devez configurer trois niveaux hiérarchiques : - **Campaign** : les campagnes définissent vos objectifs publicitaires. - **Ad set** : les ensembles de publicités précisent votre audience cible et les placements — en déterminant où et à qui vos publicités seront diffusées. Chaque campagne peut contenir plusieurs ensembles de publicités. - **Ads** : les publicités sont les créations que les utilisateurs voient et avec lesquelles ils interagissent. Chaque ensemble de publicités peut contenir plusieurs publicités ; il est cependant recommandé de ne pas dépasser cinq publicités par ensemble pour des performances optimales. ## Étape 1. Créer un compte Meta Ads Manager \{#step-1-create-meta-ads-manager-account\} Pour démarrer avec Meta Ads, vous devez avoir une page professionnelle Facebook, car vous ne pouvez pas diffuser de publicités depuis votre profil personnel. Vous devez donc associer votre page professionnelle à votre portefeuille d'entreprise Meta Ads : 1. Rendez-vous sur [business.facebook.com](https://business.facebook.com/). Si vous n'avez pas encore de page professionnelle dans votre portefeuille d'entreprise, vous devez en ajouter une. Cliquez sur **Go to settings**. 2. Dans la barre latérale gauche, allez dans **Account > Pages**. Cliquez sur **Add** et sélectionnez **Add an existing Facebook page** ou **Create a new Facebook page**. Consultez le [guide sur la création d'une page professionnelle](https://www.facebook.com/business/help/473994396650734) si vous n'en avez pas encore. 3. Vous pouvez également associer votre compte Instagram via la page **Account > Instagram accounts** dans les paramètres. Une fois votre page professionnelle connectée, vous pouvez passer à la suite. ## Étape 2. Ajouter le pixel Meta \{#step-2-add-meta-pixel\} Vous aurez besoin d'un pixel Meta pour relier les données de votre campagne aux revenus et obtenir de meilleurs résultats. Avant de connecter des données et de créer un pixel, vous aurez besoin de : - Une page professionnelle — ajoutez-la à votre portefeuille d'entreprise dans [**Settings > Accounts > Pages**](https://business.facebook.com/latest/settings/pages) - Un compte Business Manager — vous devez avoir un contrôle total sur le portefeuille d'entreprise - Un e-mail professionnel — à définir dans [**Settings > Business info**](https://business.facebook.com/latest/settings/business_info) - Un compte publicitaire — ajoutez-le à votre portefeuille d'entreprise dans [**Settings > Accounts > Ad accounts**](https://business.facebook.com/latest/settings/ad_accounts) Lorsque vous êtes prêt(e), créez un pixel : 1. Rendez-vous dans [**Events Manager**](https://www.facebook.com/events_manager2). Cliquez sur **Connect data**. 2. Sélectionnez **Web** comme type de source de données. 3. Donnez un nom à votre jeu de données et cliquez sur **Create**. 4. Pour [l'attribution Adapty](adapty-user-acquisition), vous n'aurez pas besoin de terminer l'installation complète du pixel. Ainsi, lorsqu'on vous demande de choisir une intégration, vous pouvez simplement cliquer sur **x** dans la fenêtre de configuration — votre pixel apparaîtra quand même dans la liste après avoir actualisé la page. 5. Lorsque votre jeu de données apparaît dans la liste, vous pouvez passer à la création d'une campagne. ## Étape 3. Créer une campagne \{#step-3-create-campaign\} Pour créer une campagne dans Meta Ads Manager : 1. Rendez-vous dans [Meta Ads Manager](https://adsmanager.facebook.com/adsmanager/manage). Dans l'onglet **Campaign**, cliquez sur **Create**. 2. Sélectionnez **Sales** comme objectif de campagne et cliquez sur **Continue**. 3. Nommez votre campagne dans la section **Campaign name**. 4. Dans la section **Budget**, sous **Budget strategy**, choisissez comment vous souhaitez gérer votre budget : - **Campaign budget** : l'option la plus simple si vous n'êtes pas sûr(e) de ce qui fonctionnera le mieux. En la sélectionnant, Meta Ads détecte automatiquement les meilleures performances pour allouer davantage de budget aux ensembles de publicités les plus efficaces. Ensuite, choisissez entre un budget **Daily** ou **Lifetime** et saisissez la limite dans votre devise. Le budget **Daily** vous offre plus de flexibilité lorsque vous débutez : vous pouvez commencer avec de petits montants et les ajuster progressivement. Vous pouvez aussi sélectionner **Schedule budget increase** et définir des règles pour augmenter automatiquement le budget d'un montant fixe ou d'un pourcentage. - **Ad set budget** : sélectionnez cette option si vous souhaitez définir manuellement quelles audiences recevront plus ou moins de budget. Si vous n'êtes pas totalement certain(e), vous pouvez sélectionner **Share some of your budget with other ad sets** pour permettre à Meta d'ajuster automatiquement les budgets des ensembles de publicités jusqu'à 20 % si cela améliore les performances. 5. Dans **Campaign bid strategy**, sélectionnez l'option la mieux adaptée à vos objectifs : - **Highest volume (default)** : l'option la plus simple pour commencer. En la sélectionnant, vous laissez Meta optimiser le coût par clic pour obtenir les meilleurs résultats avec votre budget. - **Cost per result goal** : visez un coût par résultat précis si vous connaissez vos références. - **Bid cap** : définissez le coût maximum que vous êtes prêt(e) à enchérir. 6. Adapty vous permet de réaliser des [tests A/B](ab-tests) complets. Vous pouvez également activer des tests A/B dans Meta Ads si nécessaire. Apprenez-en plus sur les tests A/B dans Meta Ads Manager [ici](https://www.facebook.com/business/help/1159714227408868). 7. Il est maintenant temps d'ajouter le premier ensemble de publicités à votre campagne. Cliquez sur **Next** pour continuer. ## Étape 4. Créer un ensemble de publicités \{#step-4-create-ad-set\} Pour créer un ensemble de publicités : 1. Donnez un nom à votre ensemble de publicités dans le champ **Ad set name**. 2. Dans le menu déroulant **Conversion location**, sélectionnez **Website**. 3. Dans le champ **Performance goal**, sélectionnez **Maximize number of landing page views** si vous avez une page de destination, ou **Maximize number of link clicks** si vous utilisez un lien intelligent redirigeant les utilisateurs directement vers le store. 4. Dans le champ **Dataset**, sélectionnez le jeu de données créé à l'[Étape 2](#step-2-add-meta-pixel). 5. Sélectionnez un **Conversion event**. Dans notre cas, il s'agira probablement de **Purchase** ou **Start trial**. Ne vous inquiétez pas si vous voyez un avertissement indiquant que votre jeu de données ne contient pas encore d'événements — cela signifie simplement que votre jeu de données est nouveau. 6. Si, lors de la configuration de la campagne, vous avez sélectionné **Ad set budget**, choisissez entre un budget **Daily** ou **Lifetime** et saisissez la limite dans votre devise. Le budget **Daily** vous offre plus de flexibilité lorsque vous débutez : vous pouvez commencer avec de petits montants et les ajuster progressivement. Définissez les dates de début et, le cas échéant, de fin de l'ensemble de publicités. Par exemple, si vous souhaitez promouvoir une offre promotionnelle dans votre application, il est essentiel d'aligner la durée de l'ensemble de publicités avec celle de l'offre. 7. Dans la section **Audience controls**, configurez les paramètres d'audience : - **Location** : les zones géographiques peuvent être aussi larges ou précises que nécessaire. Vous pouvez restreindre les **Locations** dans l'ensemble de publicités pour adapter vos publicités aux spécificités régionales. - **Minimum age** : sélectionnez l'âge minimum des utilisateurs qui verront votre publicité. Certaines publicités peuvent l'exiger légalement. Vous ne pouvez pas définir un âge minimum inférieur à 18 ans au niveau mondial, ni à 20 ans en Thaïlande. - **Language** : renseignez le champ **Language** uniquement si la langue visée n'est pas la langue la plus courante dans les pays sélectionnés. Par exemple, vous n'aurez pas besoin de sélectionner **French** en France, mais si vous ciblez des personnes francophones vivant dans un autre pays, vous pourriez vouloir le préciser. 8. Par défaut, Meta identifie automatiquement des sous-groupes de personnes susceptibles d'être réceptives à votre publicité. Cependant, en ajoutant une suggestion d'audience, vous pouvez orienter Meta vers le type de personnes qui, selon vous, sont le plus susceptibles de répondre. Dans la section **Advantage+ audience**, vous pouvez ajuster : - **Age** : définissez une tranche d'âge spécifique pour mieux correspondre aux caractéristiques de différents groupes. - **Gender** : diffusez votre publicité à tous les utilisateurs ou ciblez-les par genre. - **Detailed targeting** : ce paramètre vous offre le contrôle le plus précis sur l'audience de votre publicité et/ou application. Vous pouvez y former des groupes selon les **Demographics**, les **Interests** ou les **Behaviors**. Selon ce que fait votre application, vous pouvez par exemple cibler des professions spécifiques, des fans de groupes de musique particuliers, des parents de nouveau-nés ou des personnes qui achètent beaucoup en ligne. :::note Les paramètres **Detailed targeting** s'appliquent avec l'opérateur **Or**. Si vous souhaitez appliquer des conditions avec l'opérateur **And**, cliquez sur **Define further** et sélectionnez de nouvelles conditions. ::: 9. Dans la section **Placements**, vous pouvez choisir où votre publicité apparaîtra. Par défaut, le paramètre **Advantage+** est sélectionné, laissant Meta répartir le budget de votre ensemble de publicités sur plusieurs placements en fonction des meilleures performances attendues. Nous vous recommandons d'utiliser cette option si vous ne savez pas encore où placer votre publicité. Si vous souhaitez sélectionner des placements spécifiques manuellement, choisissez **Manual placements** et personnalisez-les. En savoir plus [ici](https://www.facebook.com/business/help/965529646866485). 10. **Recommandé** : le ciblage par appareil vous aide à optimiser vos dépenses. Dans la section **Placements**, cliquez sur **Show more settings**. Dans la sous-section **Devices and operating system**, sélectionnez les appareils, systèmes d'exploitation et versions d'OS à inclure dans votre audience. Cela garantit que vos publicités ne sont diffusées qu'aux utilisateurs pertinents. Par exemple, les utilisateurs sur ordinateur ne verront pas votre publicité, et les utilisateurs avec des versions d'OS trop anciennes que votre application ne prend pas en charge seront exclus. 11. Lorsque vous êtes prêt(e), cliquez sur **Next** pour continuer. ## Étape 5. Créer des publicités \{#step-5-create-ads\} Pour créer une publicité dans Meta Ads Manager : 1. Donnez un nom à votre publicité dans le champ **Ad name**. 2. Dans la section **Identity**, sélectionnez la page Facebook qui sera utilisée pour publier les publicités. Si vous avez un compte Instagram dédié à votre application et que vous l'avez connecté dans Meta Business Suite à l'[Étape 1](#step-1-create-meta-ads-manager-account), sélectionnez-le dans le menu déroulant **Instagram account**. Sinon, sélectionnez **Use Facebook page** pour que les publicités Instagram soient publiées via la page Facebook. 3. Dans **Ad setup**, choisissez comment vous souhaitez publier votre publicité. Pour la promotion d'applications, nous recommandons de sélectionner **Create ad** afin que votre publication redirige les utilisateurs vers votre application plutôt que vers la page Facebook. Dans le champ **Format**, sélectionnez une option selon le nombre de créations dont vous disposez et la façon dont vous souhaitez les afficher. 4. Dans la section **Destination**, conservez **Website** sélectionné comme **Main destination**. Dans le champ **Website URL**, collez `https://api-ua.adapty.io/api/v1/attribution/click`. Dans [l'attribution Adapty](adapty-user-acquisition), [créez une campagne web](ua-facebook) et collez le contenu du **Click link** après `https://api-ua.adapty.io/api/v1/attribution/click` dans le champ **URL parameters** de la section **Tracking**. 5. Dans la section **Ad creative**, cliquez sur **Set up creative** et sélectionnez **Image ad** ou **Video ad**. Une nouvelle fenêtre s'ouvrira pour vous inviter à téléverser des fichiers médias, les recadrer et ajouter des textes. 6. Si vous souhaitez traduire automatiquement vos textes publicitaires, dans la section **Languages**, cliquez sur **Add languages**. Ajoutez ensuite une langue principale — elle récupérera automatiquement les textes de votre création. Puis, ajoutez des langues de traduction pour une traduction automatique. 7. Lorsque vous êtes prêt(e), cliquez sur **Publish** pour lancer votre publicité. ## Et ensuite \{#whats-next\} Pour activer votre publicité, vous devrez ajouter un moyen de paiement si vous ne l'avez pas encore fait. Vous pouvez ensuite [découvrir comment la campagne influence les revenus de votre application dans le tableau de bord Adapty Attribution](adapty-user-acquisition). Vous n'utilisez pas encore Adapty Attribution ? [Prenez rendez-vous avec nous](https://calendly.com/tnurutdinov-adapty/30min) pour découvrir comment il peut vous aider à suivre et optimiser vos campagnes publicitaires. --- # File: tiktok-create-campaign --- --- title: "Faire de la publicité sur TikTok for Business" --- Dans ce guide étape par étape, vous apprendrez à créer et configurer des publicités pour votre application sur TikTok for Business, afin de les optimiser et de suivre facilement leurs performances. ## Étape 1. Ajouter les informations de l'entreprise \{#step-1-add-business-info\} Si vous débutez sur TikTok for Business, vous devez d'abord renseigner les informations de votre entreprise : 1. Rendez-vous sur [https://ads.tiktok.com](https://ads.tiktok.com/business/) et cliquez sur **Get started**. 2. Inscrivez-vous avec votre adresse e-mail ou votre compte TikTok. 3. Saisissez les informations de votre entreprise et suivez les instructions à l'écran. Une fois votre compte professionnel approuvé, vous serez redirigé vers la création de votre première campagne. ## Étape 2. Créer un pixel \{#step-2-create-a-pixel\} Vous aurez besoin d'un pixel TikTok pour relier les données de votre campagne aux revenus et obtenir de meilleurs résultats : 1. Accédez à [**Events Manager**](https://ads.tiktok.com/i18n/events_manager/home). Cliquez sur **Connect data source**. 2. Sélectionnez **Web** comme type de source de données. 3. Dans la fenêtre **Add your website**, cliquez sur **Skip**. 4. Sélectionnez **Manual setup** et cliquez sur **Next**. 5. Sélectionnez **TikTok pixel + Events API** et cliquez sur **Next**. 6. Donnez un nom à votre pixel et cliquez sur **Create**. 7. Pour [Adapty Attribution](adapty-user-acquisition), vous n'aurez pas besoin de terminer l'installation complète du pixel. Vous pouvez simplement fermer la fenêtre de configuration, et votre pixel apparaîtra dans la liste. 8. Pour rendre ce pixel utilisable dans les campagnes, vous devez lui envoyer un événement de test depuis [Adapty Attribution](adapty-user-acquisition) : 1. [Créez une nouvelle campagne TikTok](ua-tiktok). 2. Développez une section spécifique à la plateforme – par exemple, iOS. 3. Sélectionnez un pixel dans la liste déroulante. 4. Cliquez sur **Send test event**. 5. Dans la liste déroulante, sélectionnez l'événement que vous utiliserez pour l'optimisation dans la publicité. 6. Dans TikTok for Business, ouvrez votre pixel et passez à l'onglet **Test events**. Copiez le `test_event_code`. 7. Collez-le dans le champ **Test event code** dans Adapty et cliquez sur **Send**. 9. L'événement de test apparaîtra dans TikTok en quelques minutes. Dès qu'il s'affiche dans les détails de votre pixel, vous pouvez poursuivre la configuration de la campagne dans TikTok Ads Manager. ## Étape 3. Sélectionner l'objectif de la campagne \{#step-3-select-the-campaign-objective\} :::important Ce tutoriel utilise la vue Quick setup dans TikTok Ads Manager. Quelques paramètres recommandés n'apparaissent que dans la vue Full, ce que nous indiquons dans les étapes concernées. ::: Accédez à la [page de création d'annonce](https://ads.tiktok.com/i18n/nb_creation/create/objectives) dans Ads Manager. Sur le premier écran, sélectionnez l'objectif publicitaire et cliquez sur **Continue**. Sélectionnez **Sales > Website conversion**. ## Étape 4. Remplir les informations de la campagne \{#step-4-fill-in-the-campaign-info\} Ensuite, renseignez les informations de la campagne : 1. Nommez votre campagne dans le champ **Campaign name**. 2. Dans le champ **Optimization goal**, sélectionnez **Conversion**. 3. Sélectionnez votre pixel actif dans la liste déroulante et choisissez un **Optimization event**. Notez que seuls les événements actifs sont disponibles à la sélection. Si l'événement dont vous avez besoin n'est pas disponible, envoyez un événement de test en suivant les instructions de l'[Étape 2](#step-2-create-a-pixel). 4. Votre publicité sera diffusée dans le fil et la recherche TikTok. Pour une configuration supplémentaire, cliquez sur **Advanced settings**. Dans **Placements**, configurez les paramètres de placement : - **User comment** : Sélectionnez cette option si vous souhaitez afficher votre publicité dans la section commentaires également. TikTok recommande de laisser les commentaires activés pour aider vos publicités à obtenir plus d'impressions. - **Allow video download** : Autorisez les spectateurs à télécharger votre publicité. - **Allow video sharing** : Autorisez les spectateurs à partager votre publicité. 5. Cliquez sur **Continue**. ## Étape 5. Ajouter le contenu de la publicité \{#step-5-add-ad-content\} Il est maintenant temps de configurer vos créatifs et l'URL de destination : 1. Dans le champ **TikTok account**, sélectionnez le compte qui sera utilisé pour la publication. 2. Dans [Adapty Attribution](adapty-user-acquisition), [créez une campagne web](ua-tiktok) et collez le **Click link** dans le champ **Destination URL**. 3. Dans la section **Creatives**, cliquez sur **+ Videos and images**. 4. Si vous souhaitez utiliser vos publications TikTok comme créatifs, sélectionnez-les dans l'onglet **TikTok post**. Sinon, passez à l'onglet **Creative library** et cliquez sur **Upload**. Les fichiers que vous y téléchargez seront accessibles depuis cet onglet ultérieurement, vous pourrez donc les réutiliser dans d'autres campagnes. 5. Recadrez les créatifs pour les adapter au format TikTok et choisissez s'ils seront utilisés comme publicités individuelles ou en carrousel. 6. Développez le créatif importé et cliquez sur **+** à côté de **No music selected**. Vous pouvez y télécharger vos propres fichiers mp3. L'ajout de musique est obligatoire. 7. Dans le champ **Add text**, saisissez le texte qui servira de description. 8. Sélectionnez **Place the ads on this TikTok account as a post** si vous souhaitez publier cette publicité sur votre compte TikTok. 9. Dans le champ **Call to action**, sélectionnez ou supprimez les appels à l'action pertinents pour votre publicité. TikTok les ajoutera automatiquement à votre publicité. 10. Cliquez sur **Continue**. ## Étape 6. Configurer le ciblage et le budget \{#step-6-configure-targeting-and-budget\} Pour finir, définissez qui doit voir votre publicité et combien vous prévoyez de dépenser : 1. Dans la section **Targeting**, sélectionnez **Automatic** ou **Custom**. L'option **Automatic** est la plus simple si vous ne connaissez pas encore bien votre audience. En revanche, si vous choisissez **Custom**, vous pouvez optimiser vos dépenses en ciblant les groupes d'utilisateurs les plus susceptibles de réagir à votre publicité. 2. Si vous avez sélectionné **Custom**, configurez : - **Location** : Par défaut, il s'agit de la localisation de votre compte publicitaire. Si vous sélectionnez plusieurs pays ou régions cibles, les résultats de vérification des publicités seront renvoyés séparément pour chaque localisation. La diffusion effective des publicités peut également varier selon les emplacements pris en charge par les différents placements. - **Languages** : Par défaut, toutes les langues sont sélectionnées. Choisissez la langue cible en fonction de la langue la plus utilisée dans la localisation sélectionnée. - **Gender** : Par défaut, tous les genres sont sélectionnés. :::tip Si vous passez en mode Full, vous trouverez une section **Device** supplémentaire sous **Targeting**. Elle vous permet de limiter votre audience par type d'appareil, système d'exploitation et version du système — utile si votre application exige une version minimale. ::: 3. Dans la section **Budget**, sélectionnez l'une des options proposées ou choisissez **Custom**. 4. Si vous avez sélectionné **Custom**, choisissez entre un budget **Daily** ou **Lifetime** et saisissez la limite dans votre devise. Le budget **Daily** offre plus de flexibilité pendant la phase d'apprentissage, ce qui vous permet de démarrer avec de petits montants et de les ajuster progressivement. 5. Dans la section **Schedule**, sélectionnez **Continue for at least 7 days** ou **Custom**. Nous vous recommandons de définir un calendrier **Custom** si votre publicité est liée à une date précise, afin de ne pas manquer le moment où vous devez l'arrêter. 6. Si vous avez sélectionné **Custom**, définissez la date de début ou les dates de début et de fin des publicités. Notez que le fuseau horaire de votre compte sera utilisé. 7. Cliquez sur **Publish**. Une fois terminé, une nouvelle campagne sera créée avec un groupe d'annonces. Le groupe d'annonces contiendra une publicité si vous avez configuré un carrousel, ou plusieurs publicités si vous avez ajouté des créatifs comme annonces séparées. ## Étape 7. Saisir les informations de paiement \{#step-7-enter-payment-details\} Pour commencer à diffuser la publicité, après avoir configuré le ciblage et le budget, saisissez vos informations de paiement. Vous êtes ensuite prêt à démarrer ! ## Et ensuite \{#whats-next\} Vous pouvez maintenant [explorer l'impact de la campagne sur les revenus de votre application dans le tableau de bord Adapty Attribution](adapty-user-acquisition). Vous n'utilisez pas encore Adapty Attribution ? [Réservez un appel avec nous](https://calendly.com/tnurutdinov-adapty/30min) pour découvrir comment il peut vous aider à suivre et optimiser vos campagnes publicitaires. --- # File: getting-started-with-server-side-api --- --- title: "API côté serveur" description: "Démarrez avec l'API côté serveur d'Adapty pour la gestion des abonnements." --- :::tip Vous utilisez un agent de codage IA ? Consultez [Vérifier et accorder l'accès aux abonnements depuis votre backend](server-side-api-with-ai) pour un guide complet en une seule page. ::: Avec l'API, vous pouvez : 1. Vérifier le statut d'abonnement d'un utilisateur. 2. Activer l'abonnement d'un utilisateur avec un niveau d'accès. 3. Récupérer les attributs d'un utilisateur. 4. Définir les attributs d'un utilisateur. 5. Récupérer et mettre à jour les configurations de paywall. <img src="/assets/shared/img/server.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note Pour suivre les événements d'abonnement, utilisez l'intégration [Webhook](webhook) dans Adapty ou intégrez directement votre service existant. ::: ## Cas 1 : Synchroniser les abonnés entre web et mobile \{#case-1-sync-subscribers-between-web-and-mobile\} Si vous utilisez des prestataires de paiement web comme Stripe, ChargeBee ou autres, vous pouvez synchroniser vos abonnés facilement. Voici comment : 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Vérifiez leur statut d'abonnement](api-adapty/operations/getProfile) via l'API. 3. Si un utilisateur est sur un plan freemium, affichez un paywall sur votre site web. 4. Après un paiement réussi, [mettez à jour le statut d'abonnement](api-adapty/operations/setTransaction) dans Adapty via l'API. 5. Vos abonnés resteront automatiquement synchronisés avec votre application mobile. ## Cas 2 : Accorder un abonnement \{#case-2-grant-a-subscription\} :::note Pour des raisons de sécurité, vous ne pouvez pas accorder un abonnement via le SDK. ::: Si vous vendez via votre propre boutique en ligne, l'Amazon Appstore, le Microsoft Store ou toute autre plateforme en dehors de Google Play et de l'App Store, vous devrez synchroniser ces transactions avec Adapty pour fournir l'accès et suivre la transaction dans les analyses. 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Configurez un store personnalisé pour vos produits dans l'Adapty Dashboard](custom-store). 3. Synchronisez la transaction avec Adapty via la requête API [Set transaction](api-adapty/operations/setTransaction). ## Cas 3 : Accorder un niveau d'accès \{#case-3-grant-an-access-level\} Imaginons que vous organisez une promotion offrant un essai gratuit de 7 jours et que vous souhaitez une expérience cohérente sur toutes les plateformes. Pour synchroniser cela avec l'application mobile : 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. Utilisez l'API pour [accorder un accès premium](api-adapty/operations/grantAccessLevel) pendant 7 jours. Après les 7 jours, les utilisateurs qui ne s'abonnent pas seront rétrogradés au niveau gratuit. ## Cas 4 : Synchroniser les propriétés et attributs personnalisés des utilisateurs \{#case-4-sync-users-properties-and-custom-attributes\} Si vous avez des attributs personnalisés pour vos utilisateurs — comme le nombre de mots appris dans une application d'apprentissage des langues — vous pouvez également les synchroniser. 1. <InlineTooltip tooltip="Attribuer un identifiant unique à chaque utilisateur">[iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), et [Unity](unity-identifying-users)</InlineTooltip>. 2. [Mettez à jour l'attribut](api-adapty/operations/updateProfile) via l'API ou le SDK. Ces attributs personnalisés peuvent être utilisés pour créer des segments et lancer des tests A/B. ## Cas 5 : Gérer les configurations de paywall \{#case-5-manage-paywall-configurations\} Vous pouvez [mettre à jour les Remote Configs dans les paywalls](api-adapty/operations/updatePaywall) pour ajuster dynamiquement l'apparence et le comportement de votre paywall sans redéployer votre application. --- **Prochaines étapes :** - Poursuivez avec [l'autorisation pour l'API côté serveur](ss-authorization) - Requêtes : - [Obtenir un profil](api-adapty/operations/getProfile) - [Créer un profil](api-adapty/operations/createProfile) - [Mettre à jour un profil](api-adapty/operations/updateProfile) - [Supprimer un profil](api-adapty/operations/deleteProfile) - [Accorder un niveau d'accès](api-adapty/operations/grantAccessLevel) - [Révoquer un niveau d'accès](api-adapty/operations/revokeAccessLevel) - [Définir une transaction](api-adapty/operations/setTransaction) - [Valider un achat, accorder un niveau d'accès au client et importer son historique de transactions](api-adapty/operations/validateStripePurchase) - [Ajouter des identifiants d'intégration](api-adapty/operations/setIntegrationIdentifiers) - [Obtenir un paywall](api-adapty/operations/getPaywall) - [Lister les paywalls](api-adapty/operations/listPaywalls) - [Mettre à jour un paywall](api-adapty/operations/updatePaywall) --- # File: onboardings --- --- title: "Onboardings" --- :::warning Le créateur d'onboarding no-code est entièrement fonctionnel, mais Adapty n'y ajoute plus de fonctionnalités ni de mises à jour. Pour les nouveaux projets, envisagez le [Adapty Flow Builder](adapty-flow-builder) — un éditeur visuel no-code pour les paywalls mono-écran et les flows d'onboarding multi-écrans qui s'affichent nativement sur l'appareil : - **Tout type de flow** : Créez des paywalls mono-écran, des onboardings multi-étapes incluant un paywall, et tout ce qui se trouve entre les deux. - **Rendu natif** : Les flows s'affichent via le SDK Adapty, sans web view. - **Mise à jour sans redéploiement** : Modifiez les textes, le design ou la logique à tout moment — les mises à jour parviennent aux utilisateurs sans publication d'une nouvelle version de l'app. ::: Les onboardings d'Adapty permettent aux équipes non techniques de créer des flows d'onboarding sans code. Le créateur no-code génère une série d'écrans pour présenter votre app aux utilisateurs. Vous pouvez personnaliser les écrans avec des questions interactives et des variables, puis lancer des tests A/B pour trouver le flow le plus performant. Les onboardings sont disponibles pour les apps utilisant le SDK Adapty v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity), ou v3.15.0+ (Kotlin Multiplatform, Capacitor). ## Comment ça fonctionne \{#how-it-works\} 1. [Créez un onboarding dans l'éditeur no-code.](design-onboarding) 2. [Créez un placement pour l'onboarding.](create-onboarding#step-2-create-a-placement-for-your-onboarding) 3. Intégrez l'onboarding à votre projet avec le SDK Adapty : - [iOS](ios-onboardings) - [Android](android-onboardings) - [React Native](react-native-onboardings) - [Flutter](flutter-onboardings) - [Unity](unity-onboardings) - [Kotlin Multiplatform](kmp-onboardings) - [Capacitor](capacitor-onboardings) 4. Testez l'onboarding et publiez-le pour vos utilisateurs. --- # File: create-onboarding --- --- title: "Créer un onboarding" --- Les [onboardings](onboardings) présentent aux nouveaux utilisateurs la valeur, les fonctionnalités et les conseils d'utilisation de votre application mobile. ## Étape 1. Créer un onboarding \{#step-1-create-an-onboarding\} Pour créer un nouvel onboarding dans l'Adapty Dashboard : 1. Accédez à **Onboardings** depuis le menu principal d'Adapty. Cette page donne un aperçu de tous les onboardings que vous avez configurés, ainsi que leurs métriques. Cliquez sur **Create onboarding**. <img src="/assets/shared/img/create-onboarding1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Donnez un nom explicite à votre onboarding et cliquez sur **Proceed to build onboarding**. <img src="/assets/shared/img/create-onboarding2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Vous serez redirigé vers le créateur d'onboarding. Il contient un modèle de démonstration par défaut, que vous pouvez explorer pour comprendre comment les onboardings collectent des données et comment les personnaliser à l'aide de variables et de quiz. N'hésitez pas à supprimer les écrans dont vous n'avez pas besoin et à [concevoir votre propre expérience d'onboarding](design-onboarding). <img src="/assets/shared/img/create-onboarding3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Lorsque vous êtes prêt, cliquez sur le bouton **Preview** en haut à droite. Parcourez vous-même votre flow d'onboarding pour vérifier que tout fonctionne comme prévu. <img src="/assets/shared/img/create-onboarding4.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Si tout fonctionne correctement, cliquez sur **Publish** en haut à droite. Attendez que la publication soit terminée avant de revenir dans Adapty. Dans le cas contraire, votre progression sera perdue. :::danger Si vous ne cliquez pas sur **Publish**, le SDK ne pourra pas récupérer l'onboarding que vous avez créé. ::: <img src="/assets/shared/img/create-onboarding5.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois votre onboarding publié, cliquez sur **Back to Adapty**. Votre onboarding est créé et vous pouvez l'ajouter à un placement pour commencer à l'utiliser. ## Étape 2. Créer un placement pour votre onboarding \{#step-2-create-a-placement-for-your-onboarding\} 1. Accédez à **Placements** depuis le menu principal et basculez sur l'onglet **Onboardings**. Cliquez sur **Create placement**. <img src="/assets/shared/img/create-onboarding6.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Saisissez le nom et l'ID du placement. Ensuite, cliquez sur **Run onboarding** et sélectionnez un onboarding à afficher à tous les utilisateurs. 3. Si vous avez préparé un onboarding distinct pour un groupe d'utilisateurs spécifique, [ajoutez d'autres audiences](audience) et sélectionnez un onboarding différent pour elles. ## Étape 3. Intégrer l'onboarding dans votre application \{#step-3-integrate-the-onboarding-into-your-app\} :::important Les onboardings sont disponibles pour les applications utilisant le SDK Adapty v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity) ou v3.15.0+ (Kotlin Multiplatform, Capacitor). ::: Pour commencer à afficher des onboardings dans votre application, intégrez-les avec le SDK Adapty : - [iOS](ios-onboardings) - [Android](android-onboardings) - [React Native](react-native-onboardings) - [Flutter](flutter-onboardings) - [Unity](unity-onboardings) - [Kotlin Multiplatform](kmp-onboardings) - [Capacitor](capacitor-onboardings) Pour déterminer quel onboarding fonctionne le mieux, vous pouvez également lancer des [tests A/B](ab-tests). --- # File: design-onboarding --- --- title: "Concevoir des onboardings" description: "Créez des onboardings efficaces." --- Le builder d'onboarding no-code pour applications mobiles est un outil puissant et personnalisable qui vous aide à offrir la meilleure expérience d'onboarding à vos utilisateurs. Inutile d'être développeur ou designer pour obtenir un excellent résultat. ## Écrans d'onboarding \{#onboarding-screens\} Le flow d'onboarding est composé de plusieurs écrans que vous ajoutez et concevez. Les utilisateurs appuient sur le bouton pour naviguer entre eux. :::tip Si certains de vos utilisateurs ont besoin d'un flow légèrement différent (par exemple, dans une application fitness, vous pourriez vouloir afficher des images d'« objectif » différentes selon le sexe de l'utilisateur), vous n'avez pas besoin de créer des onboardings séparés. À la place, vous pouvez masquer certains écrans par défaut et les afficher uniquement dans certains cas. ::: ## Éléments d'onboarding \{#onboarding-elements\} Les éléments d'onboarding s'affichent à gauche dans l'ordre où ils apparaissent. Cliquez sur **Add** en haut à droite pour ajouter un nouvel élément. Voici les groupes d'éléments disponibles : - **Containers** : Les conteneurs vous permettent de configurer une mise en page flexible. Par exemple, si vous souhaitez ajouter un texte sur deux colonnes, ajoutez **Columns** puis faites glisser deux blocs de texte dans **Columns** dans le panneau de gauche. Ou, si vous ajoutez un carrousel, vous devrez ajouter des images aux éléments **Media** à l'intérieur. - **Typography** : Ajoutez des blocs de texte préformatés et configurez leur apparence selon vos besoins. - **Media & Display** : En plus des images et des vidéos, vous pouvez ajouter des graphiques animés qui démontrent la valeur de votre application et encouragent les utilisateurs. Les **formats vidéo pris en charge** sont MP4 et WebM. La **taille maximale des fichiers médias** est de 15 Mo. Si vous souhaitez ajouter un élément animé non pris en charge (comme Lottie), vous pouvez le convertir en vidéo (par exemple avec [cet outil](https://www.lottielab.com/lottie/lottie-to-video)) et l'intégrer en tant que vidéo. - **Quiz** : Créez de courts questionnaires avec des options texte et image pour personnaliser l'expérience d'onboarding et mieux connaître vos utilisateurs. - **Inputs** : Collectez les données de vos utilisateurs. - **Buttons** : Les boutons permettent à vos utilisateurs de naviguer entre les écrans, de fermer l'onboarding ou d'accéder au paywall. Vous pouvez également ajouter des boutons brillants ou animés pour attirer l'attention des utilisateurs et convertir leur installation en achat. - **Loaders** : Des loaders animés maintiennent l'engagement des utilisateurs pendant le processus. - **User engagement** : Ajoutez des témoignages, des listes d'e-mails d'utilisateurs et des comptes à rebours. :::note Dans le groupe **Media & Display**, vous pouvez également ajouter du code HTML personnalisé si les options de personnalisation disponibles ne sont pas suffisantes. Cependant, les éléments HTML personnalisés ne sont ni préchargés ni mis en cache, il est donc recommandé d'utiliser **Raw HTML** uniquement pour des éléments petits et légers. ::: <img src="/assets/shared/img/design-onboarding4.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ID d'élément et ID d'action \{#element-id-and-action-id\} Si vous souhaitez utiliser un bouton pour des actions personnalisées, attribuez-lui un **action ID** puis utilisez-le dans votre code source. Les action IDs vous permettent de gérer différents boutons avec le même action ID de la même manière. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Si vous souhaitez traiter la saisie d'un utilisateur dans un champ spécifique (par exemple, enregistrer son âge ou son e-mail), attribuez-lui un **element ID** puis utilisez-le dans votre code source pour associer les questions aux réponses. Les element IDs ne peuvent être utilisés qu'une seule fois dans votre onboarding. <img src="/assets/shared/img/design-onboarding5.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Options de personnalisation \{#customization-options\} Vous disposez des options de personnalisation suivantes dans le builder : - Onglet **Styles** : Ajustez l'apparence de l'élément. <img src="/assets/shared/img/design-onboarding1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - Onglet **Element** : Définissez les attributs de l'élément, tels que la visibilité, les actions associées aux boutons ou d'autres propriétés sans rapport avec l'apparence de l'élément. <img src="/assets/shared/img/design-onboarding2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - Onglet **Screen** : Configurez les paramètres généraux de l'écran, comme un en-tête ou l'affichage d'un compteur d'écrans. <img src="/assets/shared/img/design-onboarding3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Copier des écrans et des éléments \{#copy-screens-and-elements\} Si vous avez créé un onboarding et souhaitez en réutiliser des parties, ou si vous voulez apporter de légères modifications et lancer des tests A/B, vous pouvez copier un ou plusieurs écrans d'un onboarding vers un autre. Pour copier des écrans, ouvrez le builder d'onboarding et procédez de l'une des façons suivantes : - Faites un clic droit sur un écran et sélectionnez **Copy** - Sélectionnez l'écran souhaité et appuyez sur `Ctrl+C` (Windows) ou `⌘+C` (Mac) Vous pouvez également copier des éléments individuels ou des blocs de texte, que ce soit dans le même onboarding ou entre différents onboardings. ## Copier des écrans depuis des funnels web-to-app \{#copy-screens-from-web-to-app-funnels\} Si vous utilisez des funnels web-to-app créés dans [FunnelFox](https://funnelfox.com/) et souhaitez utiliser des écrans de ces funnels dans vos onboardings, vous pouvez le faire rapidement en copiant des écrans dans le funnel builder et en les collant dans le builder d'onboarding : 1. Dans le funnel builder FunnelFox, faites un clic droit sur un écran et sélectionnez **Copy**, ou sélectionnez l'écran et appuyez sur `Ctrl+C`/`⌘+C`. 2. Ouvrez le builder d'onboarding. 3. Faites un clic droit sur l'écran sous lequel vous souhaitez insérer l'écran copié et sélectionnez **Paste**, ou sélectionnez-le et appuyez sur `Ctrl+V`/`⌘+V`. L'écran copié sera inséré sous l'écran sélectionné. <img src="/assets/shared/img/funnel-to-onboarding.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: adapty-paywall-builder --- --- title: "Adapty Paywall Builder (Legacy)" description: "Créez des paywalls et des flows d'onboarding avec l'éditeur visuel no-code." --- :::warning Le Paywall Builder est pleinement fonctionnel, mais Adapty n'y ajoute plus de fonctionnalités ni de mises à jour. Pour les nouveaux projets, pensez à l'[Adapty Flow Builder](adapty-flow-builder) — un éditeur visuel no-code pour créer des paywalls à écran unique et des flows d'onboarding multi-écrans qui s'affichent nativement sur l'appareil : - **Tous types de flows** : Créez des paywalls à écran unique, des onboardings multi-étapes incluant un paywall, et tout ce qui se trouve entre les deux. - **Rendu natif** : Les flows s'affichent via le SDK Adapty, sans web view. - **Mise à jour sans redéploiement** : Modifiez les textes, le design ou la logique à tout moment — les mises à jour parviennent aux utilisateurs sans publication d'une nouvelle version de l'app. ::: Le **Paywall Builder** d'Adapty est un outil visuel no-code pour concevoir des paywalls personnalisés. Vous pouvez partir d'un modèle, personnaliser la mise en page et ajouter des éléments comme des carrousels, des cartes, des listes de produits et des pieds de page. L'éditeur prend également en charge les polices personnalisées, les tags de produits et la localisation. Le Paywall Builder nécessite le SDK Adapty v3.0 ou une version ultérieure. Une fois votre paywall conçu, [ajoutez-le à un placement](add-audience-paywall-ab-test) et affichez-le dans votre app : - [iOS](ios-quickstart-paywalls) - [Android](android-quickstart-paywalls) - [React Native](react-native-quickstart-paywalls) - [Flutter](flutter-quickstart-paywalls) - [Unity](unity-quickstart-paywalls) - [Capacitor](capacitor-quickstart-paywalls) - [Kotlin Multiplatform](kmp-quickstart-paywalls) --- # File: flutterflow --- --- title: "Plugin Adapty pour FlutterFlow" description: "Intégrez FlutterFlow avec Adapty pour une gestion améliorée des abonnements." --- Adapty est une plateforme polyvalente conçue pour aider les applications mobiles à se développer. Que vous démarriez tout juste ou que vous ayez déjà des milliers d'utilisateurs, Adapty vous permet d'économiser des mois d'intégration des achats intégrés et de doubler vos revenus d'abonnements grâce à la gestion des paywalls. Le plugin Adapty pour FlutterFlow vous permet de tirer parti de toutes les fonctionnalités d'Adapty sans une seule ligne de code. Vous pouvez concevoir vos pages de paywall dans FlutterFlow, activer les achats sur celles-ci, puis contrôler à distance quels produits y sont affichés — avec ciblage vers des groupes d'utilisateurs spécifiques ou tests A/B. Et après la sortie de votre application, vous accédez instantanément à des analytics détaillées sur les achats de vos clients directement dans notre tableau de bord. Vous souhaitez mettre à jour les produits disponibles sur votre paywall ? C'est simple ! Faites vos modifications en quelques clics dans l'Adapty Dashboard, et vos clients verront immédiatement les nouveaux produits — pas besoin de publier une nouvelle version de l'application ! Ce qu'Adapty vous offre en plus : - **Abonnements et achats intégrés** : Adapty gère pour vous la validation des reçus côté serveur et synchronise vos clients sur toutes les plateformes, y compris le web. - **Tests A/B pour les paywalls** : Testez différents prix, durées, périodes d'essai et éléments visuels pour optimiser vos offres d'abonnements et d'achats uniques. - **Analytics puissantes** : Accédez à des métriques détaillées pour mieux comprendre et améliorer la monétisation de votre application. - **Intégrations** : Adapty se connecte parfaitement aux outils d'analytics tiers comme Amplitude, AppsFlyer, Adjust, Branch, Mixpanel, Facebook Ads, AppMetrica, des Webhooks personnalisés, et bien plus encore. --- # File: ff-getting-started --- --- title: "Démarrer" description: "Commencez avec les Feature Flags Adapty pour personnaliser vos flows d'abonnement." --- Avec Adapty, vous pouvez créer et exécuter des paywalls et des tests A/B à différents points du parcours utilisateur de votre application mobile, comme l'Onboarding, les Paramètres, etc. Ces points s'appellent des [Placements](placements). Un placement dans votre application peut gérer plusieurs paywalls ou [tests A/B](ab-tests) à la fois, chacun destiné à un groupe d'utilisateurs spécifique, que nous appelons des [Audiences](audience). De plus, vous pouvez expérimenter avec les paywalls en en remplaçant un par un autre au fil du temps, sans publier de nouvelle version de l'application. La seule chose que vous codez en dur dans l'application mobile est l'identifiant du placement. <img src="/assets/shared/img/audience.jpg" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> La bibliothèque Adapty maintient votre paywall à jour avec les derniers produits de votre Adapty Dashboard. Elle [récupère les données des produits](ff-action-flow) et [les affiche sur votre paywall](ff-add-variables-to-paywalls), [gère les achats](ff-make-purchase) et [vérifie le niveau d'accès de l'utilisateur](ff-check-subscription-status) pour déterminer s'il doit accéder au contenu payant. Pour commencer, il suffit d'[ajouter la bibliothèque Adapty](ff-getting-started#add-the-adapty-library-as-a-dependency) à votre projet FlutterFlow et de [l'initier](ff-getting-started#initiate-adapty-plugin) comme indiqué ci-dessous. :::warning Avant de commencer, prenez note des limitations suivantes : - La bibliothèque Adapty pour FlutterFlow ne prend pas en charge les applications web. Évitez de compiler des applications web avec elle. - La bibliothèque Adapty pour FlutterFlow ne prend pas en charge les paywalls créés avec le Paywall Builder d'Adapty. Vous devez concevoir votre propre paywall dans FlutterFlow avant d'activer les achats avec Adapty. ::: ## Ajouter la bibliothèque Adapty en tant que dépendance \{#add-the-adapty-library-as-a-dependency\} 1. Dans le [FlutterFlow Dashboard](https://app.flutterflow.io/dashboard), ouvrez votre projet, puis cliquez sur **Settings and Integrations** dans le menu de gauche. Dans la section **Project setup** à gauche, sélectionnez **Project dependencies**. <img src="/assets/shared/img/main_settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la section **FlutterFlow Libraries**, cliquez sur **Add Library** et saisissez `adapty-xtuel0`. Cliquez sur **Add**. 3. Vous devez maintenant associer votre clé SDK à la bibliothèque. Cliquez sur **View details** en regard de la bibliothèque. <img src="/assets/shared/img/ff_view_details.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Copiez la **Public SDK key** depuis l'onglet [**App Settings** -> **General**](https://app.adapty.io/settings/general) dans l'Adapty Dashboard. <img src="/assets/shared/FF_img/adaptyapikey.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Collez la clé dans **AdaptyApiKey** dans FlutterFlow. <img src="/assets/shared/img/ff_apikey.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> La bibliothèque Adapty FF sera désormais ajoutée en tant que dépendance à votre projet. Dans la fenêtre de la bibliothèque Adapty FF, vous trouverez toutes les ressources Adapty qui ont été importées dans votre projet. ## Appeler la nouvelle action d'activation au lancement de l'application \{#call-the-new-activation-action-at-application-launch\} 1. Accédez à la section **Custom Code** depuis le menu de gauche et ouvrez `main.dart`. <img src="/assets/shared/img/ff_dartmain.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur **+** et sélectionnez `activate (Adapty)`. <img src="/assets/shared/img/ff_activate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Save**. ## Initier le plugin Adapty \{#initiate-adapty-plugin\} Pour que l'Adapty Dashboard reconnaisse votre application, vous devez fournir une clé spéciale dans FlutterFlow. 1. Dans votre projet FlutterFlow, accédez à **Settings and Integrations > Permissions** depuis le menu de gauche. 2. Dans la fenêtre **Permissions** qui s'ouvre, cliquez sur le bouton **Add Permission**. 3. Dans les champs **iOS Permission Key** et **Android Permission Key**, collez `AdaptyPublicSdkKey`. 4. Pour le champ **Permission Message**, copiez la **Public SDK key** depuis l'onglet [**App Settings** -> **General**](https://app.adapty.io/settings/general) dans l'Adapty Dashboard. Chaque application a sa propre clé SDK, donc si vous avez plusieurs applications, assurez-vous de prendre la bonne. <img src="/assets/shared/img/ff_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Une fois ces étapes terminées, vous pourrez appeler votre paywall dans votre application FlutterFlow et activer les achats via celui-ci. ## Et maintenant ? \{#whats-next\} 1. [Créez un action flow](ff-action-flow) pour gérer les produits du paywall Adapty et leurs données dans FlutterFlow. 2. [Mappez les données reçues sur le paywall](ff-add-variables-to-paywalls) que vous avez conçu dans FlutterFlow. 3. [Configurez le bouton d'achat](ff-make-purchase) sur votre paywall pour traiter les transactions via Adapty lors du clic. 4. Enfin, [ajoutez des vérifications du statut d'abonnement](ff-check-subscription-status) pour déterminer si le contenu payant doit être affiché à l'utilisateur. --- # File: ff-action-flow --- --- title: "Étape 1. Créer un flow pour afficher les données du paywall" description: "Configurez des flows d'action avec les feature flags dans Adapty pour personnaliser le parcours d'abonnement des utilisateurs." --- :::important Lorsque vous utilisez le plugin FlutterFlow, vous ne pouvez pas utiliser les paywalls créés dans le Paywall Builder d'Adapty. Vous devez implémenter votre propre page de paywall dans FlutterFlow et la connecter à Adapty. ::: Après avoir ajouté la bibliothèque Adapty en tant que dépendance à votre projet FlutterFlow, il est temps de construire le flow qui **récupère les données du paywall et des produits Adapty et les affiche sur le paywall que vous avez conçu dans FlutterFlow**. Nous devons d'abord recevoir les données du paywall depuis Adapty. Nous commencerons par demander le paywall Adapty, puis ses produits associés, et enfin vérifier si les données ont bien été reçues. Si c'est le cas, nous afficherons le titre du produit et son prix sur la page du paywall. Sinon, nous afficherons un message d'erreur. Avant de continuer, assurez-vous d'avoir effectué les étapes suivantes : 1. [Créé au moins un paywall et ajouté au moins un produit](create-paywall) dans l'Adapty Dashboard. 2. [Créé au moins un placement](create-placement) et [ajouté votre paywall](add-audience-paywall-ab-test) dans l'Adapty Dashboard. C'est parti ! ## Étape 1.1. Demander le paywall Adapty \{#step-11-request-adapty-paywall\} Comme mentionné, pour afficher des données dans votre paywall FlutterFlow, nous devons d'abord les récupérer depuis Adapty. La première étape consiste à obtenir le paywall Adapty lui-même. Voici comment procéder : 1. Ouvrez votre écran de paywall et passez à la section **Actions** dans le panneau de droite. Là, ouvrez l'**Action Flow Editor**. <img src="/assets/shared/img/ff_action_flow.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la fenêtre **Select Action Trigger**, sélectionnez **On Page Load**. <img src="/assets/shared/img/ff_action_trigger.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Add Action**. Ensuite, recherchez l'action personnalisée `getPaywall` et sélectionnez-la. <img src="/assets/shared/img/ff_getpaywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Dans la section **Set Actions Arguments**, saisissez l'ID réel du [placement que vous avez créé](create-placement) dans l'Adapty Dashboard qui inclut le paywall. Dans cet exemple, c'est `monthly`. Assurez-vous d'utiliser votre vrai ID de placement ! <img src="/assets/shared/img/ff_placementid.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Si vous avez [localisé](localizations-and-locale-codes) votre paywall dans l'Adapty Dashboard, vous pouvez également configurer l'argument **locale**. 6. Dans l'**Action Output Variable Name**, créez une nouvelle variable et nommez-la `getPaywallResult`. Nous l'utiliserons à l'étape suivante pour référencer le paywall Adapty et demander ses produits. <img src="/assets/shared/img/ff_getpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 1.2. Demander les produits du paywall Adapty \{#step-12-request-adapty-paywall-products\} Parfait ! Nous avons récupéré le paywall Adapty. Maintenant, obtenons les produits associés à ce paywall : 1. Cliquez sur **+** sous l'action créée et sélectionnez **Add Action**. Cette action permettra de recevoir les produits du paywall Adapty. Pour cela, recherchez et sélectionnez `getPaywallProducts`. 2. Dans la section **Set Actions Arguments**, sélectionnez la variable `getPaywallResult` créée précédemment. <img src="/assets/shared/img/ff_getpaywallproduct.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Remplissez les autres champs comme suit : - **Available Options** : Data Structured Field - **Select Field** : value - **Available Options** : Aucune modification supplémentaire <img src="/assets/shared/img/ff_getpaywallresult2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur **Confirm**. 5. Dans l'**Action Output Variable Name**, créez une nouvelle variable et nommez-la `getPaywallProductsResult`. Nous l'utiliserons pour associer le paywall que vous avez conçu dans FlutterFlow aux données du paywall Adapty. <img src="/assets/shared/img/ff_getpaywallproductsresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 1.3. Ajouter une vérification du chargement du paywall \{#step-13-add-check-if-the-paywall-uploaded-successfully\} Avant de continuer, vérifions que le paywall Adapty a bien été reçu. Si c'est le cas, nous pouvons mettre à jour le paywall avec les données des produits. Sinon, nous gérerons l'erreur. Voici comment ajouter la vérification : 1. Cliquez sur **+** puis sur **Add Conditional**. <img src="/assets/shared/img/ff-add-conditional.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Dans la section **Action Output**, sélectionnez la variable de sortie d'action créée précédemment (`getPaywallResult` dans notre exemple). <img src="/assets/shared/img/ff-getpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Pour vérifier que le paywall Adapty a bien été reçu, contrôlez la présence d'un champ avec une valeur. Remplissez les champs comme suit : - **Available Options** : Has Field - **Field (AdaptyGetPaywallResult)** : value 4. Cliquez sur **Confirm** pour finaliser la condition. ## Étape 1.4. Enregistrer la vue du paywall \{#step-14-log-the-paywall-review\} Pour qu'Adapty Analytics comptabilise la vue du paywall, nous devons enregistrer cet événement. Sans cette étape, la vue ne sera pas comptée dans les analyses. Voici comment procéder : 1. Cliquez sur **+** sous le label **TRUE** et cliquez sur **Add Action**. 2. Dans le champ **Select Action**, recherchez et choisissez **logShowPaywall**. <img src="/assets/shared/img/ff-logshowpaywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Value** dans la zone **Set Action Arguments** et choisissez la variable `getPaywallResult` que nous avons créée. Cette variable contient les données du paywall. 4. Remplissez les champs comme suit : - **Available Options** : Data Structured Field - **Select Field** : value 5. Cliquez sur **Confirm**. <img src="/assets/shared/img/ff-lohsgowpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 1.5. Afficher une erreur si le paywall n'est pas reçu \{#step-15-show-error-if-paywall-not-received\} Si le paywall Adapty n'est pas reçu, vous devez [gérer l'erreur](error-handling-on-flutter-react-native-unity#system-storekit-codes). Dans cet exemple, nous afficherons simplement un message d'alerte. 1. Ajoutez une action **Informational Dialog** au label **FALSE**. 2. Dans le champ **Title**, ajoutez le texte que vous souhaitez voir comme titre du dialogue. Dans cet exemple, c'est **Error**. 3. Cliquez sur **Value** dans la zone **Message**. 4. Remplissez les champs comme suit : - **Set Variable** : variable `getPaywallProductResult` que nous avons créée - **Available Options** : Data Structure Field - **Select Field** : error - **Available Options** : Data Structure Field - **Select Field** : errorMessage <img src="/assets/shared/img/ff-error.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Confirm**. 6. Ajoutez une action **Terminate action** au flow **FALSE**. <img src="/assets/shared/img/ff-terminate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur **Close** dans le coin supérieur droit. Félicitations ! Vous avez bien reçu les données des produits. Maintenant, [associez-les au paywall que vous avez conçu dans FlutterFlow](ff-add-variables-to-paywalls). --- # File: ff-add-variables-to-paywalls --- --- title: "Étape 2. Ajouter des données à la page paywall" description: "Ajoutez des variables Feature Flag aux paywalls dans Adapty." --- Une fois que vous avez [récupéré toutes les données produit nécessaires](ff-action-flow), il est temps de les associer au beau paywall que vous avez conçu dans FlutterFlow. Dans cet exemple, nous allons associer le titre du produit et son prix. ## Étape 2.1. Ajouter le titre du produit à la page paywall \{#step-21-add-product-title-to-paywall-page\} 1. Double-cliquez sur le texte du produit dans votre page paywall. Dans la fenêtre **Set from Variable**, recherchez la variable `getPaywallProductResult` et sélectionnez-la. <img src="/assets/shared/img/ff-paywall-text.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Remplissez les champs comme suit : - **Available Options** : Data Structured Field - **Select Field** : value - **Available Options** : Item at Index - **List Index Options** : First - **Available Options** : Data Structured Field - **Select Field** : localizedTitle - **Default Variable Value** : null - **UI Builder Display Value** : N'importe quoi, dans l'exemple c'est `product.title` <img src="/assets/shared/img/ff-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Confirm** pour enregistrer les modifications. ## Étape 2.2. Ajouter le texte du prix à la page paywall \{#step-22-add-price-text-to-paywall-page\} Répétez les étapes de l'Étape 2.1 pour le texte du prix comme indiqué ci-dessous : 1. Double-cliquez sur le texte du prix dans votre page paywall. Dans la fenêtre **Set from Variable**, recherchez la variable `getPaywallProductResult` et sélectionnez-la. <img src="/assets/shared/img/ff-price.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Remplissez les champs comme suit : - **Available Options** : Data Structured Field - **Select Field** : value - **Available Options** : Item at Index - **List Index Options** : First - **Available Options** : Data Structured Field - **Select Field** : price - **Default Variable Value** : null - **UI Builder Display Value** : N'importe quoi, dans l'exemple c'est `product.price` 3. Cliquez sur le bouton **Confirm** pour enregistrer les modifications. ### Ajouter le prix en devise locale à la page paywall \{#add-price-in-local-currency-to-paywall-page\} 1. Double-cliquez sur le prix dans votre page paywall. Dans la fenêtre **Set from Variable**, recherchez la variable `getPaywallProductResult` et sélectionnez-la. 2. Remplissez les champs comme suit : - **Available Options** : Data Structured Field - **Select Field** : value - **Available Options** : Item at Index - **List Index Options** : First - **Available Options** : Data Structured Field - **Select Field** : price - **Available Options** : Data Structured Field - **Select Field** : amount - **Available Options** : Decimal - **Decimal Type** : Automatic - **Default Variable Value** : null - **UI Builder Display Value** : N'importe quoi, dans l'exemple c'est `price.amount` 3. Cliquez sur **Confirm** pour enregistrer les modifications. Et voilà ! Désormais, au lancement de votre application, elle affichera les données produit du paywall Adapty directement sur votre page paywall ! Il est temps de [laisser vos utilisateurs acheter ce produit](ff-make-purchase). --- # File: ff-make-purchase --- --- title: "Étape 3. Activer l'achat" description: "Découvrez comment effectuer des achats grâce au système de Feature Flags d'Adapty." --- Félicitations ! Vous avez réussi à [configurer votre paywall pour afficher les données produit depuis Adapty](ff-add-variables-to-paywalls), notamment le titre du produit et son prix. Passons maintenant à l'étape finale : permettre aux utilisateurs d'effectuer un achat via le paywall. ## Étape 3.1. Permettre aux utilisateurs d'effectuer des achats \{#step-31-enable-users-to-make-purchases\} 1. Double-cliquez sur le bouton d'achat de votre page de paywall. Dans le panneau de droite, ouvrez la section **Actions** si elle n'est pas déjà ouverte. 2. Ouvrez l'**Action Flow Editor**. <img src="/assets/shared/img/ff-action-flow-editor.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Select Action Trigger**, choisissez **On Tap**. 4. Dans la fenêtre **No Actions Created**, cliquez sur **Add Action**. Recherchez l'action `makePurchase` et sélectionnez-la. <img src="/assets/shared/img/ff-makepurchase.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Dans la section **Set Actions Arguments**, choisissez la variable `getPaywallProductsResult` créée précédemment. 6. Remplissez les champs comme suit : - **Available Options** : Data Structure Field - **Select Field** : value - **Available Options** : Item at Index - **List Index Options** : First <img src="/assets/shared/img/ff-makepurchase-value.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Cliquez sur `subscriptionUpdateParameters`, recherchez `AdaptySubscriptionUpdateParameters` et sélectionnez-le. Cliquez sur **Confirm**. :::info Par défaut, vous pouvez laisser tous les champs de l'objet vides. Vous devrez les remplir pour remplacer un abonnement par un autre dans les applications Android. En savoir plus [ici](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/). ::: <img src="/assets/shared/img/ff-subupdate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. Cliquez sur **Confirm**. 9. Dans **Action Output Variable Name**, créez une nouvelle variable et nommez-la `makePurchaseResult` — elle sera utilisée ensuite pour confirmer que l'achat a bien été effectué. <img src="/assets/shared/img/ff-makepurchaseresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3.2. Vérifier si l'achat a réussi \{#step-32-check-if-the-purchase-was-successful\} Configurons maintenant une vérification pour savoir si l'achat a bien abouti. 1. Cliquez sur **+** puis sur **Add Conditional**. 2. Dans **Set Condition for Action**, sélectionnez la variable `makePurchaseResult`. 3. Dans la fenêtre **Set Variable**, remplissez les champs comme suit : - **Available Options** : Has Field - **Select Field** : profile <img src="/assets/shared/img/ff-makepurchaseresult-conditional.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur **Confirm**. ## Étape 3.3. Ouvrir le contenu payant \{#step-33-open-paid-content\} Si l'achat réussit, vous pouvez déverrouiller le contenu payant. Voici comment procéder : 1. Cliquez sur **+** sous le libellé **TRUE** et cliquez sur **Add Action**. 2. Dans le champ **Define Action**, recherchez et sélectionnez la page que vous souhaitez ouvrir dans la liste **Navigate To**. Dans cet exemple, la page est **Questions**. <img src="/assets/shared/img/ff-questions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3.4. Afficher un message d'erreur si l'achat échoue \{#step-34-show-error-message-if-purchase-failed\} Si l'achat échoue, affichons une alerte à l'utilisateur. 1. Ajoutez une action **Informational Dialog** au libellé **FALSE**. 2. Dans le champ **Title**, saisissez le texte souhaité pour le titre de la boîte de dialogue, par exemple **Purchase Failed**. <img src="/assets/shared/img/ff-purchase-fail.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Cliquez sur **Value** dans la zone **Message**. Dans la fenêtre **Set from Variable**, recherchez `makePurchaseResult` et sélectionnez-le. Remplissez les champs comme suit : - **Available Options** : Data Structure Field - **Select Field** : error - **Available Options** : Data Structure Field - **Select Field** : errorMessage <img src="/assets/shared/img/ff-fail-message.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Cliquez sur **Confirm**. 5. Ajoutez une action **Terminate** au flow **FALSE**. <img src="/assets/shared/img/ff-terminate-purchase.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Enfin, cliquez sur **Close** dans le coin supérieur droit. Félicitations ! Vos utilisateurs peuvent désormais acheter vos produits. Pour aller plus loin, [configurez une vérification de l'accès des utilisateurs au contenu payant](ff-check-subscription-status) ailleurs dans l'application, afin de décider si leur afficher le contenu payant ou le paywall. --- # File: ff-check-subscription-status --- --- title: "Étape 4. Vérifier l'accès au contenu payant" description: "Découvrez comment vérifier le statut d'un abonnement en utilisant les feature flags d'Adapty pour une meilleure segmentation des utilisateurs." --- Pour déterminer si un utilisateur a accès à un contenu payant spécifique, vous devez vérifier son niveau d'accès. Cela consiste à s'assurer que l'utilisateur possède au moins un niveau d'accès et que ce niveau est bien celui requis. Pour cela, consultez le profil utilisateur, qui contient tous les niveaux d'accès disponibles. Voici comment permettre aux utilisateurs d'accéder à votre produit : 1. Double-cliquez sur le bouton qui doit afficher le contenu payant, puis ouvrez la section **Actions** dans le panneau de droite si elle n'est pas déjà ouverte. 2. Ouvrez l'**Action Flow Editor**. <img src="/assets/shared/img/ff-open-paid-content.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Dans la fenêtre **Select Action Trigger**, choisissez **On Tap**. 4. Dans la fenêtre **No Actions Created**, cliquez sur le bouton **Add Conditional Action**. 5. Cliquez sur **UNSET** pour définir les arguments de l'action et choisissez la variable `currentProfile`. Il s'agit de la variable Adapty qui contient les données du profil de l'utilisateur actuel. <img src="/assets/shared/img/ff-currentprofile.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Remplissez les champs comme suit : - **Available Options** : Data Structure Field - **Select Field** : accessLevels - **Available Options** : Filter List Items - **Filter Conditions** : 1. Sélectionnez **Conditions -> Single Condition** et cliquez sur **UNSET**. 2. Dans le champ **First value**, sélectionnez **Item in list** comme **Source** et remplissez les champs comme suit : - **Available Options** : Data Structure Field - **Select Field** : accessLevelIdentifier 3. Définissez l'opérateur de filtre sur **Equal to**. 4. Cliquez sur **UNSET** à côté de **Second value** et dans le champ **Value**, saisissez l'ID de votre niveau d'accès ; dans notre exemple, nous utilisons `premium`. <img src="/assets/shared/img/ff-filter.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Cliquez sur **Confirm** et continuez à remplir les autres champs ci-dessous. - **Available Options** : Item at Index - **List Index Options** : First - **Available Options** : Data Structure Field - **Select Field** : accessLevel - **Available Options** : Data Structure Field - **Select Field** : isActive 7. Cliquez sur **Confirm**. Ajoutez maintenant les actions correspondant à la suite — selon que l'utilisateur dispose ou non du bon abonnement. Redirigez-le soit vers la page réservée aux abonnés premium, soit vers la page du paywall pour qu'il puisse acheter l'accès. --- # File: ff-resources --- --- title: "Actions et types de données du plugin FlutterFlow d'Adapty" description: "Accédez aux ressources de feature flag d'Adapty pour simplifier les fonctionnalités basées sur les abonnements." --- ## Actions personnalisées \{#custom-actions\} Voici les méthodes Adapty disponibles dans FlutterFlow via le plugin Adapty. Elles peuvent être utilisées comme actions personnalisées dans FlutterFlow. | Custom Action | Description | Action Arguments | Adapty Data Types - Action Output Variable | |---|----|--------|----| | activate | Initialise le SDK Adapty | Aucun || | <p id="getPaywall">getPaywall</p> | Récupère un paywall. Ne retourne pas les produits du paywall. Utilisez l'action `getPaywallProducts` pour obtenir les produits réels | <ul><li>[Placement_ID](placements)</li><li>[Locale](localizations-and-locale-codes)</li></ul> | [AdaptyGetPaywallResult](ff-resources#adaptygetpaywallresult)| | <p id="getPaywallProducts">getPaywallProducts</p> | Retourne une liste des produits réels du paywall | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyGetProductsResult](ff-resources#adaptygetproductsresult) | | <p id="getproductsintroductoryoffereligibility">getProductsIntroductoryOfferEligibility</p> | Vérifie si l'utilisateur est éligible à une offre de lancement iOS | [AdaptyPaywallProduct](product) | [AdaptyGetIntroEligibilitiesResult](ff-resources#adaptygetintroeligibilitiesresult) | | <p id="makePurchase">makePurchase</p> | Finalise un achat et déverrouille le contenu. Si un paywall comporte une offre promotionnelle, Adapty l'applique automatiquement lors du paiement | <ul><li> **product** : un objet AdaptyPaywallProduct récupéré depuis le paywall.</li><li> **subscriptionUpdateParams** : un objet [`AdaptySubscriptionUpdateParameters`](ff-resources#adaptysubscriptionupdateparameters) utilisé pour mettre à niveau ou rétrograder un abonnement (à utiliser pour Android).</li><li>**isOfferPersonalized** : indique si l'offre est personnalisée pour l'acheteur (à utiliser pour Android).</li></ul> | [AdaptyMakePurchaseResult](ff-resources#adaptymakepurchaseresult) | | <p id="getprofile">getProfile</p> | <p>Récupère le profil de l'utilisateur actuel de l'application. Cela vous permet de définir les niveaux d'accès et d'autres paramètres</p><p>En cas d'échec (par ex. absence de connexion internet), les données en cache sont renvoyées. Adapty met régulièrement à jour le cache du profil pour que les informations restent aussi actuelles que possible</p> | Aucun | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | updateProfile | Modifie les attributs optionnels du profil de l'utilisateur actuel, comme l'adresse e-mail, le numéro de téléphone, etc. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou les consulter dans le CRM | L'ID et les paramètres à mettre à jour pour l'[AdaptyProfile](ff-resources#adaptyprofile) | [AdaptyError](ff-resources#adaptyerror) (Optionnel) | | restorePurchases | Restaure tous les achats effectués par l'utilisateur | Aucun | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | logShowPaywall | Enregistre l'affichage d'un paywall spécifique à l'utilisateur | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyError](ff-resources#adaptyerror) (Optionnel) | | identify | Identifie l'utilisateur à l'aide du `customerUserId` de votre système | customerUserId | [AdaptyError](ff-resources#adaptyerror) (Optionnel) | | logout | Déconnecte l'utilisateur actuel de votre application | Aucun | [AdaptyError](ff-resources#adaptyerror) (Optionnel) | | presentCodeRedemptionSheet | Affiche une feuille permettant aux utilisateurs de saisir des codes de remboursement (iOS uniquement) | Aucun | Aucun | ## Types de données \{#data-types\} Les types de données Adapty (collections de valeurs de données) transmis à FlutterFlow via le plugin Adapty. ### AdaptyAccessLevel Informations sur le [niveau d'accès](access-level) de l'utilisateur. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | activatedAt | DateTime | L'heure à laquelle ce niveau d'accès a été activé | | activeIntroductoryOfferType | String | Le type d'offre de lancement active. Si défini, cela signifie qu'une offre a été appliquée durant cette période d'abonnement | | activePromotionalOfferId | String | L'identifiant de l'offre promotionnelle active (achetée depuis iOS) | | activePromotionalOfferType | String | Le type d'offre promotionnelle active (achetée depuis iOS). Si défini, cela signifie qu'une offre a été appliquée durant cette période d'abonnement | | billingIssueDetectedAt | DateTime | L'heure à laquelle un problème de facturation a été détecté. L'abonnement peut toujours être actif. Défini à null si le paiement est traité avec succès | | cancellationReason | String | La raison pour laquelle l'abonnement a été annulé | | expiresAt | DateTime | La date d'expiration du niveau d'accès (peut être dans le passé ou non définie pour un accès à vie) | | id | String | L'identifiant du niveau d'accès | | isActive | Boolean | True si ce niveau d'accès est actif. En général, vous pouvez vérifier cette propriété pour déterminer si un utilisateur a accès aux fonctionnalités premium | | isInGracePeriod | Boolean | True si cet abonnement auto-renouvelable est en [délai de grâce](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions) | | isLifetime | Boolean | True si ce niveau d'accès est actif à vie (sans date d'expiration) | | isRefund | Boolean | True si cet achat a été remboursé | | offerId | String | L'identifiant de l'offre promotionnelle active (achetée depuis Android) | | renewedAt | DateTime | L'heure du dernier renouvellement du niveau d'accès | | startsAt | DateTime | L'heure de début de ce niveau d'accès (peut être dans le futur) | | store | String | Le store où l'achat a été effectué | | unsubscribedAt | DateTime | L'heure à laquelle le renouvellement automatique a été désactivé pour l'abonnement. L'abonnement peut toujours être actif. Si non défini, l'utilisateur a réactivé l'abonnement | | vendorProductId | String | L'identifiant du produit dans le store qui a déverrouillé ce niveau d'accès | | willRenew | Boolean | True si cet abonnement auto-renouvelable est configuré pour se renouveler | ### AdaptyAccessLevelIdentifiers Cette structure est destinée à remplacer la paire clé-valeur pour `Map<String, AdaptyAccessLevel` [AdaptyAccessLevel](ff-resources#adaptyaccesslevel). | Nom du champ | Type | Description | |------------|------|-------------| | accessLevelIdentifier | String | L'identifiant du niveau d'accès | | accessLevel | Data ([AdaptyAccessLevel](ff-resources#adaptyaccesslevel)) | Le [AdaptyAccessLevel](ff-resources#adaptyaccesslevel) associé | ### AdaptyCustomDoubleAttribute Informations sur les attributs double personnalisés définis pour l'[utilisateur](ff-resources#adaptyprofile). | Nom du champ | Type | Description | |--------------|------|-------------| | key | String | L'identifiant de l'attribut double personnalisé | | value | Double | La valeur de l'attribut double personnalisé | ### AdaptyCustomStringAttribute Informations sur les attributs de chaîne personnalisés définis pour l'[utilisateur](ff-resources#adaptyprofile). | Field Name | Type | Description | |------------|------|-------------| | key | String | L'identifiant de l'attribut de chaîne personnalisé | | value | String | La valeur de l'attribut de chaîne personnalisé | ### AdaptyError Contient les détails d'une erreur. Pour la liste complète des codes d'erreur, consultez [React Native, Flutter, Unity - Gérer les erreurs](error-handling-on-flutter-react-native-unity). | Nom du champ | Type | Description | |--------------------------|----------|-------------| | errorMessage | String | Une description lisible de l'erreur | | errorCode | Integer | Code numérique identifiant l'erreur | ### AdaptyGetIntroEligibilitiesResult Contient le résultat de l'action personnalisée `getProductsIntroductoryOfferEligibility`. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | value | List < Data ([AdaptyProductIntroEligibility](ff-resources#adaptyproductintroeligibility)) > | Liste des éligibilités de l'utilisateur aux offres de lancement | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | Contient les détails de l'erreur via [`AdaptyError`](ff-resources#adaptyerror) | ### AdaptyGetPaywallResult Contient le résultat de l'action personnalisée `getPaywall`. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | value | Data ([AdaptyPaywall](ff-resources#adaptypaywall)) | Contient une liste d'objets [AdaptyPaywall](ff-resources#adaptypaywall) | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | Contient les informations d'erreur via [AdaptyError](ff-resources#adaptyerror) | ### AdaptyGetProductsResult Contient le résultat de l'action personnalisée `getPaywallProducts`. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | value | List < Data ([AdaptyPaywallProduct](product)) > | Contient une liste d'[AdaptyPaywallProducts](product) | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | Contient les informations d'erreur via [AdaptyError](ff-resources#adaptyerror) | ### AdaptyGetProfileResult Contient le résultat de l'action personnalisée `getProfile`. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | value | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | Contient le profil utilisateur sous forme d'[AdaptyProfile](ff-resources#adaptyprofile) | | error | Data (AdaptyError) | Contient les informations d'erreur via [AdaptyError](ff-resources#adaptyerror) | ### AdaptyMakePurchaseResult Contient le résultat de l'action personnalisée `makePurchase`. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | value | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | Contient le profil de l'utilisateur sous forme d'[AdaptyProfile](ff-resources#adaptyprofile) | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | Contient les informations d'erreur via [AdaptyError](ff-resources#adaptyerror) | ### AdaptyNonSubscription Informations sur les achats non liés à un abonnement. Il peut s'agir d'achats uniques (consommables), de déverrouillages (comme un nouveau niveau dans un jeu), etc. | Nom du champ | Type | Description | |--------------------------|----------|-------------| | isConsumable | Boolean | Indique si le produit est consommable | | isOneTime | Boolean | Indique si le produit est un achat unique (par exemple, si true, l'achat n'est traité qu'une seule fois) | | isRefund | Boolean | Indique si le produit a été remboursé | | isSandbox | Boolean | Indique si le produit a été acheté dans un environnement sandbox | | purchasedAt | DateTime | L'heure à laquelle le produit a été acheté | | purchaseId | String | L'ID de l'achat dans Adapty. Peut être utilisé pour suivre les produits à achat unique | | store | String | Le store où le produit a été acheté (par exemple, App Store, Google Play) | | vendorProductId | String | ID du produit dans le système du vendeur | | vendorTransactionId | String | ID de transaction dans le système du vendeur | ### AdaptyPaywall Informations sur un [paywall](paywalls). | Nom du champ | Type | Description | |----------------------|----------|-------------| | abTestName | String | Le nom du test A/B parent | | hasViewConfiguration | Boolean | Indique s'il existe une configuration d'affichage pour le paywall | | locale | String | L'identifiant de locale du paywall | | name | String | Nom du paywall | | placement.id | String | L'identifiant du placement parent | | remoteConfigString | String | Un dictionnaire personnalisé depuis l'Adapty Dashboard associé à ce paywall | | placement.revision | Integer | La révision/version actuelle du paywall. Chaque modification génère une nouvelle révision | | variationId | String | L'identifiant de variante utilisé pour attribuer les achats à ce paywall | | vendorProductIds | String | Tableau des identifiants de produits associés au paywall | ### AdaptyPaywallProduct Informations sur le [produit](product). | Nom du champ | Type | Description | | -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | vendorProductId | String | L'ID d'un produit dans un store | | localizedDescription | String | Une description du produit dans la langue de l'utilisateur | | localizedTitle | String | Le nom du produit dans la langue de l'utilisateur | | regionCode | String | Le code région de la locale utilisée pour formater le prix du produit (pour iOS) | | isFamilyShareable | Boolean | Une valeur booléenne indiquant si le produit est disponible pour le partage familial dans App Store Connect. Sera toujours FALSE pour les versions iOS inférieures à 14.0 et macOS inférieures à 11.0 (pour iOS) | | paywallVariationId | String | L'ID d'une variante, utilisé pour attribuer les achats à ce paywall | | paywallABTestName | String | Nom du test A/B parent | | paywallName | String | Nom du paywall parent | | price | Data ([AdaptyPriceData](#adaptyprice) | Le prix du produit | | subscriptionDetails | Data ([AdaptySubscriptionDetails](#adaptysubscriptiondetails)) | Informations sur l'abonnement | ### AdaptyPrice Informations sur le prix du produit. | Nom du champ | Type | Description | | --------------- | ------ | -------------------------------------------------- | | amount | Double | La valeur numérique du prix | | currencyCode | String | Le code de la devise du prix | | currencySymbol | String | Le symbole utilisé pour la devise | | localizedString | String | Le prix affiché dans la langue de l'utilisateur | ### AdaptyProductIntroEligibility Définit si l'utilisateur est éligible à une offre de lancement pour un abonnement iOS. | Field Name | Type | Description | | --------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | | vendorProductId | String | L'ID d'un produit dans un store | | eligibility | [AdaptyEligibilityEnum](ff-resources#adaptyeligibilityenum) | Indique si l'utilisateur est éligible à une offre de lancement pour un abonnement iOS | ### AdaptyProductNonsubscriptions Détails de l'achat unique actif associé à ce produit. | Nom du champ | Type | Description | | ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | | productId | String | L'identifiant du produit dans le store | | nonsubscriptions | [AdaptyNonSubscription](ff-resources#adaptynonsubscription) | Informations sur les achats hors abonnement. Il peut s'agir de produits achetés une seule fois (consommables), de déverrouillages (comme un nouveau niveau dans un jeu), etc. | ### AdaptyProductSubscriptions Détails de l'abonnement actif lié à ce produit. | Nom du champ | Type | Description | | ------------ | ----------------------------------------------------- | --------------------------------------------------- | | productId | String | L'ID du produit dans un store | | subscription | [AdaptySubscription](ff-resources#adaptysubscription) | Informations sur les achats d'abonnement | ### AdaptyProfile Informations sur le profil de l'utilisateur | Field Name | Type | Description | | ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | accessLevels | List < Data ([AdaptyAccessLevelIdentifiers](ff-resources#adaptyaccesslevelidentifiers)) > | Liste de tous les niveaux d'accès appartenant à l'utilisateur | | profileId | String | L'identifiant du profil utilisateur | | customerUserId | String | L'identifiant de l'utilisateur dans le système du vendeur | | subscriptions | List < Data ([MapKeySubscriptions](#mapkeysubscriptions)) > | La liste de tous les abonnements achetés par l'utilisateur | | nonSubscriptions | List < Data ([MapKeyNonSubscriptions](#mapkeynonsubscriptions)) > | La liste de tous les produits hors abonnement achetés par l'utilisateur | ### AdaptyProfileParameters Informations sur l'utilisateur. | Nom du champ | Type | Description | | ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | firstName | String | Le prénom de l'utilisateur | | lastName | String | Le nom de famille de l'utilisateur | | gender | [AdaptyGenderEnum](#adaptygenderenum) | Le genre de l'utilisateur | | birthday | String | La date de naissance de l'utilisateur | | email | String | L'e-mail de l'utilisateur | | phoneNumber | String | Le numéro de téléphone de l'utilisateur | | facebookAnonymousId | String | L'identifiant de l'utilisateur dans l'[intégration Facebook Ads](facebook-ads) | | amplitudeUserId | String | L'identifiant de l'utilisateur dans l'[intégration Amplitude](amplitude) | | amplitudeDeviceId | String | L'identifiant de l'appareil de l'utilisateur dans l'[intégration Amplitude](amplitude) | | mixpanelUserId | String | L'identifiant de l'utilisateur dans l'[intégration Mixpanel](mixpanel) | | appmetricaProfileId | String | L'identifiant de l'utilisateur dans l'[intégration AppMetrica](appmetrica) | | appmetricaDeviceId | String | L'identifiant de l'appareil de l'utilisateur dans l'[intégration AppMetrica](appmetrica) | | oneSignalPlayerId | String | L'identifiant de l'utilisateur dans l'[intégration OneSignal](onesignal) | | pushwooshHWID | String | L'identifiant de l'appareil de l'utilisateur dans l'[intégration Pushwoosh](pushwoosh) | | firebaseAppInstanceId | String | L'identifiant de l'utilisateur dans l'[intégration Firebase](firebase-and-google-analytics) | | airbridgeDeviceId | String | L'identifiant de l'appareil de l'utilisateur dans l'[intégration Airbridge](airbridge) | | appTrackingTransparencyStatus | AdaptyATTStatus | Le statut de l'accès à l'IDFA (à utiliser pour iOS) | | analyticsDisabled | Boolean | Indique si l'[analytics externe est désactivé pour l'utilisateur](analytics-integration#disabling-external-analytics-for-a-specific-customer) | | customStringAttributes | List < Data ([AdaptyCustomStringAttribute](ff-resources#adaptycustomstringattribute)) > | Liste des attributs de chaîne personnalisés de l'utilisateur | | customDoubleAttributes | List < Data ([AdaptyCustomDoubleAttribute](ff-resources#adaptycustomdoubleattribute)) > | Liste des attributs double personnalisés de l'utilisateur | ### AdaptySubscription Informations sur l'abonnement existant de l'utilisateur. | Nom du champ | Type | Description | | --------------------------- | -------- | ------------------------------------------------------------ | | activatedAt | DateTime | L'heure à laquelle cet abonnement a été activé | | activeIntroductoryOfferType | String | Le type d'offre de lancement active. Si défini, cela signifie qu'une offre a été appliquée pendant cette période d'abonnement | | activePromotionalOfferId | String | L'identifiant d'une offre promotionnelle active (à utiliser pour iOS) | | activePromotionalOfferType | String | Le type d'offre promotionnelle active (à utiliser pour iOS). Si défini, cela signifie qu'une offre a été appliquée pendant cette période d'abonnement | | cancellationReason | String | La raison pour laquelle l'abonnement a été annulé | | expiresAt | DateTime | La date d'expiration de l'abonnement | | renewedAt | DateTime | La dernière heure de renouvellement de l'abonnement | | unsubscribedAt | DateTime | L'heure à laquelle le renouvellement automatique a été désactivé pour l'abonnement. L'abonnement peut encore être actif. Si non défini, l'utilisateur a réactivé l'abonnement | | billingIssueDetectedAt | DateTime | L'heure à laquelle un problème de facturation a été détecté. L'abonnement peut encore être actif. Défini à null si le paiement est traité avec succès | | isActive | Boolean | True si cet abonnement est actif. En général, vous pouvez vérifier cette propriété pour déterminer si un utilisateur a accès aux fonctionnalités premium | | isInGracePeriod | Boolean | True si cet abonnement à renouvellement automatique est en [délai de grâce](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions) | | isLifetime | Boolean | True si cet abonnement est actif à vie (sans date d'expiration) | | isRefund | Boolean | True si cet achat a été remboursé | | isSandbox | Boolean | Indique si le produit a été acheté dans un environnement sandbox | | offerId | String | L'identifiant d'une offre promotionnelle active (à utiliser pour Android) | | startsAt | DateTime | L'heure de début de ce niveau d'accès (peut être dans le futur) | | store | String | Le store où le produit a été acheté (ex. : App Store, Google Play) | | vendorOriginalTransactionId | String | Identifiant de l'abonnement initial dans le système du fournisseur | | vendorProductId | String | Identifiant du produit dans le système du fournisseur | | vendorTransactionId | String | Identifiant de la transaction dans le système du fournisseur | | willRenew | Boolean | True si cet abonnement à renouvellement automatique est configuré pour se renouveler | ### AdaptySubscriptionDetails Schéma d'un objet Subscription faisant partie de [AdaptyPaywallProduct](product). | Nom du champ | Type | Description | | ----------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | androidBasePlanId | String | [ID du plan de base](https://support.google.com/googleplay/android-developer/answer/12154973) dans le Google Play Store ou [ID de prix](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) dans Stripe. | | androidIntroductoryOfferEligibility | [AdaptyEligibilityEnum](ff-resources#adaptyeligibilityenum) | Indique si l'utilisateur est éligible à une offre de lancement pour un abonnement iOS | | androidOfferId | String | L'ID d'une offre promotionnelle active (à utiliser pour Android) | | androidOfferTags | List < String > | Liste des [tags personnalisés](https://developers.google.com/android-publisher/api-ref/rest/v3/OfferTag) spécifiés pour les plans de base et les offres d'abonnement. | | introductoryOffer | List < Data ([AdaptySubscriptionPhase](ff-resources#adaptysubscriptionphase)) > | L'ID d'une offre de lancement (à utiliser pour iOS) | | localizedSubscriptionPeriod | String | La durée de l'abonnement dans la langue de l'utilisateur | | promotionalOffer | Data ([AdaptySubscriptionPhase](ff-resources#adaptysubscriptionphase)) | Les détails de l'offre promotionnelle (à utiliser pour iOS) | | promotionalOfferEligibility | Boolean | Indique si l'utilisateur est éligible à une offre promotionnelle pour un abonnement iOS | | promotionalOfferId | String | L'ID de l'offre promotionnelle (à utiliser pour iOS) | | renewalType | [AdaptyRenewalTypeEnum](#adaptyrenewaltypeenum) | Indique si l'abonnement est à renouvellement automatique ou non via [AdaptyRenewalTypeEnum](ff-resources#adaptyrenewaltypeenum) | | subscriptionGroupIdentifier | String | L'ID du groupe de produits auquel appartient le produit (à utiliser pour iOS) | | subscriptionPeriod | Data ([AdaptySubscriptionPeriod](#adaptysubscriptionperiod)) | La durée de l'abonnement | ### AdaptySubscriptionPeriod La durée de l'abonnement. | Field Name | Type | Description | | ------------- | --------------------------------------------- | ----------------------------------------------------------- | | numberOfUnits | Integer | Nombre de jours/semaines/mois/années que dure l'abonnement. | | unit | [AdaptyPeriodUnitEnum](#adaptyperiodunitenum) | Unité de mesure de la période : jours, semaines, mois, années. | ### AdaptySubscriptionPhase Représente une phase d'abonnement, comme un essai gratuit ou une période d'offre de lancement. | Nom du champ | Type | Description | | --------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | identifier | String | L'identifiant de la phase | | localizedNumberOfPeriods | String | La durée de la phase. Par exemple, une offre de 6 mois s'affichera comme `6 months` dans la langue de l'utilisateur. | | localizedSubscriptionPeriod | String | La durée de l'abonnement dans la langue de l'utilisateur, par exemple `3 months`. | | numberOfPeriods | Integer | Le nombre de périodes d'abonnement dans cette phase. Par exemple, une offre de 6 mois comprend deux périodes de 3 mois. | | paymentMode | [AdaptyPaymentModeEnum](#adaptypaymentmodeenum) | Le mode de paiement utilisé pour cette phase. | | price | Data ([AdaptyPrice](#adaptyprice)) | Le prix de cette phase. | | subscriptionPeriod | Data ([AdaptySubscriptionPeriod](#adaptysubscriptionperiod)) | La période d'abonnement sur laquelle cette phase est basée. | ### AdaptySubscriptionUpdateParameters (*Android uniquement*) Paramètres pour remplacer un abonnement par un autre. | Field Name | Type | Description | | ---------- | ------------------------------------------------------------ | ---------- | | oldSubVendorProductId | String | L'ID de l'abonnement actuel dans le Play Store que vous souhaitez remplacer. | | replacementMode | [AdaptySubscriptionUpdateReplacementMode](ff-resources#adaptysubscriptionupdatereplacementmode) | Enum qui correspond aux valeurs de [`BillingFlowParams.ProrationMode`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode). | ### MapKeyNonSubscriptions Remplacement d'un dictionnaire pour [AdaptyNonSubscription](ff-resources#adaptynonsubscription). | Nom du champ | Type | | ------------ | ------------------------------------------------------------ | | key | String | | value | List < Data ([AdaptyNonSubscription](ff-resources#adaptynonsubscription)) > | ### MapKeySubscriptions Remplacement d'un dictionnaire pour [AdaptySubscription](ff-resources#adaptysubscription). | Field Name | Type | | ---------- | ------------------------------------------------------------ | | key | String | | value | List < Data ([AdaptySubscription](ff-resources#adaptysubscription)) > | ## Enums \{#enums\} Les enums Adapty (variables correspondant à des ensembles de constantes prédéfinies) sont transmis à FlutterFlow via le plugin Adapty. ### AdaptyEligibilityEnum Définit si l'utilisateur est éligible à une offre de lancement pour un abonnement iOS. | Nom du champ | Description | |--------------------------|-------------| | eligible | L'utilisateur est éligible à une offre de lancement ; vous pouvez afficher cette information dans votre interface | | ineligible | L'utilisateur n'est pas éligible à une offre ; vous ne devez pas l'afficher dans votre interface | | notApplicable | Ce produit n'est pas configuré pour proposer une offre | ### AdaptyGenderEnum Définit le genre de l'utilisateur. | Field Name | Description | | ---------- | -------------------------------------------------- | | none | Le genre n'est pas défini | | female | Le genre de l'utilisateur est féminin | | male | Le genre de l'utilisateur est masculin | | Other | L'utilisateur a défini son genre comme « autre » | ### AdaptyPaymentModeEnum Définit le modèle de paiement. | Nom du champ | Description | | ------------ | ------------------------------------------------------------ | | payAsYouGo | Un modèle de tarification où les clients sont facturés en fonction de leur utilisation réelle d'un produit/service, plutôt que de payer un montant fixe à l'avance | | payUpFront | Un modèle de tarification où les clients sont facturés avant de recevoir le produit/service. | | freeTrial | L'utilisateur est en période d'essai gratuit | | unknown | Le modèle de tarification n'est pas défini | ### AdaptyPeriodUnitEnum Définit les unités de mesure des périodes. | Field Name | Description | | ---------- | --------------- | | day | En jours | | week | En semaines | | month | En mois | | year | En années | | unknown | Non défini | ### AdaptyRenewalTypeEnum Définit si l'abonnement est à renouvellement automatique ou non. | Field Name | Description | | ------------- | -------------------------------------------------------------- | | prepaid | L'abonnement est prépayé et n'est pas à renouvellement automatique. | | autorenewable | L'abonnement est à renouvellement automatique. | ### AdaptySubscriptionUpdateReplacementMode Définit le mode de mise à jour d'abonnement pour Android. | Nom du champ | Description | | --------------- | --------------------------------------------------- | | withTimeProration | (par défaut) Le nouveau plan prend effet immédiatement, et le temps restant est calculé au prorata et crédité à l'utilisateur. | | chargeProratedPrice | Le nouveau plan prend effet immédiatement, et le cycle de facturation reste identique. Le prix pour la période restante est facturé. Cette option est uniquement disponible pour les mises à niveau d'abonnement. | | withoutProration | Le nouveau plan prend effet immédiatement, et le nouveau prix sera facturé à la prochaine date de renouvellement. Le cycle de facturation reste identique. | | deferred | Le nouvel achat prend effet immédiatement, et le nouveau plan entrera en vigueur à l'expiration de l'ancien article. | | chargeFullPrice | Le nouveau plan prend effet immédiatement, et le cycle de facturation reste identique. Le prix pour la période restante est facturé. Cette option est uniquement disponible pour les mises à niveau d'abonnement. | ### États de l'application \{#app-states\} Les variables d'état de l'application sont des variables spécifiques qui contiennent l'état actuel d'une application. Elles sont accessibles et modifiables dans toute l'application, sur toutes les pages et dans tous les composants. Ce type de variable est utile pour stocker des données devant être partagées entre différentes parties de l'app, comme les préférences utilisateur et les jetons d'authentification. | Nom du champ | Type de données | Persisté | Description | | -------------- | -------------------------------------------------- | --------- | ------------------------------------------------------------ | | currentProfile | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | False | La variable contenant les informations sur le profil utilisateur actuel. Gardez-la à jour. | --- # End of Documentation _Generated on: 2026-08-04T15:08:26.308Z_ _Successfully processed: 319/319 files_ # UNITY - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-04T15:08:26.316Z Total files: 52 --- # File: unity-sdk-overview --- --- title: "Vue d'ensemble du SDK Unity" description: "Découvrez le SDK Adapty pour Unity et ses principales fonctionnalités." --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Unity.svg?style=flat&logo=unity)](https://github.com/adaptyteam/AdaptySDK-Unity/releases) Bienvenue ! Nous sommes là pour simplifier vos achats intégrés 🚀 Nous avons conçu le SDK Unity Adapty pour vous libérer des tracas des achats intégrés, afin que vous puissiez vous concentrer sur ce que vous faites de mieux : créer des jeux extraordinaires. Voici ce que nous gérons pour vous : - Gestion des achats, validation des reçus et gestion des abonnements prêts à l'emploi - Créez et testez des paywalls sans mettre à jour l'application - Obtenez des analyses d'achats détaillées sans configuration - cohortes, LTV, churn et analyse de tunnel inclus - Maintenez le statut d'abonnement de l'utilisateur toujours à jour entre les sessions et les appareils - Intégrez votre application à des services d'attribution marketing et d'analytique en une seule ligne de code :::note Avant de vous plonger dans le code, vous devrez intégrer Adapty avec App Store Connect et Google Play Console, puis configurer des produits dans le tableau de bord. Consultez notre [guide de démarrage rapide](quickstart) pour tout configurer d'abord. ::: ## Pour commencer \{#get-started\} For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. Voici ce que nous allons couvrir dans ce guide d'intégration : 1. [Installer et configurer le SDK](sdk-installation-unity) : Ajoutez le SDK en tant que dépendance à votre projet et activez-le dans le code. 2. [Activer les achats via les flows](unity-quickstart-paywalls) : Configurez le flow d'achat pour que les utilisateurs puissent acheter des produits. Pour créer votre propre interface, consultez plutôt [Implémenter les paywalls manuellement](unity-quickstart-manual). 3. [Vérifier le statut de l'abonnement](unity-check-subscription-status) : Vérifiez automatiquement l'état de l'abonnement de l'utilisateur et contrôlez son accès au contenu payant. 4. [Identifier les utilisateurs (facultatif)](unity-quickstart-identify) : Associez les utilisateurs à leurs profils Adapty pour garantir que leurs données sont enregistrées de manière cohérente sur tous leurs appareils. ### Voir en action \{#see-it-in-action\} Envie de voir comment tout s'assemble ? On vous a préparé ça : - **Exemple d'application** : Consultez notre [exemple complet](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) qui illustre la configuration complète ## Concepts clés \{#main-concepts\} Avant de plonger dans le code, familiarisons-nous avec les concepts clés qui font fonctionner Adapty. L'avantage de l'approche Adapty, c'est que seuls les placements sont codés en dur dans votre app. Tout le reste – produits, designs de paywall, tarifs et offres – peut être géré de manière flexible depuis l'Adapty Dashboard, sans mise à jour de l'app : 1. [**Produit**](product) - Tout ce qui est disponible à l'achat dans votre app – abonnement, produit consommable ou accès à vie. 2. **Flow ou paywall** - Produits regroupés avec une configuration, attachés à un placement. Deux options : - **[Flow](adapty-flow-builder)** - Interface visuelle no-code construite dans le Flow Builder. Adapty génère l'interface et gère l'achat pour vous. - **[Paywall](paywalls)** - Pas de configuration visuelle ; vous construisez l'interface dans votre propre code et appelez `MakePurchase` vous-même. Voir [Implémenter les paywalls manuellement](unity-quickstart-manual). Dans le code du SDK, les deux sont récupérés via la même méthode `GetFlow`. 3. [**Placement**](placements) - Un point stratégique dans le parcours utilisateur où vous souhaitez afficher un flow ou un paywall. Les placements représentent le « où » et le « quand » de votre stratégie de monétisation. Voici quelques placements courants : - `main` - Votre emplacement principal de paywall - `onboarding` - Affiché pendant le flow d'onboarding - `settings` - Accessible depuis les paramètres de votre application Commencez par les basiques comme `main` ou `onboarding` pour votre première intégration, puis [réfléchissez aux autres endroits de votre application où les utilisateurs pourraient être prêts à acheter](choose-meaningful-placements). 4. [**Profil**](profiles-crm) - Lorsque les utilisateurs achètent un produit, un **niveau d'accès** est attribué à leur profil, ce qui vous permet de définir l'accès aux fonctionnalités payantes. --- # File: sdk-installation-unity --- --- title: "Installer et configurer le SDK Unity" description: "Guide étape par étape pour installer le SDK Adapty sur Unity pour les applications basées sur des abonnements." --- Le SDK Adapty comprend deux modules essentiels pour une intégration fluide dans votre application Unity : - **Core Adapty** : ce SDK de base est nécessaire au bon fonctionnement d'Adapty dans votre application. - **AdaptyUI** : ce module est requis si vous utilisez le [Paywall Builder d'Adapty](adapty-paywall-builder), un outil no-code convivial pour créer facilement des paywalls multiplateformes. :::tip Vous voulez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez notre [application exemple](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets), qui illustre la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Prérequis \{#requirements\} Le SDK Adapty est compatible avec iOS 13.0+, mais nécessite iOS 15.0+ pour utiliser les paywalls créés dans le Paywall Builder. Le SDK Adapty 4.0 (bêta) — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — exige **iOS 15.0+** pour l'ensemble de l'application : un validateur de build dans l'Unity Editor bloque la compilation iOS si la cible de déploiement est inférieure. :::info Adapty est compatible avec Google Play Billing Library jusqu'à la version 8.x. Par défaut, Adapty utilise la version 7.0.0 de Google Play Billing Library. Pour utiliser une version plus récente, [remplacez la dépendance Billing](https://developer.android.com/google/play/billing/integrate#dependency) dans votre build Android. ::: :::info L'installation du SDK correspond à l'étape 5 de la configuration d'Adapty. Avant que les achats fonctionnent dans votre app, vous devez également connecter votre app aux stores, puis créer des produits, un paywall et un placement dans l'Adapty Dashboard. Le [guide de démarrage rapide](quickstart) décrit toutes les étapes requises. ::: ## Installer le SDK 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) Choisissez votre méthode d'installation préférée : <Tabs groupId="unity-install-method"> <TabItem value="git-url" label="Git URL"> Installez le SDK Adapty via Unity Package Manager en utilisant une URL Git : 1. Dans Unity, ouvrez **Window → Package Manager**. 2. Cliquez sur **+** en haut à gauche, puis sélectionnez **Add package from git URL...**. 3. Saisissez l'URL suivante et cliquez sur **Add** : ``` https://github.com/adaptyteam/AdaptySDK-Unity.git?path=/Packages/com.adapty.unity-sdk ``` Pour plus de détails, consultez le guide Unity sur [l'installation d'un package UPM depuis une URL Git](https://docs.unity3d.com/Manual/upm-ui-giturl.html). </TabItem> <TabItem value="unity-package" label="Unity package" default> Téléchargez le [`adapty-unity-plugin-*.unitypackage`](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Releases) depuis GitHub et importez-le dans votre projet. <img src="/assets/shared/img/456bd98-adapty-unity-plugin.webp" style={{ border: 'none', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </TabItem> </Tabs> Après avoir installé le SDK, effectuez les étapes suivantes : 1. Installez le [plugin External Dependency Manager (EDM)](https://github.com/googlesamples/unity-jar-resolver#getting-started). Le SDK Adapty l'utilise pour gérer les dépendances iOS et les dépendances gradle Android. 2. Après avoir installé EDM, vous devrez peut-être invoquer le gestionnaire de dépendances : `Assets -> External Dependency Manager -> Android Resolver -> Force Resolve` et `Assets -> External Dependency Manager -> iOS Resolver -> Install Cocoapods` 3. Lors de la compilation de votre projet Unity pour iOS, vous obtiendrez un fichier `Unity-iPhone.xcworkspace`, que vous devez ouvrir à la place de `Unity-iPhone.xcodeproj`, sinon les dépendances Cocoapods ne seront pas utilisées. ### Adapty SDK 4.0 (bêta) SDK 4.0 — qui ajoute la prise en charge du [Flow Builder](adapty-flow-builder) — est une version préliminaire. Pour l'installer via le Unity Package Manager, ajoutez le tag bêta à l'URL Git : ``` https://github.com/adaptyteam/AdaptySDK-Unity.git?path=/Packages/com.adapty.unity-sdk#4.0.0-beta.1 ``` Si vous installez via le package Unity, téléchargez `adapty-unity-plugin-4.0.0-beta.1.unitypackage` depuis la [version 4.0.0-beta.1](https://github.com/adaptyteam/AdaptySDK-Unity/releases/tag/4.0.0-beta.1). Deux modifications de configuration s'accompagnent de la v4 — le SDK natif iOS d'Adapty est déclaré en tant que package Swift distant et ne s'installe plus via CocoaPods : - Mettez à jour l'External Dependency Manager vers la version **1.2.188 ou ultérieure** — les versions antérieures ne prennent pas en charge les dépendances Swift Package Manager. C'est la version que le SDK 4.0 déclare comme dépendance pair, donc Unity vous avertit si votre projet en possède une plus ancienne. - Les étapes CocoaPods ci-dessus (`iOS Resolver -> Install Cocoapods`, ouverture de `Unity-iPhone.xcworkspace`) s'appliquent uniquement au SDK 3.x. Avec le SDK 4.0, EDM ajoute automatiquement le package Swift au projet Xcode généré. - Définissez la cible de déploiement iOS à **15.0 ou ultérieure**. Un validateur de build dans l'éditeur Unity bloque sinon le build iOS. Consultez le [guide de migration](migration-to-unity-sdk-v4) pour la liste complète des changements du SDK 4.0. ## Activer le module Adapty du SDK \{#activate-adapty-module-of-adapty-sdk\} Activez le SDK dans le code de votre application. :::note Le SDK n'a besoin d'être activé qu'une seule fois dans votre application. ::: Pour obtenir votre **Public SDK Key** : 1. Accédez à l'Adapty Dashboard et naviguez vers [**App settings → General**](https://app.adapty.io/settings/general). 2. Dans la section **Api keys**, copiez la **Public SDK Key** (et NON la Secret Key). 3. Remplacez `"YOUR_PUBLIC_SDK_KEY"` dans le code. Ou obtenez-la de façon programmatique via l'[Adapty CLI](developer-cli) : ``` npm install -g adapty adapty auth login adapty apps list ``` Ou, directement : ``` npx adapty auth login adapty apps list ``` - Assurez-vous d'utiliser la **Public SDK key** pour l'initialisation d'Adapty — la **Secret key** ne doit être utilisée que pour l'[API côté serveur](getting-started-with-server-side-api). - Les **SDK keys** sont propres à chaque application, donc si vous avez plusieurs applications, veillez à choisir la bonne. ```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) { } } ``` :::note Dans le SDK 4.0, les interfaces de listener suivent la convention de préfixe I du C# : implémentez `IAdaptyEventListener` plutôt que `AdaptyEventListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: :::important Attendez le callback de complétion d'`Activate` avant d'appeler toute autre méthode du SDK Adapty. Consultez [l'ordre d'appel dans le SDK Unity](unity-sdk-call-order) pour la séquence complète. ::: ## Configurer l'écoute des événements \{#set-up-event-listening\} Créez un script pour écouter les événements Adapty. Nommez-le `AdaptyListener` dans votre scène. Nous recommandons d'utiliser la méthode `DontDestroyOnLoad` sur cet objet pour qu'il persiste pendant toute la durée de vie de l'application. <img src="/assets/shared/img/2ccd564-create_adapty_listener.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty utilise le namespace `AdaptySDK`. En haut de vos fichiers de script qui utilisent le SDK Adapty, vous pouvez ajouter : ```csharp showLineNumbers title="C#" using AdaptySDK; ``` Abonnez-vous aux événements 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) { } } ``` Nous recommandons d'ajuster l'ordre d'exécution des scripts pour placer l'AdaptyListener avant Default Time. Cela garantit qu'Adapty s'initialise le plus tôt possible. <img src="/assets/shared/img/activate_unity.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Configurez maintenant les paywalls dans votre application : - Si vous utilisez le [Paywall Builder d'Adapty](adapty-paywall-builder), commencez par [activer le module AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) ci-dessous, puis suivez le [guide de démarrage rapide du Paywall Builder](unity-quickstart-paywalls). - Si vous créez votre propre interface de paywall, consultez le [guide de démarrage rapide pour les paywalls personnalisés](unity-quickstart-manual). ## Activer le module AdaptyUI du SDK Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Si vous prévoyez d'utiliser le [Paywall Builder](adapty-paywall-builder) et avez installé le module AdaptyUI, vous devez activer AdaptyUI. Vous pouvez l'activer lors de la configuration : ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetActivateUI(true); ``` ## Configuration optionnelle \{#optional-setup\} ### Journalisation \{#logging\} #### Configurer le système de journalisation \{#set-up-the-logging-system\} Adapty enregistre les erreurs et d'autres informations importantes pour vous aider à comprendre ce qui se passe. Les niveaux suivants sont disponibles : | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Seules les erreurs seront journalisées | | `warn` | Les erreurs et les messages du SDK qui ne causent pas d'erreurs critiques, mais méritent attention, seront journalisés | | `info` | Les erreurs, avertissements et divers messages d'information seront journalisés | | `verbose` | Toute information supplémentaire pouvant être utile lors du débogage, comme les appels de fonctions, les requêtes API, etc., sera journalisée | Vous pouvez définir le niveau de log dans votre application lors de la configuration d'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; ``` Vous pouvez également modifier le niveau de log à l'exécution : ```csharp showLineNumbers title="C#" Adapty.SetLogLevel(AdaptyLogLevel.Verbose, (error) => { // handle result }); ``` ### Politiques de données \{#data-policies\} Adapty ne stocke pas les données personnelles de vos utilisateurs sauf si vous les envoyez explicitement, mais vous pouvez mettre en place des politiques de sécurité des données supplémentaires pour vous conformer aux directives du store ou des pays. #### Désactiver la collecte et le partage des adresses IP \{#disable-ip-address-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `SetIPAddressCollectionDisabled` sur `true` pour désactiver la collecte et le partage des adresses IP des utilisateurs. La valeur par défaut est `false`. Utilisez ce paramètre pour renforcer la confidentialité des utilisateurs, vous conformer aux réglementations régionales de protection des données (comme le RGPD ou le CCPA), ou réduire la collecte de données inutiles lorsque les fonctionnalités basées sur l'adresse IP ne sont pas nécessaires pour votre application. ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetIPAddressCollectionDisabled(true); ``` #### Désactiver la collecte et le partage de l'identifiant publicitaire \{#disable-advertising-id-collection-and-sharing\} Lors de l'activation du module Adapty, définissez `SetAppleIDFACollectionDisabled` et/ou `SetGoogleAdvertisingIdCollectionDisabled` à `true` pour désactiver la collecte des identifiants publicitaires. La valeur par défaut est `false`. Utilisez ce paramètre pour respecter les politiques de l'App Store/Google Play, éviter de déclencher l'invite App Tracking Transparency, ou si votre application n'a pas besoin d'attribution publicitaire ni d'analytiques basées sur les identifiants publicitaires. ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleIDFACollectionDisabled(true) .SetGoogleAdvertisingIdCollectionDisabled(true); ``` #### Configurer le cache média pour AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Par défaut, AdaptyUI met en cache les médias (images et vidéos) pour améliorer les performances et réduire la consommation réseau. Vous pouvez personnaliser ces paramètres en fournissant une configuration personnalisée. Utilisez `SetAdaptyUIMediaCache` pour remplacer les paramètres de cache par défaut : ```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 ); ``` Paramètres : | Paramètre | Requis | Description | |-----------------------------|----------|-----------------------------------------------------------------------------------------------| | memoryStorageTotalCostLimit | optionnel | Taille totale du cache en mémoire en octets. Valeur par défaut spécifique à la plateforme. | | memoryStorageCountLimit | optionnel | Nombre maximal d'éléments dans le stockage en mémoire. Valeur par défaut spécifique à la plateforme. | | diskStorageSizeLimit | optionnel | Taille limite des fichiers sur disque en octets. Valeur par défaut spécifique à la plateforme. | ### Activer les niveaux d'accès locaux (Android) \{#enable-local-access-levels-android\} Par défaut, les [niveaux d'accès locaux](local-access-levels) sont activés sur iOS et désactivés sur Android. Pour les activer également sur Android, définissez `SetGoogleLocalAccessLevelAllowed` sur `true` : ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetGoogleLocalAccessLevelAllowed(true); ``` ### Effacer les données lors d'une restauration de sauvegarde \{#clear-data-on-backup-restore\} Lorsque `SetAppleClearDataOnBackup` est défini sur `true`, le SDK détecte quand l'application est restaurée depuis une sauvegarde iCloud et supprime toutes les données SDK stockées localement, notamment les informations de profil en cache, les détails des produits et les paywalls. Le SDK s'initialise ensuite dans un état propre. La valeur par défaut est `false`. :::note Seul le cache local du SDK est supprimé. L'historique des transactions avec Apple et les données utilisateur sur les serveurs Adapty restent inchangés. ::: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleClearDataOnBackup(true); ``` ## Dépannage \{#troubleshooting\} #### Règles de sauvegarde Android (configuration Auto Backup) \{#android-backup-rules-auto-backup-configuration\} Certains SDKs (dont Adapty) embarquent leur propre configuration Android Auto Backup. Si vous utilisez plusieurs SDKs qui définissent des règles de sauvegarde, la fusion du manifeste Android peut échouer avec une erreur mentionnant `android:fullBackupContent`, `android:dataExtractionRules` ou `android:allowBackup`. Symptômes typiques : `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 Ces modifications doivent être effectuées dans votre répertoire de la plateforme Android (généralement situé dans le dossier `android/` de votre projet). ::: Pour résoudre ce problème, vous devez : - Indiquer au gestionnaire de fusion de manifeste d'utiliser les valeurs de votre application pour les attributs liés à la sauvegarde. - Créer des fichiers de règles de sauvegarde qui fusionnent les règles d'Adapty avec celles des autres SDKs. #### 1. Ajoutez l'espace de noms `tools` à votre manifeste \{#1-add-the-tools-namespace-to-your-manifest\} Dans votre fichier `AndroidManifest.xml`, assurez-vous que la balise racine `<manifest>` inclut tools : ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. Remplacez les attributs de sauvegarde dans `<application>` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `<application>` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion de remplacer les valeurs des bibliothèques : ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` : ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Créez les fichiers de règles de sauvegarde fusionnés \{#3-create-merged-backup-rules-files\} Créez des fichiers XML dans le répertoire `res/xml/` de votre projet Android, en combinant les règles d'Adapty avec celles des autres SDKs. Android utilise des formats de règles de sauvegarde différents selon la version de l'OS, donc créer les deux fichiers garantit la compatibilité avec toutes les versions d'Android prises en charge par votre application. :::note Les exemples ci-dessous utilisent AppsFlyer comme exemple de SDK tiers. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application. ::: **Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) : ```xml title="sample_data_extraction_rules.xml" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::important Dans Unity, appliquez ces modifications à `Assets/Plugins/Android/AndroidManifest.xml` et créez les fichiers de règles de sauvegarde dans `Assets/Plugins/Android/res/xml/`. ::: #### Les achats échouent après un retour depuis une autre application sur Android \{#purchases-fail-after-returning-from-another-app-in-android\} Si l'Activity qui démarre le flow d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser incorrectement lorsque l'utilisateur revient depuis Google Play, une application bancaire ou un navigateur. Cela peut entraîner la perte du résultat d'achat ou son interprétation comme une annulation. Pour que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flow d'achat, et évitez tout autre mode. Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui démarre le flow d'achat est configurée sur `standard` ou `singleTop` : ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### L'application plante lors de l'affichage d'un paywall sur Android \{#app-crashes-when-a-paywall-is-displayed-on-android\} Si votre application plante sur Android lors de l'affichage d'un paywall, il est possible que le plugin Kotlin soit absent de votre configuration Gradle. Pour l'ajouter : 1. Dans **Player Settings**, assurez-vous que les options **Custom Launcher Gradle Template** et **Custom Base Gradle Template** sont sélectionnées. <img src="/assets/shared/img/kotlin-plugin1.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Ajoutez la ligne suivante à `/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. Ajoutez la ligne suivante dans `/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** } ``` --- # File: unity-quickstart-paywalls --- --- title: "Activer les achats avec Flow Builder dans le SDK Unity" description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder." --- Ce guide utilise les APIs du SDK Adapty Unity v4 (bêta). Si vous utilisez la v3, consultez le [guide de migration](migration-to-unity-sdk-v4) pour les noms de méthodes correspondants. Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Flows**](adapty-flow-builder) – séquences d'écrans qui présentent des produits aux utilisateurs, construites dans le Flow Builder sans code. Le SDK les récupère via `GetFlow`. Si vous préférez créer l'interface dans votre propre code, utilisez un paywall à la place — voir [Implémenter des paywalls manuellement](unity-quickstart-manual). - [**Placements**](placements) – où et quand vous affichez des flows dans votre application (par exemple `main`, `onboarding`, `settings`). Vous associez des flows à des placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs. Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond à vos besoins : | Implémentation | Complexité | Quand l'utiliser | |---|---|---| | Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder no-code](quickstart-paywalls). Adapty le rend automatiquement et gère en coulisses tout le flow d'achat, la validation des reçus et la gestion des abonnements. | | Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre application, mais récupérez tout de même l'objet flow depuis Adapty pour conserver une flexibilité dans les offres de produits. Consultez le [guide](unity-quickstart-manual). | | Mode Observer | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode Observer présente certaines limitations dans Adapty. Consultez l'[article](observer-vs-full-mode). | :::important **Les étapes ci-dessous montrent comment implémenter un flow créé dans l'Adapty Flow Builder.** Si vous préférez construire l'UI du paywall vous-même, consultez [Implémenter les paywalls manuellement](unity-quickstart-manual). ::: Pour afficher un flow créé dans l'Adapty Flow Builder, dans le code de votre application, il vous suffit de : 1. **Récupérer le flow** : Obtenez-le depuis Adapty. 2. **L'afficher et Adapty gérera les achats pour vous** : Affichez la vue dans votre application. 3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons. ## Avant de commencer \{#before-you-start\} Avant de commencer, effectuez ces étapes : 1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans Adapty Dashboard. 2. [Créez vos produits](create-product) dans Adapty. 3. [Créez un flow et ajoutez-y des produits](create-paywall). 4. [Créez un placement et ajoutez votre flow](create-placement). 5. [Installez et activez le SDK Adapty](sdk-installation-unity) dans le code de votre application. :::tip Le moyen le plus rapide d'effectuer ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des flows et des placements à l'aide du [CLI développeur](developer-cli-quickstart). ::: ## 1. Récupérer le flow \{#1-get-the-flow\} Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'afficher des flows différents selon les audiences ou de lancer des [tests A/B](ab-tests). Pour récupérer un flow créé dans l'Adapty Flow Builder, vous devez : 1. Récupérer l'objet `flow` par l'ID du [placement](placements) en utilisant la méthode `GetFlow`. 2. Créer la vue du flow à l'aide de la méthode `CreateFlowView`. La vue contient les éléments d'interface et le style nécessaires à l'affichage du flow. Si le flow n'a pas de vue configurée, `CreateFlowView` retourne une erreur — gérez-la dans le callback. :::important Pour afficher la vue, vous devez activer le bouton **Show on device** dans le Flow Builder. Sinon, `CreateFlowView` retournera une erreur et le flow ne s'affichera pas. ::: ```csharp showLineNumbers Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => { if (error != null) { // handle the error return; } // Create the flow view AdaptyUI.CreateFlowView(flow, (view, error) => { if (error != null) { // the flow has no view configured, or view creation failed return; } // view - the flow view ready to be presented }); }); ``` :::info Ce démarrage rapide fournit la configuration minimale requise pour afficher un flow. Pour les détails de configuration avancée, consultez notre [guide sur la récupération des flows](unity-get-pb-paywalls). ::: ## 2. Afficher le flow \{#2-display-the-flow\} Maintenant que vous avez la vue du flow, il suffit d'ajouter quelques lignes pour l'afficher. Pour afficher le flow, utilisez la méthode `view.Present()` sur le `view` créé par la méthode `CreateFlowView`. Chaque `view` ne peut être utilisé qu'une seule fois : après l'avoir fermé, appelez à nouveau `CreateFlowView` pour afficher le flow une nouvelle fois. ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::info Pour plus de détails sur la façon d'afficher un flow, consultez notre [guide](unity-present-paywalls). ::: ## 3. Gérer les actions des boutons \{#handle-button-actions\} Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Unity gère automatiquement les achats et la restauration. Cependant, d'autres boutons ont des identifiants personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Par exemple, votre flow dispose probablement d'un bouton de fermeture et d'URLs à ouvrir (par exemple, les conditions d'utilisation et la politique de confidentialité). Pour gérer ces actions, votre classe doit implémenter l'interface `IAdaptyFlowsEventsListener` et s'enregistrer en tant qu'écouteur. Notez que le flow reste ouvert après un achat réussi. Si vous souhaitez le fermer une fois l'achat terminé, fermez la vue dans le callback `FlowViewDidFinishPurchase`. :::tip Consultez nos guides sur la gestion des [actions](unity-handle-paywall-actions) et des [événements](unity-handling-events) de bouton. ::: ```csharp showLineNumbers title="Unity" public class YourClass : MonoBehaviour, IAdaptyFlowsEventsListener { void Start() { // Register this class as the flows events listener Adapty.SetFlowsEventsListener(this); } // IAdaptyFlowsEventsListener method - handles button actions public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: AdaptyUI.OpenUrl(action.Value, AdaptyWebPresentation.ExternalBrowser, null); break; default: break; } } // IAdaptyFlowsEventsListener method - dismiss the flow after a purchase public void FlowViewDidFinishPurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { if (purchasedResult.Type != AdaptyPurchaseResultType.UserCancelled) { view.Dismiss(null); } } } ``` ## Prochaines étapes :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre flow est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou sur [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow. Ensuite, vous devez [vérifier le niveau d'accès des utilisateurs](unity-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs. ## Exemple complet \{#full-example\} Voici comment intégrer toutes ces étapes dans votre application. ```csharp showLineNumbers using System; using System.Collections.Generic; using UnityEngine; using AdaptySDK; public class FlowManager : MonoBehaviour, IAdaptyFlowsEventsListener { [SerializeField] private string placementId = "YOUR_PLACEMENT_ID"; void Start() { // Register for flow events Adapty.SetFlowsEventsListener(this); GetAndDisplayFlow(); } private void GetAndDisplayFlow() { Adapty.GetFlow(placementId, (flow, error) => { if (error != null) { Debug.LogError("Error getting flow: " + error.Message); return; } CreateAndPresentFlowView(flow); }); } private void CreateAndPresentFlowView(AdaptyFlow flow) { AdaptyUI.CreateFlowView(flow, (view, error) => { if (error != null) { // the flow has no view configured — use custom logic Debug.LogError("Error creating flow view: " + error.Message); return; } view.Present((presentError) => { if (presentError != null) { Debug.LogError("Error presenting flow: " + presentError.Message); return; } Debug.Log("Flow presented successfully"); }); }); } // IAdaptyFlowsEventsListener implementation public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: Debug.Log("Close button pressed"); view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: AdaptyUI.OpenUrl(action.Value, AdaptyWebPresentation.ExternalBrowser, null); break; default: break; } } public void FlowViewDidFinishPurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { if (purchasedResult.Type != AdaptyPurchaseResultType.UserCancelled) { view.Dismiss(null); } } // Required interface methods (implement as needed) public void FlowViewDidAppear(AdaptyUIFlowView view) { } public void FlowViewDidDisappear(AdaptyUIFlowView view) { } public void FlowViewDidSelectProduct(AdaptyUIFlowView view, string productId) { } public void FlowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { } public void FlowViewDidFailPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { } public void FlowViewDidStartRestore(AdaptyUIFlowView view) { } public void FlowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { } public void FlowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) { } public void FlowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { } public void FlowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) { } public void FlowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { } public void FlowViewDidReceiveAnalyticEvent(AdaptyUIFlowView view, string name, IDictionary<string, object> @params) { } public void ShowFlow() { GetAndDisplayFlow(); } } ``` --- # File: unity-check-subscription-status --- --- title: "Vérifier le statut d'abonnement dans le SDK Unity" description: "Découvrez comment vérifier le statut d'abonnement dans votre application Unity avec Adapty." --- Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil. Cet article vous explique comment accéder à l'état du profil afin de décider ce que les utilisateurs doivent voir — qu'il s'agisse de leur afficher un paywall ou de leur accorder l'accès aux fonctionnalités payantes. ## Vérifier le statut de l'abonnement \{#get-subscription-status\} Lorsque vous souhaitez décider d'afficher un paywall ou du contenu payant à un utilisateur, vous consultez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous : - Appeler `GetProfile` si vous avez besoin des dernières données du profil immédiatement (par exemple au lancement de l'application) ou si vous souhaitez forcer une mise à jour. - Configurer des **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement à chaque changement de statut de l'abonnement. ### Obtenir le profil \{#get-profile\} La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `GetProfile` pour accéder au profil : ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` ### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\} Pour recevoir automatiquement les mises à jour de profil dans votre application : 1. Étendez `AdaptyEventListener` et implémentez la méthode `OnLoadLatestProfile` — Adapty appellera automatiquement cette méthode chaque fois que le statut d'abonnement de l'utilisateur change. 2. Stockez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser dans toute votre application sans effectuer de requêtes réseau supplémentaires. :::note Dans le SDK 4.0, les interfaces de listener suivent la convention C# avec préfixe I : implémentez `IAdaptyEventListener` au lieu de `AdaptyEventListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: ```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 appelle automatiquement `OnLoadLatestProfile` au démarrage de votre application, fournissant des données d'abonnement en cache même si l'appareil est hors ligne. ::: ## Associer le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\} Lorsque vous avez besoin de prendre des décisions immédiates concernant l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez consulter directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'accès à des sections premium, ou avant d'afficher du contenu spécifique. ```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; } if (!profile.AccessLevels.TryGetValue("YOUR_ACCESS_LEVEL", out var accessLevel) || !accessLevel.IsActive) { // Show paywall if no access } }); } private void InitializePaywall() { LoadPaywall(); CheckAccessLevel(); } ``` ## Étapes suivantes \{#next-steps\} Maintenant que vous savez comment suivre le statut de l'abonnement, découvrez comment [travailler avec les profils utilisateurs](unity-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce pour quoi ils ont payé. --- # File: unity-quickstart-identify --- --- title: "Identifier les utilisateurs dans le SDK Unity" description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans Unity." --- :::important Ce guide est fait pour vous si vous disposez de votre propre système d'authentification. Vous y apprendrez comment travailler avec les profils utilisateurs dans Adapty afin de les aligner avec votre système d'authentification existant. ::: La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application : - Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users). - Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users). **Concepts clés** : - Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement. - Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**. - Vous fournissez un **customer user ID** afin de faire le lien entre les profils Adapty et votre système d'authentification interne. Voici les différences entre les utilisateurs anonymes et identifiés : | | Utilisateurs anonymes | Utilisateurs identifiés | |------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------| | **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID | | **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil sur toutes les sessions et tous les appareils | | **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'application | Les données des utilisateurs identifiés persistent d'une installation à l'autre | ## Utilisateurs anonymes \{#anonymous-users\} Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** : 1. Lorsque le SDK est activé au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**. 2. Lorsque l'utilisateur effectue un achat dans l'application, celui-ci est **associé à son profil Adapty et à son compte store**. 3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme lors de l'activation**. 4. Si l'utilisateur a déjà effectué des achats dans votre application, par défaut, ses achats sont automatiquement synchronisés depuis l'App Store lors de l'activation du SDK. Ainsi, avec des utilisateurs anonymes, de nouveaux profils sont créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics). Pour les utilisateurs anonymes, vous devez comptabiliser les installations par **ID d'appareils**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations. ## Utilisateurs identifiés \{#identified-users\} Vous avez deux options pour identifier les utilisateurs dans l'application : - [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient. - [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`. :::important Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils ont un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à l'autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails. ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Lors de la connexion/inscription \{#during-loginsignup\} Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après qu'ils se soient connectés à votre application ou inscrits), utilisez la méthode `identify` pour définir leur customer user ID. - Si vous **n'avez jamais utilisé ce customer user ID auparavant**, Adapty le liera automatiquement au profil actuel. - Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID. :::important Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez en dur la valeur du paramètre, tous les utilisateurs seront considérés comme un seul. ::: Attendez le callback de complétion d'`Identify` avant d'appeler d'autres méthodes du SDK. Les appels simultanés produisent `#3006 profileWasChanged` ou atterrissent sur le profil anonyme. Consultez [Ordre des appels dans le SDK Unity](unity-sdk-call-order). ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` ### Lors de l'activation du SDK \{#during-the-sdk-activation\} Si vous connaissez déjà un customer user ID lors de l'activation du SDK, vous pouvez l'envoyer dans la méthode `activate` plutôt que d'appeler `identify` séparément. Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie que, lors de l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après l'appel à `identify`. Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé auparavant) ou un nouveau. Si vous en passez un nouveau, le nouveau profil créé lors de l'activation sera automatiquement lié au customer user ID. :::note Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord des analyses, car les installations sont comptées par ID d'appareils. Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application. Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une nouvelle installation, ni de l'utilisation d'un customer user ID existant. La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application sans la réinstaller ne génèrent pas d'événements d'installation supplémentaires. Si vous souhaitez comptabiliser les installations par utilisateurs uniques plutôt que par appareils, accédez à **App settings** et configurez [**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"); // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` ### Déconnecter les utilisateurs \{#log-users-out\} Si vous avez un bouton pour déconnecter les utilisateurs, utilisez la méthode `logout`. :::important La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur. ::: ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` :::info Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`. ::: ### Autoriser les achats sans connexion \{#allow-purchases-without-login\} Si vos utilisateurs peuvent effectuer des achats aussi bien avant qu'après s'être connectés à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion : 1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty le lie à son ID de profil anonyme. 2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié. - S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé. - S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez récupérer le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](unity-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](unity-check-subscription-status) pour que les données se synchronisent automatiquement. ## Prochaines étapes \{#next-steps\} Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre application ! Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets : - [**Tests**](troubleshooting-test-purchases) : Assurez-vous que tout fonctionne comme prévu - [**Onboardings**](onboardings) : Engagez les utilisateurs avec des onboardings et favorisez la rétention - [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyses en une seule ligne de code - [**Définir des attributs de profil personnalisés**](unity-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher différents paywalls à différents utilisateurs --- # File: adapty-sdk-integration-skill-unity --- --- title: "Intégrer Adapty dans votre application Unity avec la compétence d'intégration SDK" description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Unity de bout en bout avec votre outil de codage IA." --- :::important La compétence est en version bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-unity) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée. ::: La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill). **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil. Après l'installation, exécutez la compétence dans votre projet : ``` /adapty-sdk-integration ``` La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification. --- # File: adapty-cursor-unity --- --- title: "Intégrer Adapty dans votre application Unity avec l'aide de l'IA" description: "Un guide étape par étape pour intégrer Adapty dans votre application Unity avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA." --- Ce guide vous accompagne étape par étape dans l'intégration d'Adapty dans votre application Unity à l'aide d'un outil IA — vous lui fournissez les bonnes docs Adapty dans le bon ordre. For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\} Adapty nécessite quelques réglages dans le tableau de bord avant d'écrire la moindre ligne de code SDK. Vous pouvez le faire via un skill LLM interactif, ou manuellement depuis le Dashboard. ### Approche par skill (recommandée) \{#skill-approach-recommended\} Le skill Adapty CLI permet à votre LLM de configurer votre application, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Vous n'avez qu'à [connecter vos stores](integrate-payments) dans le Dashboard. ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris quand ouvrir le Dashboard pour connecter vos stores. ### Approche manuelle \{#dashboard-approach\} Si vous préférez tout configurer manuellement, voici ce qu'il vous faut avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir. 1. **Connectez vos stores** : Dans l'Adapty Dashboard, allez dans **App settings → General**. Connectez l'App Store et Google Play si votre application Unity cible les deux plateformes. C'est indispensable pour que les achats fonctionnent. [Connecter les stores](integrate-payments) 2. **Copiez votre clé SDK publique** : Dans l'Adapty Dashboard, allez dans **App settings → General**, puis repérez la section **API keys**. Dans le code, c'est la chaîne que vous passez au builder de configuration Adapty. 3. **Créez au moins un produit** : Dans l'Adapty Dashboard, accédez à la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les livre via les paywalls. [Ajouter des produits](quickstart-products) 4. **Créez un paywall et un placement** : Dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID de placement est la chaîne que vous passez à `Adapty.GetPaywall("YOUR_PLACEMENT_ID")`. [Créer un paywall](quickstart-paywalls) 5. **Configurez les niveaux d'accès** : Dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.AccessLevels["premium"]?.IsActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants accèdent à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` vs. un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder. :::tip Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Indiquez à votre LLM : « Ma clé SDK publique est X, mon ID de placement est Y » pour qu'il génère un code d'initialisation et de récupération de paywall correct. ::: ### À configurer quand vous serez prêt \{#set-up-when-ready\} Ces éléments ne sont pas indispensables pour démarrer, mais vous en aurez besoin à mesure que votre intégration mûrit : - **Tests A/B** : Configurez-les sur la page **Placements**. Aucun changement de code nécessaire. [Tests A/B](ab-tests) - **Paywalls et placements supplémentaires** : Ajoutez d'autres appels `GetPaywall` avec des ID de placement différents. - **Intégrations analytics** : Configurez-les sur la page **Integrations**. La mise en place varie selon l'intégration. Voir [intégrations analytics](analytics-integration) et [intégrations attribution](attribution-integration). ## Fournir la documentation Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\} ### Utiliser Context7 (recommandé) \{#use-context7-recommended\} [Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs selon vos questions — pas besoin de coller des URL manuellement. Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, lancez : ``` npx ctx7 setup ``` Cette commande détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7). Une fois configuré, référencez la bibliothèque Adapty dans vos prompts : ``` Use the adaptyteam/adapty-docs library to look up how to install the Unity SDK ``` :::warning Même si Context7 évite de coller des liens de docs manuellement, l'ordre d'implémentation est important. Suivez le [parcours d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour que tout fonctionne correctement. ::: ### Utiliser les docs en texte brut \{#use-plain-text-docs\} Vous pouvez accéder à n'importe quelle doc Adapty en texte brut Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-unity.md](https://adapty.io/docs/fr/adapty-cursor-unity.md). Chaque étape du [parcours d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc « À envoyer à votre LLM » avec des liens `.md` à coller. Pour accéder à plus de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous. ## Parcours d'implémentation \{#implementation-walkthrough\} La suite de ce guide décrit l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devez observer une fois terminé, et les problèmes courants. ### Planifier votre intégration \{#plan-your-integration\} Avant de plonger dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode planification (comme le mode plan de Cursor ou Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et les docs Adapty avant d'écrire du code. Indiquez à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides à suivre : - [**Adapty Paywall Builder**](adapty-paywall-builder) : Vous créez des paywalls dans le builder no-code d'Adapty, et le SDK les affiche automatiquement. - [**Paywalls créés manuellement**](unity-making-purchases) : Vous construisez votre propre interface de paywall dans le code, mais utilisez toujours Adapty pour récupérer les produits et gérer les achats. - [**Mode observateur**](observer-vs-full-mode) : Vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour l'analytics et les intégrations. Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le quickstart](unity-quickstart-paywalls). ### Installer et configurer le SDK \{#install-and-configure-the-sdk\} Ajoutez le package SDK Adapty via Unity Package Manager et activez-le avec votre clé SDK publique. C'est le socle — rien d'autre ne fonctionne sans ça. **Guide :** [Installer et configurer le SDK Adapty](sdk-installation-unity) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/sdk-installation-unity.md ``` :::tip[Checkpoint] - **Attendu :** Le projet se compile et s'exécute. La console Unity affiche le log d'activation Adapty. - **Point d'attention :** « Public API key is missing » → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings. ::: ### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\} Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de la façon dont vous gérez les achats. Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration. <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **Guides :** - [Activer les achats avec les paywalls (quickstart)](unity-quickstart-paywalls) - [Récupérer les paywalls Paywall Builder et leur configuration](unity-get-pb-paywalls) - [Afficher les paywalls](unity-present-paywalls) - [Gérer les événements de paywall](unity-handling-events) - [Répondre aux actions des boutons](unity-handle-paywall-actions) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/unity-quickstart-paywalls.md - https://adapty.io/docs/fr/unity-get-pb-paywalls.md - https://adapty.io/docs/fr/unity-present-paywalls.md - https://adapty.io/docs/fr/unity-handling-events.md - https://adapty.io/docs/fr/unity-handle-paywall-actions.md ``` :::tip[Checkpoint] - **Attendu :** Le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Point d'attention :** Paywall vide ou erreur `GetPaywall` → vérifiez que l'ID de placement correspond exactement à celui du tableau de bord et que le placement a une audience assignée. ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **Guides :** - [Activer les achats dans votre paywall personnalisé (quickstart)](unity-quickstart-manual) - [Récupérer les paywalls et les produits](fetch-paywalls-and-products-unity) - [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-unity) - [Effectuer des achats](unity-making-purchases) - [Restaurer des achats](unity-restore-purchase) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/unity-quickstart-manual.md - https://adapty.io/docs/fr/fetch-paywalls-and-products-unity.md - https://adapty.io/docs/fr/present-remote-config-paywalls-unity.md - https://adapty.io/docs/fr/unity-making-purchases.md - https://adapty.io/docs/fr/unity-restore-purchase.md ``` :::tip[Checkpoint] - **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox. - **Point d'attention :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience. ::: </TabItem> <TabItem value="observer" label="Observer mode"> **Guides :** - [Présentation du mode observateur](observer-vs-full-mode) - [Implémenter le mode observateur](implement-observer-mode-unity) - [Signaler les transactions en mode observateur](report-transactions-observer-mode-unity) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/observer-vs-full-mode.md - https://adapty.io/docs/fr/implement-observer-mode-unity.md - https://adapty.io/docs/fr/report-transactions-observer-mode-unity.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox via votre flow d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty. - **Point d'attention :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores. ::: </TabItem> </Tabs> ### Vérifier le statut de l'abonnement \{#check-subscription-status\} Après un achat, vérifiez dans le profil utilisateur la présence d'un niveau d'accès actif pour contrôler l'accès au contenu premium. **Guide :** [Vérifier le statut de l'abonnement](unity-check-subscription-status) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/unity-check-subscription-status.md ``` :::tip[Checkpoint] - **Attendu :** Après un achat sandbox, `profile.AccessLevels["premium"]?.IsActive` retourne `true`. - **Point d'attention :** `AccessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord. ::: ### Identifier les utilisateurs \{#identify-users\} Associez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent sur tous les appareils. :::important Ignorez cette étape si votre application ne requiert pas d'authentification. ::: **Guide :** [Identifier les utilisateurs](unity-quickstart-identify) À envoyer à votre LLM : ``` Read these Adapty docs before writing code: - https://adapty.io/docs/fr/unity-quickstart-identify.md ``` :::tip[Checkpoint] - **Attendu :** Après avoir appelé `Adapty.Identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé. - **Point d'attention :** Appelez `Identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution de profil anonyme. ::: ### Se préparer pour la mise en production \{#prepare-for-release\} Une fois votre intégration fonctionnelle en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt. **Guide :** [Checklist de mise en production](release-checklist) À envoyer à votre LLM : ``` Read these Adapty docs before releasing: - https://adapty.io/docs/fr/release-checklist.md ``` :::tip[Checkpoint] - **Attendu :** Tous les éléments de la checklist confirmés : connexions aux stores, notifications serveur, flow d'achat, vérifications des niveaux d'accès et exigences de confidentialité. - **Point d'attention :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**. ::: ## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\} Si vous avez besoin de donner à votre LLM un contexte plus large que des pages individuelles, nous hébergeons des fichiers d'index qui listent ou regroupent toute la documentation Adapty : - [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : Liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites accessibles aux LLM. Notez que pour certains agents IA (ex. ChatGPT), vous devrez télécharger `llms.txt` et le joindre à la conversation en tant que fichier. - [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : L'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement si vous avez besoin de la vue d'ensemble complète. - [`unity-llms.txt`](https://adapty.io/docs/fr/unity-llms.txt) et [`unity-llms-full.txt`](https://adapty.io/docs/fr/unity-llms-full.txt) spécifiques à Unity : Des sous-ensembles par plateforme qui économisent des tokens par rapport au site complet. --- # File: unity-paywalls --- --- title: "Flows et paywalls - Unity" description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre application Unity." --- ## Afficher les paywalls \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder <CustomDocCardList ids={['unity-get-pb-paywalls', 'unity-present-paywalls', 'unity-handling-events', 'unity-handle-paywall-actions']} /> :::tip Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](unity-quickstart-paywalls). ::: ### Implémenter les paywalls manuellement \{#implement-paywalls-manually\} <CustomDocCardList ids={['unity-quickstart-manual', 'fetch-paywalls-and-products-unity', 'present-remote-config-paywalls-unity', 'unity-making-purchases']} /> Pour plus de guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](unity-implement-paywalls-manually). ## Fonctionnalités utiles \{#useful-features\} <CustomDocCardList ids={['unity-use-fallback-paywalls', 'unity-web-paywalls']} /> --- # File: unity-get-pb-paywalls --- --- title: "Récupérer les flows et paywalls - Unity" description: "Récupérez les flows et paywalls depuis Adapty dans votre application Unity." --- <SDKv4> <MethodPromo method="GetFlow" /> Après avoir [conçu votre flow ou votre paywall dans le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher des flows dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-unity) dans votre application mobile. </details> ## Récupérer un flow/paywall \{#fetch-flowpaywall\} Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son ID via le placement, sa configuration de vue, puis le présenter dans votre application mobile. Pour des performances optimales, il est essentiel de récupérer le flow ou le paywall ainsi que sa [configuration de vue](unity-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher à l'utilisateur. Pour obtenir un flow ou un paywall, utilisez la méthode `GetFlow` : ```csharp showLineNumbers Adapty.GetFlow( "YOUR_PLACEMENT_ID", AdaptyPlacementFetchPolicy.Default, TimeSpan.FromSeconds(5), (flow, error) => { if (error != null) { // handle the error return; } // flow - the requested flow/paywall } ); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **fetchPolicy** | défaut : `AdaptyPlacementFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour les récupérer plus rapidement et un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version tout en assurant la fiabilité, même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en interne.</p> | | Paramètre | Description | | :-------- | :---------- | | Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`InstanceIdentity`, `VariationId`), le nom, les variantes de paywall (`Paywalls` — une liste d'`AdaptyFlowPaywall`) et les Remote Configs (`RemoteConfigs` — une liste avec une entrée par locale). Pour récupérer les produits réels en vue d'un préchargement, d'une UI personnalisée ou de vérifications programmatiques, appelez `GetPaywallProducts(flow)`. | ## Récupérer la configuration de la vue \{#fetch-the-view-configuration\} Après avoir récupéré le flow ou le paywall, chargez sa configuration de vue et créez la vue en une seule étape avec la méthode `CreateFlowView`. Il n'y a pas d'indicateur distinct à vérifier : si le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall), `CreateFlowView` retourne la vue prête à être affichée. Si le placement est un paywall personnalisé sans interface Builder, `CreateFlowView` retourne une erreur — [gérez-la comme un paywall Remote Config](present-remote-config-paywalls-unity). :::important Assurez-vous d'activer le bouton **Show on device** dans le Flow Builder. Si cette option n'est pas activée, la configuration de la vue ne sera pas disponible pour être récupérée. ::: ```csharp showLineNumbers var parameters = new AdaptyUICreateFlowViewParameters() .SetPreloadProducts(true) .SetLoadTimeout(TimeSpan.FromSeconds(5)); AdaptyUI.CreateFlowView(flow, parameters, (view, error) => { if (error != null) { // the flow has no view configured, or view creation failed return; } // use view }); ``` | Paramètre | Présence | Description | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.GetFlow`. | | **Locale** | optionnel | L'identifiant de la [localisation du Builder](add-paywall-locale-in-adapty-paywall-builder) à utiliser pour afficher le flow ou le paywall, par exemple `en` ou `pt-br`. Un flow est localisé lors de la création de sa vue ; c'est donc le seul endroit où choisir sa localisation. Si vous l'omettez, Adapty détermine la localisation depuis l'appareil. Voir [Utiliser les localisations et les codes de langue](unity-localizations-and-locale-codes). | | **LoadTimeout** | optionnel | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `LoadTimeout`, car l'opération peut comporter plusieurs requêtes en interne. | | **PreloadProducts** | optionnel | Définissez à `true` pour précharger les produits et améliorer les performances. Lorsque cette option est activée, les produits sont chargés à l'avance, ce qui réduit le temps nécessaire pour afficher le flow ou le paywall. | | **ProductPurchaseParameters** | optionnel | Android uniquement (ignoré sur iOS). Un dictionnaire associant `AdaptyProductIdentifier` à `AdaptyPurchaseParameters`. Utilisez-le pour configurer des paramètres d'achat spécifiques comme les offres personnalisées ou les paramètres de mise à jour d'abonnement pour chaque produit du flow ou du paywall. | | **EnableSafeAreaPaddings** | optionnel | Android uniquement (ignoré sur iOS). Lorsque la valeur est `true`, la vue du flow applique des marges de zone sécurisée. Valeur par défaut : `true`. La valeur par défaut convient à la plupart des cas. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Builder](add-paywall-locale-in-adapty-paywall-builder). ::: Une fois chargé, [présentez le flow ou le paywall](unity-present-paywalls). ## Obtenez un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En général, les flows et les paywalls sont récupérés quasi instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs ont une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher. Pour y remédier, vous pouvez utiliser la méthode `GetFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `GetFlow`, comme expliqué dans la section [Récupérer un flow/paywall](#fetch-flowpaywall) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `GetFlow` La méthode `GetFlowForDefaultAudience` présente plusieurs inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des flows différents selon les versions de l'application (version actuelle et versions futures), vous pourriez rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows qui ne s'affichent pas correctement. - **Perte de ciblage** : tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment par pays, attribution marketing ou attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow ou du paywall, utilisez la méthode `GetFlowForDefaultAudience` comme suit. Sinon, utilisez `GetFlow` décrit [ci-dessus](#fetch-flowpaywall). ::: ```csharp showLineNumbers Adapty.GetFlowForDefaultAudience( "YOUR_PLACEMENT_ID", AdaptyPlacementFetchPolicy.Default, (flow, error) => { if (error != null) { // handle the error return; } // flow - the requested flow } ); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPlacementFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter des requêtes réseau.</p><p></p><p>Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation de celle-ci ou par un nettoyage manuel.</p> | ## Personnaliser les ressources \{#customize-assets\} Pour personnaliser les images et vidéos dans votre flow ou paywall, implémentez des ressources personnalisées. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. Voici un exemple montrant comment fournir des ressources personnalisées via un dictionnaire simple : ```csharp showLineNumbers var customAssets = new Dictionary<string, AdaptyCustomAsset> { { "custom_image", AdaptyCustomAsset.LocalImageFile("custom_assets/images/custom_image.png") }, { "hero_video", AdaptyCustomAsset.LocalVideoFile("custom_assets/videos/custom_video.mp4") } }; var parameters = new AdaptyUICreateFlowViewParameters() .SetCustomAssets(customAssets) .SetLoadTimeout(TimeSpan.FromSeconds(3)); AdaptyUI.CreateFlowView(flow, parameters, (view, error) => { // handle the result }); ``` :::note Si une ressource est introuvable ou ne parvient pas à se charger, le flow ou le paywall reviendra à son apparence par défaut telle que configurée dans le Builder. ::: ## Configurer des minuteries définies par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des minuteries personnalisées dans votre application Unity, passez un dictionnaire d'identifiants de minuteries et leurs dates de fin à la méthode `SetCustomTimers`. Voici un exemple : ```csharp showLineNumbers var customTimers = new Dictionary<string, DateTime> { { "CUSTOM_TIMER_6H", DateTime.Now.AddHours(6) }, { "CUSTOM_TIMER_NY", new DateTime(2026, 1, 1) } }; var parameters = new AdaptyUICreateFlowViewParameters() .SetCustomTimers(customTimers) .SetLoadTimeout(TimeSpan.FromSeconds(3)); AdaptyUI.CreateFlowView(flow, parameters, (view, error) => { // handle the result }); ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID**s des minuteries définies par le développeur que vous configurez dans l'Adapty Dashboard. Le résolveur de minuterie garantit que votre application met dynamiquement à jour chaque minuterie avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin de la minuterie, par exemple le jour du Nouvel An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures qui a démarré lorsque l'utilisateur a ouvert le flow ou le paywall. </SDKv4> <SDKv3> Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le paywall associé au placement et sa configuration d'affichage, comme décrit ci-dessous. :::warning Le nouveau Paywall Builder fonctionne avec le SDK Unity version 3.3.0 ou supérieure. ::: Veuillez noter que ce sujet concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, reportez-vous à la rubrique [Récupérer les paywalls et les produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-unity). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à afficher les paywalls dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard. 4. Installez le [SDK Adapty](sdk-installation-unity) dans votre application mobile. </details> ## Récupérer un paywall créé avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\} Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Vous devez néanmoins récupérer son identifiant via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile. Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur. Pour obtenir un paywall, utilisez la méthode `GetPaywall` : ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.</p><p></p><p>Exemple : `en` signifie l'anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs sont confrontés à une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne recevront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut regrouper différentes requêtes en coulisses.</p> | Paramètres de réponse : | Paramètre | Description | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) contenant une liste d'identifiants de produits, l'identifiant du paywall, la Remote Config, et plusieurs autres propriétés. | ## Récupérer la configuration d'affichage d'un paywall créé avec Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration d'affichage ne sera pas disponible pour la récupération. ::: Après avoir récupéré le paywall, vérifiez s'il inclut une `ViewConfiguration`, ce qui indique qu'il a été créé avec Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si la `ViewConfiguration` est présente, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-unity). Dans le SDK Unity, appelez directement la méthode `CreatePaywallView` sans récupérer manuellement la configuration de la vue au préalable. :::warning Le résultat de la méthode `CreatePaywallView` ne peut être utilisé qu'une seule fois. Si vous devez l'utiliser à nouveau, appelez de nouveau la méthode `CreatePaywallView`. L'appeler deux fois sans recréer peut entraîner l'erreur `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 }); ``` Paramètres : | Paramètre | Présence | Description | | :------------------ | :------------- | :----------------------------------------------------------- | | **paywall** | obligatoire | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. | | **loadTimeout** | défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après la valeur spécifiée dans `loadTimeout`, car l'opération peut impliquer différentes requêtes en interne. | | **PreloadProducts** | optionnel | Fournissez un tableau d'`AdaptyPaywallProducts` pour optimiser le moment d'affichage des produits à l'écran. Si `nil` est passé, AdaptyUI récupérera automatiquement les produits nécessaires. | | **CustomTags** | optionnel | Définissez un dictionnaire de tags personnalisés et leurs valeurs résolues. Les tags personnalisés servent de balises dans le contenu du paywall, remplacées dynamiquement par des chaînes spécifiques pour un contenu personnalisé. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. | | **CustomTimers** | optionnel | Définissez un dictionnaire de minuteries personnalisées et leurs dates de fin. Les minuteries personnalisées permettent d'afficher des comptes à rebours dans votre paywall. | :::note Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](localizations-and-locale-codes). ::: Une fois que vous avez la vue, [affichez le paywall](unity-present-paywalls). ## Personnaliser les assets \{#customize-assets\} Pour personnaliser les images et vidéos de votre paywall, implémentez des assets personnalisés. Les images et vidéos hero ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle d'assets personnalisé, vous ciblez ces éléments par leurs IDs et personnalisez leur comportement. Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans l'Adapty Dashboard. Par exemple, vous pouvez : - Afficher une image ou vidéo différente à certains utilisateurs. - Afficher une image de prévisualisation locale pendant le chargement d'une image principale distante. - Afficher une image de prévisualisation avant de lancer une vidéo. :::important Pour utiliser cette fonctionnalité, mettez à jour le SDK Unity d'Adapty vers la version 3.8.0 ou supérieure. ::: Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via un simple dictionnaire : ```csharp showLineNumbers var customAssets = new Dictionary<string, AdaptyCustomAsset> { { "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 un asset est introuvable, le paywall reviendra à son apparence par défaut. ::: ## Configurer des minuteries définies par le développeur \{#set-up-developer-defined-timers\} Pour utiliser des minuteries personnalisées dans votre application Unity, vous pouvez passer un dictionnaire d'identifiants de minuteries et leurs dates de fin directement à la méthode `SetCustomTimers`. Voici un exemple : ```csharp showLineNumbers var customTimers = new Dictionary<string, DateTime> { { "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 }); ``` Dans cet exemple, `CUSTOM_TIMER_NY` et `CUSTOM_TIMER_6H` sont les **Timer ID**s des minuteries définies par le développeur que vous avez configurées dans l'Adapty Dashboard. Le résolveur de minuterie garantit que votre application met dynamiquement à jour chaque minuterie avec la valeur correcte. Par exemple : - `CUSTOM_TIMER_NY` : le temps restant jusqu'à la fin de la minuterie, par exemple le Jour de l'An. - `CUSTOM_TIMER_6H` : le temps restant dans une période de 6 heures qui a démarré lorsque l'utilisateur a ouvert le paywall. ## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En règle générale, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `GetPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée consiste à récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer le paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus. :::warning Privilégiez `GetPaywall` plutôt que `GetPaywallForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des difficultés lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions s'affichent incorrectement. - **Pas de personnalisation** : affiche uniquement le contenu pour l'audience « Tous les utilisateurs », sans ciblage basé sur le pays, l'attribution ou des attributs personnalisés. Si la rapidité de récupération compense ces inconvénients pour votre cas d'usage, utilisez `GetPaywallForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `GetPaywall` comme décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation du paywall. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second désigne la région.</p><p></p><p>Exemple : `en` signifie l'anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les paywalls de secours. Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous disposez toujours de la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | </SDKv3> --- # File: unity-present-paywalls --- --- title: "Afficher les paywalls" description: "Découvrez comment afficher les paywalls dans votre application Unity avec le SDK Adapty." --- Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. :::warning Ce guide couvre le **nouveau Paywall Builder**, qui nécessite le SDK Adapty 3.3.0 ou une version ultérieure. Pour afficher des paywalls avec Remote Config, consultez [Afficher les paywalls conçus avec Remote Config](present-remote-config-paywalls). ::: Pour afficher un paywall, utilisez la méthode `view.Present()` sur le `view` créé par la méthode [`CreatePaywallView`](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisé qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `CreatePaywallView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser le même `view` sans le recréer peut entraîner une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Afficher une boîte de dialogue \{#show-dialog\} Utilisez cette méthode à la place des boîtes de dialogue natives lorsqu'un paywall est affiché sur Android. Sur Android, les alertes classiques apparaissent derrière le paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes. ```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 } }); ``` ## Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `Present()`. Ce paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FullScreen` (par défaut) ou `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` --- # File: unity-handle-paywall-actions --- --- title: "Répondre aux actions de flow - Unity" description: "Gérez les actions de boutons des flows et des paywalls dans votre application Unity." --- <SDKv4> Si vous créez des flows ou des paywalls avec le Flow Builder ou le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le builder](paywall-buttons) et attribuez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **Seuls les achats et les restaurations sont gérés automatiquement.** Toutes les autres actions de bouton, comme fermer les flows ou ouvrir des liens, nécessitent une implémentation appropriée dans le code de l'application. ::: ## Configurer l'écouteur d'événements des flows \{#set-up-the-flows-events-listener\} Pour gérer les actions des flows, implémentez l'interface `IAdaptyFlowsEventsListener` et enregistrez-la avec `Adapty.SetFlowsEventsListener()`. Cela doit être fait tôt dans le cycle de vie de votre application, généralement dans votre scène principale ou lors de l'initialisation de l'app. ```csharp showLineNumbers title="Unity" using AdaptySDK; public class FlowsListener : MonoBehaviour, IAdaptyFlowsEventsListener { void Start() { Adapty.SetFlowsEventsListener(this); } // implement all IAdaptyFlowsEventsListener methods here } ``` `IAdaptyFlowsEventsListener` est une interface C#, donc implémentez toutes ses méthodes — consultez [Gérer les événements de flow et de paywall](unity-handling-events) pour la liste complète. Les exemples ci-dessous montrent uniquement la méthode `FlowViewDidPerformAction`. Toutes les actions de bouton arrivent dans le callback `FlowViewDidPerformAction(view, action)` sous forme d'objet `AdaptyUIUserAction` avec un `Type` parmi `Close`, `SystemBack`, `OpenUrl` ou `Custom`, ainsi qu'une `Value` optionnelle (l'URL ou l'identifiant de l'action personnalisée). ## Fermer les flows et les paywalls \{#close-flows-and-paywalls\} Pour ajouter un bouton permettant de fermer votre flow ou paywall : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `Close` qui ferme le flow. :::info Une vue fermée est détruite et ne peut plus être affichée. Pour afficher le flow à nouveau, appelez `CreateFlowView` une nouvelle fois. ::: ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; default: // handle other events break; } } ``` ## Gérer le bouton retour système Android \{#handle-the-android-system-back-button\} Appuyer sur le bouton retour système Android (ou utiliser le geste de retour) émet une action de type `SystemBack`. Cela ne ferme pas le flow en soi — le flow reste ouvert, et l'utilisateur le quitte via un chemin que vous définissez, comme un bouton **Close** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même : ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: case AdaptyUIUserActionType.SystemBack: view.Dismiss(null); break; default: // handle other events break; } } ``` ## Ouvrir des URL depuis des flows et des paywalls :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `OpenUrl` qui ouvre l'URL reçue. Utilisez la méthode `AdaptyUI.OpenUrl` pour ouvrir l'URL nativement, en respectant l'option de navigateur externe ou intégré (`action.OpenIn`) configurée dans le builder : ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if (!string.IsNullOrWhiteSpace(urlString)) { AdaptyUI.OpenUrl( urlString, action.OpenIn ?? AdaptyWebPresentation.ExternalBrowser, (error) => { // handle the error } ); } break; default: // handle other events break; } } ``` ## Se connecter à l'application \{#log-into-the-app\} Pour ajouter un bouton qui connecte les utilisateurs à votre application : 1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Custom** avec l'ID `login`. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action personnalisée `login` qui identifie votre utilisateur. ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView 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; } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un identifiant. 2. Dans le code de votre application, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous avez d'autres offres d'abonnement ou achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall : ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "openNewFlow") { // Display another flow or paywall ShowAlternativeFlow(); } break; default: // handle other events break; } } private void ShowAlternativeFlow() { // Implement your logic to show an alternative flow } ``` </SDKv4> <SDKv3> Si vous créez des paywalls avec le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons : 1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un identifiant d'action personnalisé. 2. Écrivez le code dans votre application pour gérer chaque action assignée. Ce guide explique comment gérer les actions personnalisées et les actions existantes dans votre code. :::warning **Seuls les achats et les restaurations sont gérés automatiquement.** Toutes les autres actions de bouton, comme la fermeture des paywalls ou l'ouverture de liens, nécessitent une implémentation des réponses appropriées dans le code de l'application. ::: ## Fermer les paywalls \{#close-paywalls\} Pour ajouter un bouton permettant de fermer votre paywall : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `close` qui ferme le 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; } } ``` ## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\} :::tip Si vous souhaitez ajouter un groupe de liens (par exemple, conditions d'utilisation et restauration des achats), ajoutez un élément **Link** dans le Paywall Builder et traitez-le de la même manière que les boutons avec l'action **Open URL**. ::: Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Terms of use** ou **Privacy policy**) : 1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur. ```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; } } ``` ## Se connecter à l'application \{#log-into-the-app\} Pour ajouter un bouton permettant aux utilisateurs de se connecter à votre application : 1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Custom** avec l'ID `login`. 2. Dans le code de votre application, implémentez un gestionnaire pour l'action personnalisée `login` qui identifie votre utilisateur. ```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; } } ``` ## Gérer les actions personnalisées \{#handle-custom-actions\} Pour ajouter un bouton qui gère d'autres actions : 1. Dans le Paywall Builder, ajoutez un bouton, attribuez-lui l'action **Custom** et un identifiant. 2. Dans le code de votre application, implémentez un gestionnaire pour l'identifiant d'action que vous avez créé. Par exemple, si vous proposez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre 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 } ``` </SDKv3> --- # File: unity-handling-events --- --- title: "Gérer les événements de flow et de paywall - Unity" description: "Gérez les événements de flow et de paywall dans votre application Unity." --- <SDKv4> :::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 devez également implémenter la gestion des boutons (fermeture du flow, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de flow](unity-handle-paywall-actions) pour plus de détails. ::: Les flows et paywalls configurés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-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 pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez ci-dessous comment réagir à ces événements. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Gestion des événements \{#handling-events\} Pour contrôler ou surveiller les processus qui se déroulent sur l'écran du flow dans votre application mobile, implémentez l'interface `IAdaptyFlowsEventsListener` et enregistrez-la avec `Adapty.SetFlowsEventsListener()` : ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; public class FlowEventsHandler : MonoBehaviour, IAdaptyFlowsEventsListener { void Start() { Adapty.SetFlowsEventsListener(this); } // Implement all interface methods below } ``` :::note Ces méthodes sont l'endroit où vous ajoutez votre logique personnalisée pour répondre aux événements du flow. Le SDK n'applique aucun comportement par défaut : un achat réussi ou une erreur ne ferme pas la vue automatiquement — appelez `view.Dismiss(...)` vous-même au moment opportun. ::: ### Événements générés par l'utilisateur \{#user-generated-events\} #### Flow apparu \{#flow-appeared\} Invoqué lorsque la vue du flow s'affiche à l'écran. :::note Sur iOS, également invoqué lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un flow, et qu'un paywall web s'ouvre dans un navigateur intégré. ::: ```csharp showLineNumbers title="Unity" public void FlowViewDidAppear(AdaptyUIFlowView view) { } ``` #### Flow disparu \{#flow-disappeared\} Invoqué lorsque la vue du flow est fermée depuis l'écran. :::note Sur iOS, également invoqué lorsqu'un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un flow dans un navigateur intégré disparaît de l'écran. ::: ```csharp showLineNumbers title="Unity" public void FlowViewDidDisappear(AdaptyUIFlowView view) { } ``` #### Sélection de produit \{#product-selection\} Invoqué lorsqu'un produit est sélectionné pour achat (par l'utilisateur ou par le système). ```csharp showLineNumbers title="Unity" public void FlowViewDidSelectProduct( AdaptyUIFlowView view, string productId ) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> #### Achat démarré \{#started-purchase\} Invoqué lorsqu'un utilisateur lance le processus d'achat. ```csharp showLineNumbers title="Unity" public void FlowViewDidStartPurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product ) { } ``` :::note En [mode Observer](unity-present-flows-in-observer-mode), les achats démarrés depuis un flow sont transmis à votre `IAdaptyUIObserverModeResolver` à la place. ::: <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si l'achat réussit, que l'utilisateur annule son achat, ou que l'achat est en attente, cette méthode sera invoquée. Les annulations de l'utilisateur et les paiements en attente (par exemple, approbation parentale requise) déclenchent cette méthode, et non `FlowViewDidFailPurchase`. Le flow reste ouvert après l'achat jusqu'à ce que vous le fermiez vous-même, alors appelez `view.Dismiss(...)` dès que l'utilisateur obtient l'accès : ```csharp showLineNumbers title="Unity" public void FlowViewDidFinishPurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { switch (purchasedResult.Type) { case AdaptyPurchaseResultType.Success: // Check if user has access to premium features if (purchasedResult.Profile != null && purchasedResult.Profile.AccessLevels.TryGetValue("premium", out var premium) && premium.IsActive) { view.Dismiss(null); } break; case AdaptyPurchaseResultType.Pending: // Handle pending purchase (e.g., user will pay offline with cash) break; case AdaptyPurchaseResultType.UserCancelled: // Handle user cancellation break; default: break; } } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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" } } ``` </Details> Nous recommandons de fermer l'écran du flow en cas d'achat réussi. #### Échec d'achat \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera appelée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `FlowViewDidFinishPurchase` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode. ```csharp showLineNumbers title="Unity" public void FlowViewDidFailPurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```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" } } } ``` </Details> #### Restauration démarrée \{#started-restore\} Déclenché lorsqu'un utilisateur lance le processus de restauration : ```csharp showLineNumbers title="Unity" public void FlowViewDidStartRestore(AdaptyUIFlowView view) { } ``` #### Restauration réussie \{#successful-restore\} Appelé lorsque la restauration des achats réussit. Le flow reste ouvert après la restauration jusqu'à ce que vous le fermiez : ```csharp showLineNumbers title="Unity" public void FlowViewDidFinishRestore( AdaptyUIFlowView view, AdaptyProfile profile ) { // Check if user has access to premium features if (profile.AccessLevels.TryGetValue("premium", out var premium) && premium.IsActive) { view.Dismiss(null); } } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```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" } ] } } ``` </Details> Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](unity-listen-subscription-changes) pour savoir comment le vérifier. #### Échec de la restauration \{#failed-restore\} Invoqué lorsque la restauration des achats échoue : ```csharp showLineNumbers title="Unity" public void FlowViewDidFailRestore( AdaptyUIFlowView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> #### Navigation de paiement web terminée \{#finished-web-payment-navigation\} Après une tentative d'ouverture d'un [paywall web](web-paywall) pour un achat (qu'elle ait réussi ou échoué), cette méthode sera invoquée : ```csharp showLineNumbers title="Unity" public void FlowViewDidFinishWebPaymentNavigation( AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` **Paramètres :** - `product` : Le produit pour lequel le paywall web a été ouvert (ou tenté), ou `null` - `error` : `null` si le paywall web s'est ouvert avec succès, ou un `AdaptyError` en cas d'échec <Details> <summary>Exemples d'événements (Cliquez pour développer)</summary> ```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": null, "error": { "code": "wrong_param", "message": "Current method is not available for this product", "details": { "underlyingError": "Product not configured for web purchases" } } } ``` </Details> ### Récupération et rendu des données \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Déclenché quand le chargement des produits échoue et fournit une `AdaptyError`. Si vous n'avez pas passé le tableau de produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires auprès du serveur. Cette opération peut échouer, et AdaptyUI signalera l'erreur en appelant cette méthode : ```csharp showLineNumbers title="Unity" public void FlowViewDidFailLoadingProducts( AdaptyUIFlowView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquer pour agrandir)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> #### Erreurs de rendu et d'exécution \{#rendering-and-runtime-errors\} Si une erreur survient lors du rendu de l'interface, ou qu'une autre erreur d'exécution non liée à un achat se produit, elle sera signalée par cette méthode. La vue n'est pas fermée automatiquement — appelez `view.Dismiss(...)` vous-même si nécessaire : ```csharp showLineNumbers title="Unity" public void FlowViewDidReceiveError( AdaptyUIFlowView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } ``` </Details> En situation normale, ces erreurs ne devraient pas se produire. Si vous en rencontrez une, merci de nous en informer. #### Événements analytiques \{#analytics-events\} `FlowViewDidReceiveAnalyticEvent` est réservé aux événements analytiques personnalisés provenant d'un flow. Les flows n'émettent pas encore ces événements vers votre code, donc laissez le corps de la méthode vide — `IAdaptyFlowsEventsListener` est une interface C#, la méthode doit tout de même être présente : ```csharp showLineNumbers title="Unity" public void FlowViewDidReceiveAnalyticEvent( AdaptyUIFlowView view, string name, IDictionary<string, object> @params ) { } ``` ### Gérer les requêtes système \{#handle-system-requests\} Le `IAdaptyUISystemRequestsHandler` (enregistré via `Adapty.SetSystemRequestsHandler(...)`) est réservé aux requêtes système provenant d'un flow : invites de permission OS (comme les notifications push ou l'accès à la caméra) et demandes d'évaluation de l'application. Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler. ### Navigation \{#navigation\} #### Bouton retour système Android \{#android-system-back-button\} Le bouton retour système Android (ou le geste de retour) est transmis à `FlowViewDidPerformAction` sous forme d'action `SystemBack` et ne ferme pas le flow par lui-même — l'utilisateur quitte le flow via un chemin que vous définissez, comme un bouton **Close** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même : ```csharp showLineNumbers title="Unity" public void FlowViewDidPerformAction( AdaptyUIFlowView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: case AdaptyUIUserActionType.SystemBack: view.Dismiss(null); break; default: // handle other events break; } } ``` Consultez le [guide sur la gestion des actions de flow](unity-handle-paywall-actions) pour la liste complète des actions. </SDKv4> <SDKv3> :::important Ce guide couvre la gestion des événements liés aux achats, aux restaurations, à la sélection de produits et au 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](unity-handle-paywall-actions) pour plus de détails. ::: Les paywalls configurés avec le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent des événements auxquels votre application peut réagir. Ces événements incluent 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 ci-dessous comment réagir à ces événements. :::warning Ce guide s'adresse uniquement aux paywalls du **nouveau Paywall Builder**, qui nécessitent le SDK Adapty v3.3.0 ou ultérieur. ::: :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Gestion des événements \{#handling-events\} Pour contrôler ou surveiller les processus qui se déroulent sur l'écran du paywall dans votre application mobile, implémentez l'interface `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 } ``` ### Événements générés par l'utilisateur \{#user-generated-events\} #### Paywall apparu \{#paywall-appeared\} Déclenché lorsque la vue du paywall s'affiche à l'écran. :::note Sur iOS, également déclenché lorsqu'un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) à l'intérieur d'un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré à l'application. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### Paywall disparu \{#paywall-disappeared\} Déclenché lorsque la vue du paywall est fermée et disparaît de l'écran. :::note Sur iOS, également invoqué lorsqu'un [web paywall](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### Sélection de produit \{#product-selection\} Invoqué lorsqu'un produit est sélectionné pour achat (par l'utilisateur ou par le système). ```csharp showLineNumbers title="Unity" public void PaywallViewDidSelectProduct( AdaptyUIPaywallView view, string productId ) { } ``` <Details> <summary>Exemple d'événement (Cliquer pour développer)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> #### Achat démarré \{#started-purchase\} Invoqué lorsqu'un utilisateur lance le processus d'achat. ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\} Si l'achat réussit, si l'utilisateur l'annule, ou si l'achat est en attente, cette méthode sera invoquée. Les annulations par l'utilisateur et les paiements en attente (par exemple, approbation parentale requise) déclenchent cette méthode, et non `PaywallViewDidFailPurchase`. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { } ``` <Details> <summary>Exemples d'événements (cliquez pour développer)</summary> ```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" } } ``` </Details> Nous vous recommandons de fermer l'écran dans ce cas. #### Échec d'achat \{#failed-purchase\} Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification des transactions et les erreurs système. Notez que les annulations de l'utilisateur déclenchent `PaywallViewDidFinishPurchase` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode. ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```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" } } } ``` </Details> #### Restauration démarrée \{#started-restore\} Déclenché lorsqu'un utilisateur lance le processus de restauration : ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### Restauration réussie \{#successful-restore\} Invoqué lorsque la restauration des achats réussit : ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishRestore( AdaptyUIPaywallView view, AdaptyProfile profile ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```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" } ] } } ``` </Details> Nous vous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](unity-listen-subscription-changes) pour savoir comment le vérifier. #### Échec de la restauration \{#failed-restore\} Déclenché en cas d'échec de la restauration des achats : ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRestore( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (cliquer pour développer)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> #### Navigation web de paiement terminée \{#finished-web-payment-navigation\} Après avoir tenté d'ouvrir un [paywall web](web-paywall) pour un achat (qu'il ait réussi ou échoué), cette méthode sera invoquée : ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishWebPaymentNavigation( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` **Paramètres :** - `product` : Le produit pour lequel le paywall web a été ouvert (ou tenté) - `error` : `null` si le paywall web s'est ouvert avec succès, ou une `AdaptyError` en cas d'échec <Details> <summary>Exemples d'événements (Cliquez pour développer)</summary> ```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" } } } ``` </Details> ### Récupération et rendu des données \{#data-fetching-and-rendering\} #### Erreurs de chargement des produits \{#product-loading-errors\} Déclenché quand le chargement des produits échoue et fournit une `AdaptyError`. Si vous n'avez pas transmis le tableau de produits lors de l'initialisation, AdaptyUI récupèrera lui-même les objets nécessaires depuis le serveur. Cette opération peut échouer, et AdaptyUI signalera l'erreur en invoquant cette méthode : ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailLoadingProducts( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> #### Erreurs de rendu \{#rendering-errors\} Invoqué lorsqu'une erreur survient pendant le rendu de l'interface et fournit `AdaptyError` : ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRendering( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous en informer. </SDKv3> --- # File: unity-web-paywalls --- --- title: "Implémenter des paywalls web dans le SDK Unity" description: "Configurez un paywall web pour être payé sans les frais et audits de l'App Store." --- :::important Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé le SDK Adapty version 3.14 ou ultérieure. ::: ## Paywalls web ouverts \{#open-web-paywalls\} Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `Adapty.OpenWebPaywall` : 1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur donné à la page web vers laquelle il est redirigé. 2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `Adapty.GetProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour. Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement. ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, AdaptyWebPresentation.ExternalBrowser, (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` :::note Il existe deux versions de la méthode `OpenWebPaywall` : 1. `OpenWebPaywall(product)` qui génère des URLs à partir du paywall et y ajoute les données du produit. 2. `OpenWebPaywall(paywall)` qui génère des URLs à partir du paywall sans ajouter les données du produit. Utilisez-la lorsque vos produits dans le paywall Adapty diffèrent de ceux du paywall web. Dans le SDK v4, l'argument `paywall` prend un `AdaptyFlowPaywall` — l'une des variations de paywall dans `flow.Paywalls`. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: #### Gérer les erreurs \{#handle-errors\} | Code d'erreur | Description | Action recommandée | |-----------|--------------------------------------------------------|---------------------------------------------------------------------------| | `AdaptyErrorCode.WrongParam` | Le paywall ou le produit ne dispose pas d'une URL d'achat web configurée, ou l'ouverture de l'URL dans le navigateur a échoué | Consultez le message d'erreur pour plus de détails. Vérifiez la configuration du paywall/produit dans l'Adapty Dashboard, ou vérifiez les paramètres de l'appareil. | | `AdaptyErrorCode.DecodingFailed` | Échec de l'encodage correct des paramètres dans l'URL | Vérifiez que les paramètres d'URL sont valides et correctement formatés | :::note Vérifiez la propriété `Message` de l'erreur pour obtenir des détails sur ce qui s'est mal passé, car `WrongParam` peut indiquer plusieurs problèmes (URL d'achat manquante, échec de l'ouverture du navigateur, etc.). ::: ## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\} :::important L'ouverture des paywalls web dans un navigateur intégré est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les paywalls web s'ouvrent dans le navigateur externe, ce qui fait quitter l'application à l'utilisateur. Pour offrir une expérience fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. La page d'achat web s'affiche alors directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'app. Pour activer cette option, passez `AdaptyWebPresentation.InAppBrowser` à la méthode `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 - Use fallback paywalls" description: "Handle cases when users are offline or Adapty servers aren't available" --- :::warning Les paywalls de secours sont pris en charge par le SDK Unity v2.11 et versions ultérieures. ::: To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection. * **If the application cannot access Adapty servers:** It will be able to display a fallback flow or paywall, and access the local onboarding configuration. * **If the application cannot access the internet:** It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function. :::important Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty. ::: ## Configuration \{#configuration\} 1. Ajoutez les fichiers de configuration de secours dans le répertoire commun `Assets/StreamingAssets` de votre projet. 2. Appelez la méthode `.SetFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible. ```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 }); ``` :::important `SetFallback` doit être exécuté avant que le SDK récupère le flow, le paywall ou l'onboarding cible. ::: Paramètres : | Paramètre | Description | |:-------------|:-----------------------------------------------------| | **fileName** | La chaîne contenant le nom du fichier de configuration de secours. | --- # File: unity-localizations-and-locale-codes --- --- title: "Utiliser les localisations et les codes de langue dans le SDK Unity" description: "Découvrez comment localiser les paywalls dans votre application Unity avec le SDK Adapty." --- <SDKv4> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de locale interviennent lorsqu'Adapty sélectionne la localisation d'un flow et lorsque vous lisez un Remote Config pour un paywall personnalisé. Les codes de locale sont complexes et peuvent varier d'une plateforme à l'autre. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prédire quelle localisation un utilisateur recevra. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty cherche la localisation correspondant à la langue d'un utilisateur, voici ce qui se passe : 1. La chaîne de langue est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`) 2. Adapty recherche la localisation dont le code de langue correspond exactement 3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, Adapty renvoie la localisation `en` par défaut Ainsi, `'pt_BR'`, `pt-BR` et `pt-br` correspondent tous à la même localisation. ## Implémentation des localisations \{#implementing-localizations\} Avec le SDK v4, vous ne transmettez pas de code de langue lors de la récupération d'un flow — le flow est localisé au moment de la création de sa vue. - **Paywalls Flow Builder et Paywall Builder** : Adapty résout automatiquement la localisation depuis l'appareil et les localisations que vous avez configurées dans le builder, donc `CreateFlowView` n'a pas besoin de code de locale. Pour choisir vous-même la localisation, [remplacez-la lors de la création de la vue](#override-the-localization-of-a-flow). - **Paywalls personnalisés (Remote Config)** : `GetFlow` retourne toutes les localisations configurées dans `flow.RemoteConfigs`. Chaque entrée est un `AdaptyRemoteConfig` avec un code `Locale` et un `Dictionary` de valeurs. Sélectionnez l'entrée qui correspond à l'utilisateur, avec votre propre fallback : ```csharp showLineNumbers using System.Linq; using AdaptySDK; Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => { if (error != null) { // handle the error return; } var config = flow.RemoteConfigs.FirstOrDefault(c => c.Locale == "en") ?? flow.RemoteConfigs.FirstOrDefault(); // read your values from config?.Dictionary }); ``` Les règles de correspondance des codes de locale décrites ci-dessus expliquent comment Adapty normalise les codes `Locale` stockés dans chaque Remote Config. ### Remplacer la localisation d'un flow \{#override-the-localization-of-a-flow\} Pour afficher un flow ou un paywall avec une localisation spécifique plutôt que celle qu'Adapty résout depuis l'appareil, passez le code de langue à `SetLocale` lors de la création de la vue : ```csharp showLineNumbers var parameters = new AdaptyUICreateFlowViewParameters() .SetLocale("pt-br"); AdaptyUI.CreateFlowView(flow, parameters, (view, error) => { if (error != null) { // handle the error return; } // view.Locale — the localization the view was built with }); ``` La vue indique la localisation avec laquelle elle a réellement été construite dans `view.Locale` : celle que vous avez demandée si cette localisation existe, ou la localisation par défaut du flow dans le cas contraire. </SDKv4> <SDKv3> ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu dans plusieurs scénarios — par exemple, quand vous cherchez à récupérer le bon paywall selon la localisation actuelle de votre application. Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Nous nous appuyons donc sur une norme interne pour toutes les plateformes que nous supportons. Cependant, étant donné cette complexité, il est essentiel que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin de toujours recevoir ce que vous attendez. ## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\} Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel). ## Correspondance des codes de langue \{#locale-code-matching\} Lorsqu'Adapty reçoit un appel du SDK côté client avec le code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe : 1. La chaîne de langue reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`) 2. Nous cherchons ensuite la localisation dont le code de langue correspond exactement 3. Si aucune correspondance n'est trouvée, nous extrayons la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et cherchons la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, nous renvoyons le contenu dans la langue par défaut du paywall Ainsi, un appareil iOS ayant envoyé `'pt_BR'`, un appareil Android ayant envoyé `pt-BR`, et un autre appareil ayant envoyé `pt-br` obtiendront le même résultat. ## Mise en œuvre des localisations : approche recommandée \{#implementing-localizations-recommended-way\} Si vous vous posez des questions sur les localisations, vous utilisez probablement déjà des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers pour les localisations concernées. Ensuite, récupérez la valeur de cette clé lors de l'appel de notre SDK, comme ceci : ```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('_', '-'); } } ``` De cette façon, vous pouvez vous assurer de contrôler entièrement quelle localisation sera récupérée pour chaque utilisateur de votre application. ## Implémenter les localisations : l'autre approche \{#implementing-localizations-the-other-way\} Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de locale pour chaque localisation. Il s'agit d'extraire un code de locale depuis d'autres objets fournis par votre plateforme, comme ceci : ```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; } } ``` Notez que nous déconseillons cette approche pour plusieurs raisons : 1. Sur iOS, les langues préférées et la locale actuelle ne sont pas identiques. Si vous souhaitez que la localisation soit sélectionnée correctement, vous devrez soit vous appuyer sur la logique d'Apple, qui fonctionne telle quelle si vous utilisez l'approche recommandée avec des fichiers de chaînes localisées, soit la recréer vous-même. 2. Il est difficile de prédire ce que le serveur d'Adapty recevra exactement. Par exemple, sur iOS, il est possible d'obtenir une locale comme `ar_OM@numbers='latn'` sur un appareil et de l'envoyer à notre serveur. Pour cet appel, vous obtiendrez non pas la localisation `ar-om` que vous recherchiez, mais plutôt `ar`, ce qui est probablement inattendu. Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: unity-present-flows-in-observer-mode --- --- title: "Présenter des flows en mode Observer - Unity" description: "Présentez des flows et des paywalls créés avec le Paywall Builder en mode Observer dans votre application Unity tout en gérant les achats avec votre propre code." --- Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être. :::warning Cette section concerne uniquement le [mode Observateur](observer-vs-full-mode). Si vous ne travaillez pas en mode Observateur, consultez la rubrique [Afficher les flows et paywalls](unity-present-paywalls). ::: :::info Cette fonctionnalité nécessite le SDK Adapty Unity 4.0 (bêta) ou version ultérieure — elle n'était auparavant disponible que dans les SDK natifs iOS et Android. Consultez le [guide de migration](migration-to-unity-sdk-v4) pour effectuer la mise à jour. ::: <details> <summary>Avant de commencer à afficher des flows (Cliquez pour développer)</summary> 1. Configurez l'intégration initiale d'Adapty [avec l'App Store](initial_ios) et [avec Google Play](initial-android). 2. Installez et configurez le SDK Adapty. Assurez-vous d'appeler `SetObserverMode(true)` sur le builder de configuration. Consultez le [guide d'installation du SDK Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 3. [Créez des produits](create-product) dans l'Adapty Dashboard. 4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits. 5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement). 6. [Récupérez les flows et leur configuration](unity-get-pb-paywalls) dans le code de votre application mobile. </details> En mode Observer, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou une paywall rendu par Adapty, le SDK appelle votre `IAdaptyUIObserverModeResolver` à la place — effectuez l'achat ou la restauration avec votre propre code à cet endroit. 1. Implémentez l'interface `IAdaptyUIObserverModeResolver` : ```csharp showLineNumbers using System; using AdaptySDK; public class MyObserverModeResolver : IAdaptyUIObserverModeResolver { public void FlowViewDidInitiatePurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, Action onStartPurchase, Action onFinishPurchase ) { onStartPurchase(); // the view shows its loading indicator // make the purchase with your own code, // then report the transaction to Adapty and call: onFinishPurchase(); // the view hides the loading indicator } public void FlowViewDidInitiateRestore( AdaptyUIFlowView view, Action onStartRestore, Action onFinishRestore ) { onStartRestore(); // restore purchases with your own code, then: onFinishRestore(); } } ``` Le méthode `FlowViewDidInitiatePurchase` vous informe que l'utilisateur a lancé un achat, et `FlowViewDidInitiateRestore` — que l'utilisateur a lancé une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse. N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. Cela est nécessaire pour un comportement correct du flow, comme l'affichage du chargement, entre autres : | Callback | Description | | :----------------- | :--------------------------------------------------------------------------------------------- | | onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. | | onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. | | onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a démarré. | | onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. | Le flow reste ouvert pendant que votre code s'exécute — fermez-le vous-même après un achat ou une restauration réussie. 2. Enregistrez le resolver avant d'afficher n'importe quel écran : ```csharp showLineNumbers Adapty.SetObserverModeResolver(new MyObserverModeResolver()); ``` Sans resolver enregistré, le flow n'a aucun moyen de transmettre l'achat à votre code, et rien ne se passe quand l'utilisateur appuie sur le bouton d'achat. 3. Créez et présentez le flow comme d'habitude : [récupérez le flow et créez sa vue](unity-get-pb-paywalls), puis [présentez-le](unity-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — une fois le resolver enregistré, chaque flow ou paywall rendu par Adapty achemine les achats et les restaurations via celui-ci. :::warning N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-unity). Sinon, Adapty ne reconnaîtra pas la transaction et ne pourra pas déterminer le paywall source de l'achat. ::: --- # File: unity-troubleshoot-paywall-builder --- --- title: "Résoudre les problèmes du Paywall Builder dans le SDK Unity" description: "Résoudre les problèmes du Paywall Builder dans le SDK Unity" --- Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK Unity. ## La récupération de la configuration d'un paywall échoue \{#getting-a-paywall-configuration-fails\} **Problème** : La méthode `CreateView` ne parvient pas à récupérer la configuration du paywall. **Raison** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder. **Solution** : Activez le bouton **Show on device** dans le Paywall Builder. <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Le nombre d'affichages du paywall est trop élevé \{#the-paywall-view-number-is-too-big\} **Problème** : Le nombre d'affichages du paywall est deux fois plus élevé que prévu. **Raison** : Vous appelez peut-être `LogShowFlow` (SDK v4+) / `LogShowPaywall` dans votre code, ce qui duplique le compteur d'affichages si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls créés avec ces outils, l'analyse est suivie automatiquement et vous n'avez pas besoin d'utiliser cette méthode. **Solution** : Vérifiez que vous n'appelez pas `LogShowFlow` (SDK v4+) / `LogShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder qui ne sont pas couverts ci-dessus. **Solution** : Mettez à jour le SDK vers la dernière version en utilisant les [guides de migration](unity-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: unity-implement-paywalls-manually --- --- title: "Implémenter les paywalls manuellement dans le SDK Unity" description: "Découvrez comment implémenter les paywalls manuellement dans votre application Unity avec le SDK Adapty." --- ## Accepter les achats \{#accept-purchases\} Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty en utilisant la méthode `makePurchase`. Adapty prendra alors en charge tous les scénarios utilisateur, et vous n'aurez qu'à gérer les résultats des achats. :::important `makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart). ::: <CustomDocCardList ids={['unity-quickstart-manual', 'fetch-paywalls-and-products-unity', 'present-remote-config-paywalls-unity', 'unity-making-purchases', 'unity-restore-purchase', 'unity-troubleshoot-purchases']} /> ## Mode observateur \{#observer-mode\} Si vous souhaitez implémenter votre propre logique de gestion des achats from scratch, tout en bénéficiant des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur. :::important Consultez les limitations du mode observateur [ici](observer-vs-full-mode). ::: <CustomDocCardList ids={['implement-observer-mode-unity', 'report-transactions-observer-mode-unity', 'unity-troubleshoot-purchases']} /> --- # File: unity-quickstart-manual --- --- title: "Activer les achats dans votre paywall personnalisé avec le SDK Unity" description: "Intégrez le SDK Adapty dans vos paywalls Unity personnalisés pour activer les achats intégrés." --- Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les achats précédents. Ce guide utilise les APIs du SDK Adapty Unity v4 (bêta) — si vous utilisez la v3, consultez le [guide de migration](migration-to-unity-sdk-v4) pour les noms de méthodes correspondants. :::important **Ce guide est destiné aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la solution la plus simple pour activer les achats, utilisez l'[Adapty Flow Builder](unity-quickstart-paywalls). Avec Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différents designs sans republier votre application. ::: ## Avant de commencer \{#before-you-start\} ### Configurer les produits \{#set-up-products\} Pour activer les achats intégrés, vous devez comprendre trois concepts clés : - [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie) - [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. Dans le SDK v4, les variantes de paywall d'un placement sont portées par un objet **flow** — vous récupérez un flow et interrogez ses produits. - [**Placements**](placements) – où et quand vous affichez les paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par identifiant de placement dans votre code. Cela facilite la mise en place de tests A/B et l'affichage de paywalls différents selon les utilisateurs. Assurez-vous de bien comprendre ces concepts, même si vous utilisez un paywall personnalisé. Ce sont simplement votre façon de gérer les produits que vous vendez dans votre application. Pour mettre en place votre paywall personnalisé, vous devez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour savoir ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart). ### Gérer les utilisateurs \{#manage-users\} Vous pouvez travailler avec ou sans authentification backend de votre côté. Cependant, le SDK gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](unity-quickstart-identify) pour comprendre les spécificités et vous assurer que vous gérez correctement vos utilisateurs. ## Étape 1. Récupérer les produits \{#step-1-get-products\} Pour récupérer les produits de votre paywall personnalisé, vous devez : 1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `GetFlow`. 2. Récupérer le tableau de produits pour ce flow à l'aide de la méthode `GetPaywallProducts`. ```csharp showLineNumbers using AdaptySDK; void LoadPaywall() { Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => { if (error != null) { // Handle the error return; } Adapty.GetPaywallProducts(flow, (products, productsError) => { if (productsError != null) { // Handle the error return; } // Use products to build your custom paywall UI }); }); } ``` ## Étape 2. Accepter les achats \{#step-2-accept-purchases\} Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `MakePurchase` avec le produit sélectionné. Cette méthode gère le processus d'achat et retourne le profil mis à jour. ```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; } }); } ``` ## Étape 3. Restaurer les achats \{#step-3-restore-purchases\} Les stores exigent que toutes les applications proposant des abonnements offrent un moyen aux utilisateurs de restaurer leurs achats. Appelez la méthode `RestorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et renverra le profil mis à jour. ```csharp showLineNumbers using AdaptySDK; void RestorePurchases() { Adapty.RestorePurchases((profile, error) => { if (error != null) { // Handle the error return; } // Restore successful, profile updated }); } ``` ## Étape 4. Vérifier le statut de l'abonnement \{#step-4-check-the-subscription-status\} Après un achat ou une restauration, vérifiez le [niveau d'accès](access-level) de l'utilisateur pour décider d'afficher le paywall ou de débloquer les fonctionnalités payantes. Les méthodes `MakePurchase` et `RestorePurchases` retournent déjà le profil mis à jour ; chaque fois que vous avez besoin du statut actuel ailleurs dans l'application, utilisez la méthode `GetProfile` : ```csharp showLineNumbers using AdaptySDK; void CheckPremiumAccess() { Adapty.GetProfile((profile, error) => { if (error != null) { // Handle the error return; } var hasPremiumAccess = profile.AccessLevels.TryGetValue("premium", out var premium) && premium.IsActive; // Grant access to paid features if hasPremiumAccess is true }); } ``` Pour d'autres façons de vérifier et de surveiller le statut de l'abonnement, notamment en écoutant les mises à jour en temps réel, consultez [Vérifier le statut de l'abonnement](unity-check-subscription-status). ## Prochaines étapes \{#next-steps\} :::tip Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider ! ::: Votre paywall est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans [Google Play Store](testing-on-android) pour vous assurer que vous pouvez effectuer un achat test depuis le paywall. --- # File: fetch-paywalls-and-products-unity --- --- title: "Récupérer les paywalls et produits pour les paywalls Remote Config dans le SDK Unity" description: "Récupérez les paywalls et produits dans le SDK Unity d'Adapty pour optimiser la monétisation des utilisateurs." --- <SDKv4> Avant de présenter la configuration distante et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que ce sujet traite de Remote Config et des paywalls personnalisés. Pour obtenir des instructions sur la récupération des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Récupérer les flows et paywalls](unity-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-unity) dans votre application mobile. </details> ## Récupérer les informations d'un flow \{#fetch-flow-information\} Dans Adapty, un [produit](product) est une combinaison de produits provenant de l'App Store et de Google Play. Ces produits multi-plateformes sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) à l'aide de la méthode `GetFlow`. :::important **N'encodez pas les identifiants de produits en dur.** Le seul identifiant à coder en dur est l'identifiant du placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un flow retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```csharp showLineNumbers Adapty.GetFlow( "YOUR_PLACEMENT_ID", AdaptyPlacementFetchPolicy.Default, TimeSpan.FromSeconds(5), (flow, error) => { if (error != null) { // handle the error return; } // flow - the requested flow } ); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPlacementFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les flows et les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](unity-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir en permanence la dernière version de vos flows et paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après la valeur spécifiée dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en coulisses.</p> | Ne codez pas les identifiants de produit en dur ! Puisque les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère bien ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à coder en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objet `AdaptyFlow` contenant : l'identifiant du flow, les variantes de paywall (`Paywalls` — chacune avec ses propres identifiants de produits), une liste `RemoteConfigs` (une entrée par locale configurée), et plusieurs autres propriétés. Pour récupérer les produits du flow, appelez `GetPaywallProducts(flow)`. | :::note Dans la v4, `GetFlow` n'a pas de paramètre `locale`. Lorsque vous affichez un flow avec `CreateFlowView`, la localisation est résolue automatiquement. Pour les paywalls personnalisés, toutes les localisations disponibles sont retournées ensemble dans `flow.RemoteConfigs` — choisissez la locale correspondant à l'appareil de l'utilisateur ou au paramètre de votre application. Consultez [Localisations et codes de langue](unity-localizations-and-locale-codes) pour plus de détails. ::: ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond : ```csharp showLineNumbers Adapty.GetPaywallProducts(flow, (products, error) => { if (error != null) { // handle the error return; } // products - the requested products array }); ``` Paramètres de la réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets `AdaptyPaywallProduct` contenant : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. | Lors de la mise en œuvre de votre propre design de flow, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet `AdaptyPaywallProduct`. Les propriétés les plus couramment utilisées sont illustrées ci-dessous. | Propriété | Description | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.LocalizedTitle`. La localisation se base sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. | | **Price** | Pour afficher une version localisée du prix, utilisez `product.Price.LocalizedString`. Cette localisation se base sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme numérique via `product.Price.Amount` — la valeur est fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.Price.CurrencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.Subscription?.LocalizedPeriod`. Cette localisation se base sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.Subscription?.Period`. Vous pouvez ensuite accéder à l'enum `Unit` pour obtenir la durée (c'est-à-dire `AdaptySubscriptionPeriodUnit.Day`, `AdaptySubscriptionPeriodUnit.Week`, `AdaptySubscriptionPeriodUnit.Month`, `AdaptySubscriptionPeriodUnit.Year`, ou `AdaptySubscriptionPeriodUnit.Unknown`). La valeur `NumberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `AdaptySubscriptionPeriodUnit.Month` dans la propriété `Unit`, et `3` dans la propriété `NumberOfUnits`. | | **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.Subscription?.Offer?.Phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase expose les propriétés suivantes :<br/>• `PaymentMode` : un enum avec les valeurs `AdaptyPaymentMode.FreeTrial`, `AdaptyPaymentMode.PayAsYouGo`, `AdaptyPaymentMode.PayUpFront` et `AdaptyPaymentMode.Unknown`. Les essais gratuits correspondent au type `AdaptyPaymentMode.FreeTrial`.<br/>• `Price` : un objet `AdaptyPrice` contenant le prix remisé — utilisez `Price.Amount` pour la valeur numérique et `Price.LocalizedString` pour l'afficher. Pour les essais gratuits, vérifiez que `Price.Amount` vaut `0`.<br/>• `LocalizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil décrivant la durée de l'offre. Par exemple, un essai de trois jours affiche `"3 days"` dans ce champ.<br/>• `SubscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Son fonctionnement est identique à ce qui est décrit dans la section précédente.<br/>• `LocalizedSubscriptionPeriod` : une période d'abonnement formatée pour la locale de l'utilisateur. | ## Accélérer la récupération des flows avec le flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\} En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Toutefois, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour remédier à cela, vous pouvez utiliser la méthode `GetFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `GetFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-unity#fetch-flow-information) ci-dessus. :::warning Pourquoi nous recommandons d'utiliser `GetFlow` La méthode `GetFlowForDefaultAudience` présente quelques inconvénients majeurs : - **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent avoir des problèmes avec des flows non rendus. - **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés). Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `GetFlowForDefaultAudience` comme suit. Sinon, restez sur `GetFlow` décrite [ci-dessus](fetch-paywalls-and-products-unity#fetch-flow-information). ::: ```csharp showLineNumbers Adapty.GetFlowForDefaultAudience( "YOUR_PLACEMENT_ID", AdaptyPlacementFetchPolicy.Default, (flow, error) => { if (error != null) { // handle the error return; } // flow - the requested flow } ); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **fetchPolicy** | par défaut : `AdaptyPlacementFetchPolicy.Default` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.</p> | </SDKv4> <SDKv3> Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que ce sujet concerne le Remote Config et les paywalls personnalisés. Pour obtenir des instructions sur la récupération des paywalls pour les paywalls personnalisés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](unity-get-pb-paywalls). :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: <details> <summary>Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)</summary> 1. [Créez vos produits](create-product) dans l'Adapty Dashboard. 2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard. 3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard. 4. [Installez le SDK Adapty](sdk-installation-unity) dans votre application mobile. </details> ## Récupérer les informations d'un paywall \{#fetch-paywall-information\} Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile. Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`. :::important **N'inscrivez pas les ID produit en dur dans le code.** Le seul ID à coder en dur est l'ID du placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code. ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` | Paramètre | Présence | Description | |---------|--------|-----------| | **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p></p><p>Consultez [Localisations et codes de langue](unity-localizations-and-locale-codes) pour en savoir plus sur les codes de langue et notre approche recommandée.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne bénéficieront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](unity-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p></p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en arrière-plan.</p> | N'écrivez pas les identifiants de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer à tout moment. Assurez-vous que votre code gère ces scénarios. Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modifications du code. La seule chose à écrire en dur est l'identifiant du placement. Paramètres de réponse : | Paramètre | Description | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objet [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config, et plusieurs autres propriétés. | ## Récupérer les produits \{#fetch-products\} Une fois que vous avez le paywall, vous pouvez récupérer le tableau de produits qui lui correspond : ```csharp showLineNumbers Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { // handle the error return; } // products - the requested products array }); ``` Paramètres de réponse : | Paramètre | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Liste d'objets [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) contenant : l'identifiant du produit, le nom du produit, le prix, la devise, la durée de l'abonnement, ainsi que d'autres propriétés. | Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir des informations complètes sur toutes les propriétés disponibles. | Propriété | Description | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Pour afficher le titre du produit, utilisez `product.LocalizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur et non sur la langue de l'appareil. | | **Price** | Pour afficher le prix dans une version localisée, utilisez `product.Price.LocalizedString`. Cette localisation est basée sur les informations de langue de l'appareil. Vous pouvez également accéder au prix sous forme numérique via `product.Price.Amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.Price.CurrencySymbol`. | | **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.Subscription?.LocalizedPeriod`. Cette localisation est basée sur la langue de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.Subscription?.Period`. Vous pouvez ensuite accéder à l'enum `Unit` pour obtenir la durée (c'est-à-dire `AdaptySubscriptionPeriodUnit.Day`, `AdaptySubscriptionPeriodUnit.Week`, `AdaptySubscriptionPeriodUnit.Month`, `AdaptySubscriptionPeriodUnit.Year` ou `AdaptySubscriptionPeriodUnit.Unknown`). La valeur `NumberOfUnits` indique le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous obtiendrez `AdaptySubscriptionPeriodUnit.Month` dans la propriété Unit et `3` dans la propriété NumberOfUnits. | | **Introductory Offer** | Pour afficher un badge ou un autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.Subscription?.Offer?.Phases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :<br/>• `PaymentMode` : un enum avec les valeurs `AdaptyPaymentMode.FreeTrial`, `AdaptyPaymentMode.PayAsYouGo`, `AdaptyPaymentMode.PayUpFront` et `AdaptyPaymentMode.Unknown`. Les essais gratuits correspondent au type `AdaptyPaymentMode.FreeTrial`.<br/>• `Price` : un objet `AdaptyPrice` avec le prix réduit — utilisez `Price.Amount` pour la valeur numérique et `Price.LocalizedString` pour l'afficher. Pour les essais gratuits, vérifiez que `Price.Amount` vaut `0`.<br/>• `LocalizedNumberOfPeriods` : une chaîne localisée selon la langue de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `"3 days"` dans ce champ.<br/>• `SubscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété. Elle fonctionne de la même manière pour les offres que la section précédente le décrit.<br/>• `LocalizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon la langue de l'utilisateur. | ## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\} En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout. Pour y remédier, vous pouvez utiliser la méthode `GetPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée consiste à récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer le paywall](#fetch-paywall-information) ci-dessus. :::warning Préférez `GetPaywall` à `GetPaywallForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : peut créer des difficultés lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les versions plus anciennes s'affichent incorrectement. - **Aucune personnalisation** : affiche uniquement le contenu pour l'audience « Tous les utilisateurs », sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si la rapidité de récupération l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `GetPaywallForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `GetPaywall` comme décrit [ci-dessus](#fetch-paywall-information). ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation du paywall. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second désigne la région.</p><p></p><p>Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser en cours de session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les paywalls de secours. Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | </SDKv3> --- # File: present-remote-config-paywalls-unity --- --- title: "Afficher un paywall conçu avec Remote Config dans le SDK Unity" description: "Découvrez comment afficher des paywalls Remote Config dans le SDK Adapty Unity pour personnaliser l'expérience utilisateur." --- <SDKv4> Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher à vos utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous laissant toute liberté pour afficher votre paywall personnalisé. ## Récupérer le Remote Config d'un flow et l'afficher \{#get-flow-remote-config-and-present-it\} Dans la v4, un flow comporte une entrée `AdaptyRemoteConfig` par locale configurée dans la liste `RemoteConfigs`. Sélectionnez la locale correspondant à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin. ```csharp showLineNumbers using System.Linq; using AdaptySDK; Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => { if (error != null) { // handle the error return; } var config = flow.RemoteConfigs.FirstOrDefault(c => c.Locale == "en") ?? flow.RemoteConfigs.FirstOrDefault(); var headerText = config?.Dictionary?["header_text"] as string; // Or access raw JSON data var jsonData = config?.Data; }); ``` À ce stade, une fois que vous avez reçu toutes les valeurs nécessaires, il est temps de les afficher et de les assembler en une page visuellement attrayante. Assurez-vous que le design s'adapte aux différents écrans et orientations des téléphones mobiles, offrant une expérience fluide et conviviale sur tous les appareils. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-unity#track-paywall-view-events) comme décrit ci-dessous, afin de permettre à Adapty Analytics de collecter des informations pour les entonnoirs et les tests A/B. ::: Une fois le paywall affiché, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.MakePurchase()` avec le produit de votre flow. Pour plus de détails sur la méthode `.MakePurchase()`, consultez [Effectuer des achats](unity-making-purchases). Nous vous recommandons de [créer un paywall de secours](unity-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage des paywalls \{#track-paywall-view-events\} Adapty vous aide à mesurer la performance de vos flows et paywalls. Les données sur les achats sont collectées automatiquement, mais l'enregistrement des vues requiert votre intervention, car vous seul savez quand un utilisateur voit un flow. Pour enregistrer un événement de vue, appelez simplement `.LogShowFlow(flow)` — cela sera reflété dans vos métriques dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.LogShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les vues automatiquement dans ces cas. ::: ```csharp showLineNumbers Adapty.LogShowFlow(flow, (error) => { // handle the error }); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :-------- | :------- |:-----------------------------------------------------------------| | **flow** | required | Un objet `AdaptyFlow` obtenu via `Adapty.GetFlow`. | </SDKv4> <SDKv3> Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Remote Config offrant une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant ainsi toute liberté pour afficher votre paywall personnalisé configuré via Remote Config. ## Récupérer le Remote Config d'un paywall et l'afficher \{#get-paywall-remote-config-and-present-it\} Pour obtenir le Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs dont vous avez besoin. ```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; }); ``` À ce stade, une fois que vous avez reçu toutes les valeurs nécessaires, il est temps d'afficher et d'assembler ces données dans une page visuellement attrayante. Assurez-vous que le design s'adapte aux différentes tailles d'écrans et orientations des mobiles, pour offrir une expérience fluide et agréable sur tous les appareils. :::warning Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-unity#track-paywall-view-events-1) comme décrit ci-dessous, afin que les analytics Adapty puissent collecter les données nécessaires aux entonnoirs et aux tests A/B. ::: Une fois le paywall affiché, passez à la configuration du flux d'achat. Lorsqu'un utilisateur effectue un achat, appelez simplement `.MakePurchase()` avec le produit de votre paywall. Pour plus de détails sur la méthode `.MakePurchase()`, consultez [Effectuer des achats](unity-making-purchases). Nous recommandons de [créer un paywall de secours](unity-use-fallback-paywalls). Ce paywall de secours s'affichera à l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations. ## Suivre les événements d'affichage de paywall \{#track-paywall-view-events\} Adapty vous aide à mesurer les performances de vos paywalls. Bien que les données d'achats soient collectées automatiquement, l'enregistrement des affichages de paywall nécessite votre intervention, car vous seul savez quand un client voit un paywall. Pour enregistrer un événement d'affichage de paywall, appelez simplement `.LogShowPaywall(paywall)` : cela sera reflété dans vos métriques de paywall dans les entonnoirs et les tests A/B. :::important Il n'est pas nécessaire d'appeler `.LogShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder). ::: ```csharp showLineNumbers Adapty.LogShowPaywall(paywall, (error) => { // handle the error }); ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:------------------------------------------------------------------| | **paywall** | requis | Un objet [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | </SDKv3> --- # File: unity-making-purchases --- --- title: "Effectuer des achats dans une application mobile avec le SDK Unity" description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty." --- Afficher des paywalls dans votre application mobile est une étape essentielle pour offrir aux utilisateurs l'accès à des contenus ou services premium. Cependant, afficher ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour les personnaliser. Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode dédiée appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode constitue le point d'entrée permettant aux utilisateurs d'interagir avec les paywalls et de procéder à leurs transactions. Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat. :::warning Notez que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder. Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Sauter cette étape risque d'entraîner le rejet de votre application lors de sa mise en ligne. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs pourtant éligibles à une offre de lancement. ::: Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans elle, nous ne pouvons pas valider les achats. ## Effectuer un achat \{#make-purchase\} :::note **Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape. **Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](unity-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire. ::: ```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; } }); } ``` Paramètres de la requête : | Paramètre | Présence | Description | | :---------- | :------- |:------------------------------------------------------------------------------------------------------| | **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) récupéré depuis le paywall. | Paramètres de la réponse : | Paramètre | Description | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Si la requête a réussi, la réponse contient cet objet. Un objet [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur dans l'application.</p><p>Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.</p> | :::warning **Remarque :** si vous utilisez encore StoreKit en version inférieure à v2.0 et le SDK Adapty en version inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple. ::: ## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\} Lorsqu'un utilisateur choisit un nouvel abonnement plutôt que de renouveler celui en cours, le fonctionnement dépend du store : - Sur l'App Store, l'abonnement est automatiquement mis à jour au sein du groupe d'abonnements. Si un utilisateur souscrit à un abonnement d'un groupe alors qu'il en a déjà un d'un autre groupe, les deux abonnements seront actifs en même temps. - Sur Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous. Pour remplacer un abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire suivant : ```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 }); ``` Paramètre de requête supplémentaire : | Paramètre | Présence | Description | | :--------------------------- | :------- |:-------------------------------------------------------------------------------------------------------| | **subscriptionUpdateParams** | requis | un objet [`AdaptySubscriptionUpdateParameters`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_subscription_update_parameters.html). | Vous pouvez en apprendre davantage sur les abonnements et les modes de remplacement dans la documentation Google pour les développeurs : - [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge. - Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation en cours. ## Utiliser des codes d'offre sur iOS \{#redeem-offer-codes-in-ios\} <Details> <summary>À propos des codes d'offre</summary> Les codes d'offre vous permettent d'accorder des réductions ou des périodes d'essai gratuites à des utilisateurs spécifiques. Contrairement aux offres classiques appliquées automatiquement, les codes d'offre sont distribués en dehors de l'application — par e-mail, réseaux sociaux ou supports imprimés. Les utilisateurs les activent en saisissant le code dans l'App Store, en suivant une URL de validation ou via une boîte de dialogue intégrée à l'application. Pour configurer des codes d'offre, ouvrez un abonnement dans App Store Connect et accédez à sa section **Offer Codes**. Vous pouvez créer [trois types](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes) de codes d'offre : - **Free** — l'abonnement est gratuit pendant une durée définie, puis le renouvellement suivant se fait au plein tarif. - **Pay as you go** — l'utilisateur paie un tarif réduit à chaque cycle de facturation pendant une durée définie, puis l'abonnement se renouvelle au plein tarif. - **Pay up front** — l'utilisateur paie un prix unique réduit pour toute la durée de l'offre, puis l'abonnement se renouvelle au plein tarif. Vous n'avez pas besoin d'ajouter les codes d'offre à Adapty. Apple marque chaque transaction pendant la période d'offre avec la catégorie du code d'offre. Cela inclut la première activation et tous les renouvellements à tarif réduit qui suivent. Adapty détecte ce marquage et enregistre chaque transaction avec la catégorie d'offre `offer_code`. Une fois la période d'offre terminée et l'abonnement renouvelé au plein tarif, le marquage disparaît. Vous pouvez filtrer les analyses par le type d'offre **Offer Code** dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds). #### Résolution des écarts de revenus \{#revenue-discrepancy-troubleshooting\} Si vous constatez qu'une transaction avec code d'offre apparaît dans Adapty au prix plein du produit plutôt qu'au prix réduit de l'offre, vérifiez les points suivants dans App Store Connect : - Le code d'offre dispose bien d'une tarification correcte configurée pour toutes les régions où les utilisateurs peuvent l'activer. - Le prix de l'offre est défini pour le pays ou la région spécifique de l'utilisateur. Apple envoie le prix régional dans la transaction. Si aucun prix régional n'est configuré pour l'offre, Apple peut envoyer le prix plein du produit à la place. Vous pouvez filtrer et vérifier les transactions avec code d'offre dans l'[Adapty Dashboard](controls-filters-grouping-compare-proceeds) à l'aide des filtres de type d'offre **Offer Code** et **Offer Discount Type**. #### Anciens codes promo (obsolètes) \{#legacy-promo-codes-deprecated\} :::warning Apple a supprimé les codes promo pour les achats intégrés en mars 2026. Les codes d'offre les remplacent avec davantage de fonctionnalités : éligibilité configurable, dates d'expiration et jusqu'à 1 million de codes par trimestre. Si vous utilisiez auparavant des codes promo pour les achats intégrés, passez aux codes d'offre dans App Store Connect. ::: Les anciens codes promo (limités à 100 par application et par version) donnaient un accès gratuit à un abonnement. Contrairement aux codes d'offre, Apple n'incluait pas les informations de réduction dans les transactions avec code promo — il envoyait le prix plein du produit dans le reçu. En conséquence, Adapty enregistrait ces transactions au prix plein, ce qui entraînait des écarts de revenus entre les analyses Adapty et App Store Connect. Si vous constatez des transactions historiques au prix plein qui auraient dû être gratuites, elles proviennent probablement d'anciens codes promo. Ces codes étant désormais obsolètes, passez aux codes d'offre pour un suivi précis des revenus. </Details> Pour afficher la feuille de saisie de code dans votre application : ```csharp showLineNumbers Adapty.PresentCodeRedemptionSheet((error) => { // handle the error }); ``` :::danger D'après nos observations, la feuille de rachat de code d'offre peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store. Pour ce faire, ouvrez une URL au format suivant : `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ## Gérer les plans prépayés (Android) \{#manage-prepaid-plans-android\} Si les utilisateurs de votre application peuvent acheter des [plans prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, souscrire à un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour les plans prépayés. ```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: "Restaurer les achats dans une application mobile avec le SDK Unity" description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide." --- La restauration des achats sur iOS et Android permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés — abonnements ou achats intégrés — sans être débités à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé et réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leurs achats sans repayer. :::note Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement, sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape. ::: Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.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 } }); ``` Paramètres de réponse : | Paramètre | Description | |---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>Un objet [`AdaptyProfile`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.</p><p>Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.</p> | :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: --- # File: implement-observer-mode-unity --- --- title: "Implémenter le mode Observateur dans le SDK Unity" description: "Implémentez le mode observateur dans Adapty pour suivre les événements d'abonnement utilisateur dans le SDK Unity." --- Si vous disposez déjà de votre propre infrastructure d'achat et n'êtes pas prêt à passer entièrement à Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analyse. Si cela correspond à vos besoins, il vous suffit de : 1. L'activer lors de la configuration du SDK en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 2. [Signaler les transactions](report-transactions-observer-mode-unity) depuis votre infrastructure d'achat existante à Adapty. :::tip Dans la version 4 du SDK, vous pouvez également présenter des flows et des paywalls rendus par Adapty en mode Observer : lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration, le SDK transmet l'action à votre code afin que vous puissiez effectuer l'achat ou la restauration vous-même. Voir [Présenter des flows en mode Observer](unity-present-flows-in-observer-mode). ::: ### Configuration du mode Observateur \{#observer-mode-setup\} Activez le mode Observateur si vous gérez vous-même les achats et le statut des abonnements, et que vous utilisez Adapty uniquement pour l'envoi d'événements d'abonnement et l'analytique. :::important En mode Observateur, le SDK Adapty ne clôture aucune transaction — assurez-vous de les gérer vous-même. ::: :::note Dans le SDK 4.0, les interfaces de listener suivent la convention C# avec le préfixe I : implémentez `IAdaptyEventListener` plutôt que `AdaptyEventListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: ```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) { } } ``` | Paramètre | Description | |--------------|---------------------------------------------------------------------------------------------------------------------| | observerMode | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. | ## Utiliser les paywalls Adapty en mode Observer \{#using-adapty-paywalls-in-observer-mode\} Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observer. Voici ce que vous devrez faire en plus des étapes ci-dessus : 1. Affichez les paywalls normalement pour les [paywalls avec Remote Config](present-remote-config-paywalls-unity). 3. [Associez les paywalls](report-transactions-observer-mode-unity) aux transactions d'achat. --- # File: report-transactions-observer-mode-unity --- --- title: "Signaler les transactions en Observer Mode dans le SDK Unity" description: "Signalez les transactions d'achat en Observer Mode Adapty pour obtenir des informations utilisateurs et suivre les revenus dans le SDK Unity." --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+ (current)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store. Il est crucial de le configurer **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `ReportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela lie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```csharp showLineNumbers Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requis | <ul><li> Pour iOS : identifiant de la transaction.</li><li> Pour Android : identifiant de type String `purchase.getOrderId` de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type String de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store ou les restaurer. Il est crucial de le configurer **avant** de publier votre application pour éviter des erreurs dans les analyses. Utilisez `reportTransaction` sur les deux plateformes pour signaler explicitement chaque transaction, et utilisez `restorePurchases` sur Android comme étape supplémentaire pour vous assurer qu'Adapty la reconnaisse. :::warning **Ne sautez pas le signalement des transactions et la restauration des achats !** Si vous n'appelez pas ces méthodes, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: Si vous utilisez des paywalls Adapty, incluez le `PAYWALL_VARIATION_ID` lors du signalement d'une transaction. Cela lie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises. ```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 }); ``` Paramètres : | Paramètre | Présence | Description | | ------------- | -------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requis | <ul><li> Pour iOS, StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</li><li> Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</li><li> Pour Android : identifiant de type String (`purchase.getOrderId`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</li></ul> | | variationId | optionnel | L'identifiant de type String de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **Signalement des transactions** - Les versions jusqu'à 3.1.x écoutent automatiquement les transactions dans l'App Store, le signalement manuel n'est donc pas nécessaire. - La version 3.2 ne prend pas en charge l'Observer Mode. </TabItem> <TabItem value="kotlin" label="Android and Android-based cross-platforms" default> **Signalement des transactions** Utilisez `restorePurchases` pour signaler une transaction à Adapty en Observer Mode, comme expliqué sur la page [Restaurer les achats dans le code mobile](unity-restore-purchase). :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: </TabItem> </Tabs> **Association des paywalls aux transactions** Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous souhaitez utiliser des paywalls et/ou des tests A/B en Observer Mode, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de bien configurer cela avant de publier votre application, sinon cela entraînera des erreurs dans les analyses. ```csharp Adapty.SetVariationForTransaction("<variationId>", "<transactionId>", (error) => { if(error != null) { // handle the error return; } // successful binding }); ``` | Paramètre | Présence | Description | | ------------------------------------------------------ | -------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | requis | <p>Pour iOS, StoreKit 1 : un objet [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).</p><p>Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).</p><p>Pour Android : identifiant de type String (purchase.getOrderId de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.</p> | | variationId | requis | L'identifiant de type String de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | </TabItem> </Tabs> --- # File: unity-troubleshoot-purchases --- --- title: "Troubleshoot purchases in Unity SDK" description: "Troubleshoot purchases in Unity SDK" --- Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Unity. ## makePurchase est appelé avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et le statut de l'abonnement ne sont pas mis à jour dans Adapty. **Cause** : Cela indique généralement une configuration incomplète du Google Play Store. **Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android). ## makePurchase est appelé deux fois \{#makepurchase-is-invoked-twice\} **Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat. **Cause** : Cela se produit généralement lorsque le flow d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur. **Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android). ## AdaptyError.cantMakePayments en mode observateur \{#adaptyelrorcantmakepayments-in-observer-mode\} **Problème** : Vous obtenez `AdaptyError.cantMakePayments` en utilisant `makePurchase` en mode observateur. **Cause** : En mode observateur, vous devez gérer les achats de votre côté et ne pas utiliser la méthode `makePurchase` d'Adapty. **Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observateur. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observateur. Consultez [Implémenter le mode observateur](implement-observer-mode-unity) pour plus de détails. ## Erreur 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\} **Problème** : Vous recevez une erreur de facturation indisponible depuis le Google Play Store. **Cause** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil. **Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\} **Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui est introuvable. **Cause** : Cela est généralement lié à des problèmes de test en sandbox. **Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de complétion d'achat liés au sandbox. ## Autres problèmes \{#other-issues\} **Problème** : Vous rencontrez d'autres problèmes liés aux achats qui ne sont pas couverts ci-dessus. **Solution** : Migrez le SDK vers la dernière version à l'aide des [guides de migration](unity-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK. --- # File: unity-user --- --- title: "Utilisateurs et accès dans Unity SDK" description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application Unity avec le SDK Adapty." --- <CustomDocCardList /> --- # File: unity-identifying-users --- --- title: "Identifier les utilisateurs dans le SDK Unity" description: "Découvrez comment identifier les utilisateurs dans votre application Unity avec le SDK Adapty." --- Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous pouvez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyée à toutes les intégrations. ### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\} Si vous disposez d'un identifiant utilisateur lors de la configuration, passez-le simplement en tant que paramètre `customerUserId` à la méthode `.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 Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\} Si vous n'avez pas d'identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas les plus courants d'utilisation de cette méthode sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié. ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { if(error == null) { // successful identify } }); ``` Paramètres de la requête : - **Customer User ID** (obligatoire) : un identifiant utilisateur de type chaîne de caractères. :::warning Resoumission des données utilisateur importantes Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty possèdent déjà des informations sur cet utilisateur. Dans ces situations, le SDK Adapty basculera automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, telles que des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez soumettre à nouveau ces données pour l'utilisateur identifié. Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes. ::: ### Déconnexion et reconnexion \{#logging-out-and-logging-in\} Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` : ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` Vous pouvez ensuite reconnecter l'utilisateur à l'aide de la méthode `.identify()`. ## Assigner un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de relier les transactions de l'App Store à l'identité interne de vos utilisateurs. StoreKit associe ce token à chaque transaction, afin que votre backend puisse faire correspondre les données de l'App Store à vos utilisateurs. Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils. Cela garantit que les achats et les notifications de l'App Store restent correctement associés. Vous pouvez définir le token de deux manières : lors de l'activation du SDK ou lors de l'identification de l'utilisateur. :::important Vous devez toujours passer `appAccountToken` avec `customerUserId`. Si vous ne passez que le token, il ne sera pas inclus dans la transaction. ::: ```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 } }); ``` ## Définir des identifiants de compte masqués (Android) \{#set-obfuscated-account-ids-android\} Google Play exige des identifiants de compte masqués pour certains cas d'usage afin de renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants permettent à Google Play d'identifier les achats tout en gardant les informations des utilisateurs anonymes, ce qui est particulièrement important pour la prévention des fraudes et l'analyse. Vous devrez peut-être définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations spécifiques en matière de confidentialité. Les identifiants masqués permettent à Google Play de suivre les achats sans exposer les véritables identifiants des utilisateurs. ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; // During configuration: 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) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID", (error) => { if (error == null) { // successful identify } }); ``` ## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\} Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`. Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID. **Ce qu'Adapty peut détecter entre les appareils** | Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire | | --- | --- | --- | | Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. | | Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. | | Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. | | Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. | **Restaurer les achats sur un nouvel appareil** Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK. Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`. --- # File: unity-setting-user-attributes --- --- title: "Définir les attributs utilisateur dans le SDK Unity" description: "Apprenez à mettre à jour les attributs utilisateur et les données de profil dans votre application Unity avec le SDK Adapty." --- Vous pouvez définir des attributs optionnels tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM. ### Définir les attributs utilisateur \{#setting-user-attributes\} Pour définir les attributs utilisateur, appelez la méthode `.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 } }); ``` Notez que les attributs que vous avez précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ### Liste des clés autorisées \{#the-allowed-keys-list\} Les clés `<Key>` autorisées de `AdaptyProfileParameters.Builder` et les valeurs `<Value>` correspondantes sont répertoriées ci-dessous : | Clé | Valeur | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum, les valeurs autorisées sont : `female`, `male`, `other` | | birthday | Date | ### Attributs utilisateur personnalisés \{#custom-user-attributes\} Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblés, ainsi que dans les analyses pour identifier quelles métriques produit influencent le plus les revenus. ```csharp showLineNumbers try { builder = builder.SetCustomStringAttribute("string_key", "string_value"); builder = builder.SetCustomDoubleAttribute("double_key", 123.0f); } catch (Exception e) { // handle the exception } ``` Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` : ```csharp showLineNumbers try { builder = builder.RemoveCustomAttribute("key_to_remove"); } catch (Exception e) { // handle the exception } ``` Il peut parfois être utile de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`. :::warning Gardez à l'esprit que la valeur de `customAttributes` peut ne pas être à jour, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment — les attributs sur le serveur peuvent donc avoir été modifiés depuis la dernière synchronisation. ::: ### Limites \{#limits\} - Jusqu'à 30 attributs personnalisés par utilisateur - Les noms de clés peuvent comporter jusqu'à 30 caractères. Le nom de clé peut contenir des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.` - La valeur peut être une chaîne de caractères ou un nombre décimal (float) d'au plus 50 caractères. --- # File: unity-listen-subscription-changes --- --- title: "Vérifier le statut d'abonnement dans le SDK Unity" description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Unity." --- Avec Adapty, suivre le statut d'un abonnement est simple. Vous n'avez pas besoin d'insérer manuellement des ID de produits dans votre code. Il vous suffit de vérifier l'existence d'un [niveau d'accès](access-level) actif pour confirmer le statut d'abonnement d'un utilisateur. <details> <summary>Avant de vérifier le statut d'abonnement (Cliquez pour développer)</summary> - Pour iOS, configurez les [App Store Server Notifications](enable-app-store-server-notifications) - Pour Android, configurez les [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn) </details> ## Niveau d'accès et l'objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Nous recommandons de récupérer le profil au démarrage de votre application, par exemple lorsque vous [identifiez un utilisateur](unity-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque fois que des modifications surviennent. Ainsi, vous pouvez utiliser l'objet profil sans avoir à le redemander à chaque fois. Pour être notifié des mises à jour de profil, écoutez les changements de profil comme décrit dans la section [Écouter les mises à jour de profil, y compris les niveaux d'accès](#listening-for-subscription-status-updates) ci-dessous. :::tip Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base. ::: ## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\} Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.GetProfile()` : ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` Paramètres de réponse : | Paramètre | Description | | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile | <p>Un objet [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur dispose d'un accès premium à l'application.</p><p></p><p>La méthode `.getProfile` fournit le résultat le plus à jour, car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont renvoyées. Il est également important de noter que le SDK met régulièrement à jour le cache `AdaptyProfile` afin de maintenir ces informations aussi récentes que possible.</p> | La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de presse et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer des niveaux d'accès « sports » et « science ». Mais la plupart du temps, un seul niveau d'accès suffira ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès par défaut « premium ». Voici un exemple pour vérifier le niveau d'accès par défaut « premium » : ```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 } }); ``` ### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\} Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement. Pour recevoir des messages d'Adapty, vous devez effectuer quelques configurations supplémentaires : :::note Dans le SDK 4.0, les interfaces de listener suivent la convention C# avec préfixe I : implémentez `IAdaptyEventListener` plutôt que `AdaptyEventListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: ```csharp showLineNumbers // Extend `AdaptyEventListener ` with `OnLoadLatestProfile ` method: public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle any changes to subscription state } } ``` Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache sera transmis. ### Cache du statut d'abonnement \{#subscription-status-cache\} Le cache implémenté dans le SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir les informations sur le statut d'abonnement du profil. Cependant, il est important de noter qu'il n'est pas possible d'effectuer des requêtes directes sur le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier s'il existe des mises à jour ou des modifications liées au profil. Si des changements sont détectés, comme de nouvelles transactions ou d'autres mises à jour, ils seront envoyés aux données en cache afin de les maintenir synchronisées avec le serveur. --- # File: unity-deal-with-att --- --- title: "Gérer l'ATT dans le SDK Unity" description: "Démarrez avec Adapty sur Unity pour simplifier la configuration et la gestion des abonnements." --- Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty. ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` :::warning Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de garantir que les données sont transmises en temps opportun aux intégrations que vous avez configurées. ::: --- # File: kids-mode-unity --- --- title: "Mode Enfants dans le SDK Unity" description: "Activez facilement le Mode Enfants pour respecter les politiques d'Apple et de Google. Pas de collecte d'IDFA, GAID ou de données publicitaires dans le SDK Unity." --- <SDKv4> Si votre application Unity est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/) et de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour satisfaire ces politiques et passer les revues des stores. ## Qu'est-ce qui est requis ? \{#whats-required\} Vous devez configurer le SDK pour désactiver la collecte des éléments suivants : - [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) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) En outre, nous recommandons d'utiliser l'identifiant utilisateur avec précaution. Un identifiant au format `<FirstName.LastName>` sera clairement considéré comme une collecte de données personnelles, tout comme l'utilisation d'une adresse e-mail. Pour le mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) afin de garantir la conformité. ## Activer le mode Enfants \{#enabling-kids-mode\} ### Mises à jour dans l'Adapty Dashboard Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, accédez à [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Mises à jour dans le code de votre application \{#updates-in-your-app-code\} Désactivez la collecte de l'Android Advertising ID et de l'adresse IP lors de l'activation du SDK : ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") // highlight-start .SetGoogleAdvertisingIdCollectionDisabled(true) // set to `true` .SetIPAddressCollectionDisabled(true); // set to `true` // highlight-end Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` Sur iOS, vous n'avez pas besoin d'appeler `SetAppleIDFACollectionDisabled` — activer le mode Kids pour le build iOS (voir ci-dessous) désactive automatiquement la collecte des IDFA dans la configuration du SDK. ### Activer le mode enfants pour la build iOS \{#enable-kids-mode-for-the-ios-build\} :::important Sur iOS, le mode enfants est un trait de package Swift nommé `KidsMode`. L'activer compile IDFA, AdSupport et AppTrackingTransparency hors du binaire SDK. Il requiert le SDK 4.0 ou une version ultérieure — qui installe le SDK iOS natif via Swift Package Manager — et **Xcode 26** ou une version ultérieure, car les versions antérieures d'Xcode ne prennent pas en charge les traits de packages Swift. ::: 1. Dans l'éditeur Unity, allez dans **Player Settings** > **Other Settings** et ajoutez `ADAPTY_KIDS_MODE` dans **Scripting Define Symbols** pour la plateforme iOS. 2. Compilez votre projet pour iOS normalement. Adapty active le trait `KidsMode` sur la référence de package AdaptySDK-iOS dans le projet Xcode généré, et force `apple_idfa_collection_disabled` dans la configuration d'exécution. :::warning Ajoutez le define dans **Player Settings**, pas dans un profil de build. Les scripting defines d'un profil de build n'atteignent les assemblies Editor qu'après que Unity les recompile, donc un build lancé dans la même session peut produire un binaire qui signale le Kids Mode au runtime tout en continuant à lier IDFA. Adapty fait échouer le build iOS lorsqu'il détecte cet état. `BuildPlayerOptions.extraScriptingDefines` n'est pas pris en charge du tout, car il n'atteint jamais les assemblies Editor. ::: ### Mises à jour de votre manifeste Android \{#updates-in-your-android-manifest\} Si votre application cible **uniquement** les enfants et compile avec Android 13 (API 33) ou version supérieure, Google Play exige que vous ne demandiez pas la permission `AD_ID`. Désactiver la collecte dans la configuration du SDK empêche Adapty de collecter l'identifiant, mais cela ne supprime pas une permission déclarée par un autre plugin via la fusion de manifestes. Pour supprimer cette permission, activez **Custom Main Manifest** dans **Player Settings** > **Publishing Settings**, puis ajoutez ce qui suit à l'intérieur de l'élément `<manifest>` du fichier `Assets/Plugins/Android/AndroidManifest.xml`. L'élément `<manifest>` doit déclarer `xmlns:tools="http://schemas.android.com/tools"`. ```xml showLineNumbers title="AndroidManifest.xml" <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" /> ``` </SDKv4> <SDKv3> Si votre application Unity est destinée aux enfants, vous devez respecter les politiques d'[Apple](https://developer.apple.com/kids/) et de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour satisfaire ces politiques et passer les revues des stores. ## Qu'est-ce qui est requis ? \{#whats-required\} Vous devez configurer le SDK pour désactiver la collecte des éléments suivants : - [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) - [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) En outre, nous vous recommandons d'utiliser le customer user ID avec précaution. Un identifiant au format `<FirstName.LastName>` sera inévitablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'une adresse e-mail. Pour le mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des ID hachés ou des UUID générés par l'appareil) afin de garantir la conformité. ## Activation du mode enfants \{#enabling-kids-mode\} ### Mises à jour dans l'Adapty Dashboard Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**. ### Mises à jour dans le code de votre application \{#updates-in-your-app-code\} Désactivez la collecte de l'Android Advertising ID et de l'adresse IP lors de l'activation du SDK : ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") // highlight-start .SetGoogleAdvertisingIdCollectionDisabled(true) // set to `true` .SetIPAddressCollectionDisabled(true); // set to `true` // highlight-end Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` ### Activer le Mode Enfants pour le build iOS \{#enable-kids-mode-for-the-ios-build\} La compilation sans IDFA ni AdSupport dans le binaire iOS nécessite Adapty Unity SDK 4.0 ou une version ultérieure. Effectuez la mise à niveau en suivant le [guide de migration](migration-to-unity-sdk-v4), puis suivez les instructions SDK 4.0 sur cette page. Avec le SDK 3.x, vous pouvez toujours désactiver la collecte IDFA dans la configuration du SDK avec `SetAppleIDFACollectionDisabled(true)`, mais le code IDFA et AdSupport reste dans le binaire. Pour les options de configuration natives, consultez [Mode Enfants dans le SDK iOS](kids-mode) et [Mode Enfants dans le SDK Android](kids-mode-android). </SDKv3> --- # File: unity-onboardings --- --- title: "Onboardings dans le SDK Unity" description: "Découvrez comment utiliser les onboardings dans votre application Unity avec le SDK Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](unity-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un look and feel natif cohérent, des temps de chargement plus rapides et aucune dépendance à un runtime WebView. Consultez [Récupérer les flows et paywalls](unity-get-pb-paywalls) et [Afficher les flows et paywalls](unity-present-paywalls) pour commencer. ::: <CustomDocCardList /> --- # File: unity-get-onboardings --- --- title: "Récupérer les onboardings dans le SDK Unity" description: "Découvrez comment récupérer les onboardings dans Adapty pour Unity." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](unity-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance à un runtime WebView. Consultez [Obtenir des flows et paywalls](unity-get-pb-paywalls) et [Afficher des flows et paywalls](unity-present-paywalls) pour commencer. ::: Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Unity. La première étape consiste à récupérer l'onboarding associé au placement et sa configuration d'affichage, comme décrit ci-dessous. Avant de commencer, assurez-vous que : 1. Vous avez installé le [SDK Adapty pour Unity](sdk-installation-unity) version 3.14.0 ou supérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). ## Récupérer l'onboarding et créer la vue \{#fetch-onboarding-and-create-view\} Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'ensemble de l'expérience : le contenu affiché, la façon dont il est présenté, et la manière dont les interactions utilisateur (comme les réponses à des quiz ou les saisies de formulaire) sont traitées. Le conteneur assure également le suivi automatique des événements analytiques, ce qui vous évite d'implémenter un suivi de vue séparé. Pour de meilleures performances, récupérez la configuration de l'onboarding tôt afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher aux utilisateurs. Pour obtenir un onboarding, utilisez la méthode `GetOnboarding` : ```csharp showLineNumbers Adapty.GetOnboarding("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>par défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p><p>Consultez [Localisations et codes de locale](flutter-localizations-and-locale-codes) pour plus d'informations sur les codes de locale et leur utilisation recommandée.</p> | | **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.</p><p></p><p>Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache n'est pas effacé au redémarrage de l'application ; il est uniquement supprimé lors de la désinstallation ou d'un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant une fiabilité même en cas de connexion internet limitée.</p> | | **loadTimeout** | par défaut : 5 sec | <p>Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local sont renvoyés.</p><p>Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan.</p> | Paramètres de réponse : | Paramètre | Description | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objet [`AdaptyOnboarding`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_onboarding.html) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, ainsi que plusieurs autres propriétés. | Après avoir récupéré l'onboarding, appelez la méthode `CreateOnboardingView`. :::warning Le résultat de la méthode `CreateOnboardingView` ne peut être utilisé qu'une seule fois. Si vous en avez besoin à nouveau, appelez de nouveau la méthode `CreateOnboardingView`. L'appeler deux fois sans recréer peut entraîner l'erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers AdaptyUI.CreateOnboardingView(onboarding, (view, error) => { // handle the result }); ``` Paramètres : | Paramètre | Présence | Description | |:---------------| :------------- |:-----------------------------------------------------------------------------| | **onboarding** | requis | Un objet `AdaptyOnboarding` pour obtenir une vue pour l'onboarding souhaité. | | **externalUrlsPresentation** | <p>optionnel</p><p>par défaut : `InAppBrowser`</p> | <p>Contrôle la façon dont les liens de l'onboarding sont ouverts. Options disponibles :</p><p>- `AdaptyWebPresentation.InAppBrowser` - Ouvre les liens dans un navigateur intégré à l'application (par défaut)</p><p>- `AdaptyWebPresentation.ExternalBrowser` - Ouvre les liens dans le navigateur externe de l'appareil</p><p>Consultez [Personnaliser l'ouverture des liens dans les onboardings](unity-present-onboardings#customize-how-links-open-in-onboardings) pour des exemples d'utilisation.</p> | Une fois que vous avez chargé avec succès l'onboarding et sa configuration d'affichage, vous pouvez [le présenter dans votre application mobile](unity-present-onboardings). ## Accélérer la récupération des onboardings avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ces situations, vous pouvez afficher un onboarding par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout. Pour résoudre ce problème, vous pouvez utiliser la méthode `GetOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer l'onboarding via la méthode `getOnboarding`, comme détaillé dans la section [Récupérer l'onboarding](#fetch-onboarding-and-create-view) ci-dessus. :::warning Préférez `GetOnboarding` à `GetOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes : - **Problèmes de compatibilité** : Peut créer des problèmes lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des conceptions rétrocompatibles, soit d'accepter que les anciennes versions s'affichent incorrectement. - **Pas de personnalisation** : Affiche uniquement le contenu pour l'audience « Tous les utilisateurs », supprimant le ciblage basé sur le pays, l'attribution ou les attributs personnalisés. Si une récupération plus rapide compense ces inconvénients pour votre cas d'utilisation, utilisez `GetOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `GetOnboarding` comme décrit [ci-dessus](#fetch-onboarding-and-create-view). ::: ```csharp showLineNumbers Adapty.GetOnboardingForDefaultAudience("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Paramètres : | Paramètre | Présence | Description | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. | | **locale** | <p>optionnel</p><p>défaut : `en`</p> | <p>L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.</p><p></p><p>Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.</p> | | **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | <p>Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.</p><p></p><p>Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.</p><p></p><p>Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou via un nettoyage manuel.</p><p></p><p>Le SDK Adapty stocke les onboardings localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour garantir que vous obtenez toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.</p> | --- # File: unity-present-onboardings --- --- title: "Présenter les onboardings dans le SDK Unity" description: "Apprenez à présenter les onboardings efficacement pour augmenter vos conversions." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](unity-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance à un runtime WebView. Consultez [Obtenir des flows et paywalls](unity-get-pb-paywalls) et [Afficher des flows et paywalls](unity-present-paywalls) pour commencer. ::: Si vous avez personnalisé un onboarding avec le builder, vous n'avez pas besoin de vous soucier de son rendu dans votre code Unity pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et comment cela doit l'être. Avant de commencer, assurez-vous que : 1. Vous avez installé [Adapty Unity SDK](sdk-installation-unity) 3.14.0 ou version ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Pour afficher un onboarding, utilisez la méthode `view.Present()` sur la `view` créée par la méthode `CreateOnboardingView`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `CreateOnboardingView` une nouvelle fois pour créer une nouvelle instance de `view`. :::warning Réutiliser la même `view` sans la recréer peut entraîner une erreur `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((presentError) => { if (presentError != null) { // handle the error } }; ``` ## Configurer le style de présentation iOS \{#configure-ios-presentation-style\} Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `Present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FullScreen` (par défaut) ou `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` ## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\} :::important La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15. ::: Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application, offrant une expérience fluide en affichant les pages web directement dans votre application sans changer d'app. Pour ouvrir les liens dans un navigateur externe à la place, passez `AdaptyWebPresentation.ExternalBrowser` à la méthode `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 } }); } ); ``` Options disponibles : - `AdaptyWebPresentation.InAppBrowser` - Ouvre les liens dans un navigateur intégré à l'application (par défaut) - `AdaptyWebPresentation.ExternalBrowser` - Ouvre les liens dans le navigateur externe de l'appareil --- # File: unity-handling-onboarding-events --- --- title: "Gérer les événements d'onboarding dans le SDK Unity" description: "Gérez les événements liés à l'onboarding dans Unity avec Adapty." --- :::warning **Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](unity-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides, et aucune dépendance à un runtime WebView. Consultez [Obtenir des flows & paywalls](unity-get-pb-paywalls) et [Afficher des flows & paywalls](unity-present-paywalls) pour commencer. ::: Avant de commencer, assurez-vous que : 1. Vous avez installé [le SDK Adapty Unity](sdk-installation-unity) version 3.14.0 ou ultérieure. 2. Vous avez [créé un onboarding](create-onboarding). 3. Vous avez ajouté l'onboarding à un [placement](placements). Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Découvrez ci-dessous comment gérer ces événements. Pour contrôler ou surveiller les processus qui se déroulent sur l'écran d'onboarding dans votre application Unity, implémentez l'interface `AdaptyOnboardingsEventsListener`. :::note Dans le SDK 4.0, les interfaces listener suivent la convention de préfixe C# `I-` : implémentez `IAdaptyOnboardingsEventsListener` plutôt que `AdaptyOnboardingsEventsListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: ## Actions personnalisées \{#custom-actions\} Dans le builder, vous pouvez ajouter une action **personnalisée** à un bouton et lui attribuer un identifiant. <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Ensuite, vous pouvez utiliser cet ID dans votre code et le gérer comme une action personnalisée. Par exemple, si un utilisateur appuie sur un bouton personnalisé, comme **Login** ou **Allow notifications**, la méthode `OnboardingViewOnCustomAction` sera déclenchée avec le paramètre `actionId` correspondant à l'**Action ID** défini dans le builder. Vous pouvez créer vos propres IDs, comme "allowNotifications". Pour gérer les événements d'onboarding, implémentez l'interface `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) } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## Fermeture de l'onboarding \{#closing-onboarding\} L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton auquel l'action **Close** est assignée. <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important Notez que vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même. ::: Implémentez la méthode `OnboardingViewOnCloseAction` dans votre classe : ```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 } ``` <Details> <summary>Exemple d'événement (cliquez pour développer)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## Ouverture d'un paywall \{#opening-a-paywall\} :::tip Gérez cet événement pour ouvrir un paywall si vous souhaitez l'ouvrir à l'intérieur de l'onboarding. Si vous souhaitez ouvrir un paywall après sa fermeture, il existe une méthode plus directe : gérez [`OnboardingViewOnCloseAction`](#closing-onboarding) et ouvrez un paywall sans vous appuyer sur les données de l'événement. ::: La façon la plus fluide de travailler avec les paywalls dans les onboardings est de faire correspondre l'ID d'action à l'ID de placement du paywall. Ainsi, après l'événement `OnboardingViewOnPaywallAction`, vous pouvez utiliser l'ID de placement pour récupérer et ouvrir immédiatement le paywall. :::note Notez que, pour iOS, une seule vue (paywall ou onboarding) peut être affichée à l'écran à la fois. Si vous affichez un paywall par-dessus un onboarding, vous ne pouvez pas contrôler l'onboarding en arrière-plan par programmation. Tenter de fermer l'onboarding fermera le paywall à la place, laissant l'onboarding visible. Pour éviter cela, fermez toujours la vue de l'onboarding avant d'afficher le 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 } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\} Lorsque le chargement d'un onboarding se termine, implémentez la méthode `OnboardingViewDidFinishLoading` : ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta ) { // handle loading completion } // ... other interface methods } ``` <Details> <summary>Exemple d'événement (Cliquez pour développer)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## Suivi de la navigation \{#tracking-navigation\} La méthode `OnboardingViewOnAnalyticsEvent` est appelée lorsque divers événements analytiques se produisent au cours du flow d'onboarding. L'objet `analyticsEvent` peut être l'un des types suivants : |Type | Description | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | Quand l'onboarding a été chargé | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | Quand un écran est affiché | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | Quand un écran est complété. Inclut un `ElementId` optionnel (identifiant de l'élément complété) et une `Reply` optionnelle (réponse de l'utilisateur). Déclenché quand l'utilisateur effectue une action pour quitter l'écran. | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | Quand le deuxième écran est affiché | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | Déclenché quand l'e-mail de l'utilisateur est collecté via le champ de saisie | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | Déclenché quand un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, [assignez l'ID `final` au dernier écran](design-onboarding). | | `AdaptyOnboardingsAnalyticsEventUnknown` | Pour tout type d'événement non reconnu. Inclut `Name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) | Chaque événement inclut des informations `meta` contenant : | Champ | Description | |------------|-------------| | `OnboardingId` | Identifiant unique du flow d'onboarding | | `ScreenClientId` | Identifiant de l'écran actuel | | `ScreenIndex` | Position de l'écran actuel dans le flow | | `ScreensTotal` | Nombre total d'écrans dans le flow | Voici un exemple d'utilisation des événements analytics pour le suivi : ```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 La méthode `TrackEvent` est un espace réservé que vous devez implémenter vous-même pour envoyer des données analytiques à votre service d'analyse préféré. ::: <Details> <summary>Exemples d'événements (Cliquez pour développer)</summary> ```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 } } ``` </Details> --- # File: unity-onboarding-input --- --- title: "Traiter les données des onboardings dans le SDK Unity" description: "Enregistrez et utilisez les données des onboardings dans votre application Unity avec le SDK Adapty." --- :::warning **Les onboardings sont obsolètes dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](unity-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance à l'exécution WebView. Consultez [Obtenir les flows et paywalls](unity-get-pb-paywalls) et [Afficher les flows et paywalls](unity-present-paywalls) pour commencer. ::: Lorsque vos utilisateurs répondent à une question du quiz ou saisissent leurs données dans un champ de saisie, la méthode `OnboardingViewOnStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code. Implémentez la méthode `OnboardingViewOnStateUpdatedAction` dans votre classe : :::note Dans le SDK 4.0, les interfaces listener suivent la convention C# avec le préfixe I : implémentez `IAdaptyOnboardingsEventsListener` au lieu de `AdaptyOnboardingsEventsListener`. Les méthodes restent inchangées. Consultez le [guide de migration](migration-to-unity-sdk-v4). ::: ```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 } ``` Les paramètres incluent : | Paramètre | Description | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | Identifiant unique de l'élément de saisie. Vous pouvez l'utiliser pour associer des questions à des réponses lors de leur enregistrement. | | `@params` | L'objet de données saisies par l'utilisateur. Peut être de l'un des types suivants. | | `AdaptyOnboardingsSelectParams` | Sélection unique parmi des options. Contient `Id`, `Value`, `Label` | | `AdaptyOnboardingsMultiSelectParams` | Sélections multiples parmi des options. Contient une liste de `Params` (chacun avec `Id`, `Value`, `Label`)<br/>• `input` : objet avec `type`, `value`<br/>• `datePicker` : objet avec `day`, `month`, `year` | | `AdaptyOnboardingsInputParams` | Champ de saisie de texte. Contient `Input` qui peut être `AdaptyOnboardingsTextInput`, `AdaptyOnboardingsEmailInput` ou `AdaptyOnboardingsNumberInput` | | `AdaptyOnboardingsDatePickerParams` | Sélection de date. Contient `Day`, `Month`, `Year` nullables | <Details> <summary>Exemples de données sauvegardées (peuvent différer selon votre implémentation)</summary> ```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 } } } ``` </Details> ## Cas d'utilisation \{#use-cases\} ### Enrichir les profils utilisateur avec des données \{#enrich-user-profiles-with-data\} Si vous souhaitez lier immédiatement les données saisies au profil utilisateur et éviter de lui poser deux fois les mêmes questions, vous devez [mettre à jour le profil utilisateur](unity-setting-user-attributes) avec ces données lors du traitement de l'action. Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur adresse e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci : ```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 } ``` ### Personnaliser les paywalls selon les réponses \{#customize-paywalls-based-on-answers\} Grâce aux quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding. Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher différents CTA et produits à différents groupes d'utilisateurs. 1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et attribuez des IDs explicites à ses options. 2. Traitez les réponses au quiz selon leurs IDs et [définissez des attributs personnalisés](unity-setting-user-attributes) pour les utilisateurs. ```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. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé. 4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé. 5. [Affichez un paywall](unity-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](unity-handling-onboarding-events#opening-a-paywall). --- # File: unity-best-practices --- --- title: "Meilleures pratiques avec le SDK Unity" description: "Modèles de référence pour intégrer le SDK Adapty dans Unity — ordre des appels, gestion des erreurs et autres règles de production." --- <CustomDocCardList /> --- # File: unity-sdk-call-order --- --- title: "Ordre d'appel dans le SDK Unity" description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs intermittentes #2002 en appelant les méthodes du SDK Adapty dans le bon ordre." --- `Adapty.Activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant que son callback de complétion n'a pas été déclenché, le SDK n'a aucun état. Tout appel effectué avant ou en parallèle de `Activate()` échoue avec [`#2002 notActivated`](unity-handle-errors#custom-network-codes). Si votre application authentifie les utilisateurs et que vous collectez un identifiant utilisateur client après le lancement, appelez `Adapty.Identify()` à ce moment-là. N'appelez pas les méthodes liées aux actions utilisateur avant que le callback `Identify` ne se déclenche. Les appels qui entrent en concurrence avec lui échouent soit avec [`#3006 profileWasChanged`](unity-handle-errors#custom-network-codes), soit atterrissent sur le profil anonyme créé lors de l'activation. Dans ce cas, l'attribution, les identifiants MMP tels que `appsflyer_id` et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `Identify` et continuez à travailler avec le profil anonyme. Les SDK MMP et analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.Activate`. Sinon, l'ID MMP est associé à un profil anonyme éphémère et n'est pas toujours transféré au profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer). ## L'ordre correct \{#the-correct-order\} Votre parcours dépend de deux choses : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un MMP ou un SDK d'analyse. - **Étapes 2 et 5** : Obligatoires pour chaque application. Activez le SDK, puis appelez les méthodes SDK. - **Étapes 1 et 3** : Requises uniquement si vous intégrez un MMP ou un SDK d'analyse (AppsFlyer, Adjust, Branch, PostHog). - **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et collecte l'identifiant utilisateur client après le lancement. Si vous disposez de l'identifiant utilisateur au lancement de l'application, passez-le directement dans `Activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, donc l'étape 4 est inutile. | Étape | Appel | Quand | Notes | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | Initialisez votre MMP ou SDK analytics (AppsFlyer, Adjust, PostHog, Branch) | Au lancement de l'app, en premier | Attendez le callback UID du MMP, par exemple `getAppsFlyerId`. | | 2a | `Adapty.Activate(builder.Build(), ...)` avec `SetCustomerUserId` défini sur le builder | Au lancement de l'app, après l'étape 1, si vous disposez de l'ID utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. | | 2b | `Adapty.Activate(builder.Build(), ...)` sans `SetCustomerUserId` | Au lancement de l'app, après l'étape 1, si vous n'avez pas l'ID utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. | | 3 | `Adapty.SetIntegrationIdentifier(key, value, callback)` pour chaque MMP | Après l'étape 2, avant tout appel déclenché par une action utilisateur | Nécessaire pour que les IDs MMP soient associés au bon profil. | | 4 | `Adapty.Identify("YOUR_USER_ID", callback)` | Après l'étape 3 (ou l'étape 2 si pas de MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Attendez le callback de fin. Des appels simultanés pendant `Identify` produisent `#3006 profileWasChanged`. | | 5 | `GetPaywall` (`GetFlow` dans le SDK v4), `GetPaywallProducts`, `RestorePurchases`, `MakePurchase`, `UpdateAttribution`, `UpdateProfile` | Après l'étape 4 si vous appelez `Identify` ; sinon après l'étape 3 (ou l'étape 2 si pas de MMP) | Ces appels nécessitent un profil stable. | :::important Ignorer ces étapes entraîne une perte d'accès premium pour les utilisateurs qui reviennent, l'absence d'`appsflyer_id` sur les profils, et des paywalls renvoyés pour la mauvaise audience. ::: ## Installations via web2app et web-funnel \{#web2app-and-web-funnel-installs\} Si des utilisateurs achètent via un checkout web (Stripe, Paddle) puis installent l'application native, le premier `Activate()` du terminal crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'ID utilisateur client avant le lancement de l'application (depuis votre flow d'authentification ou le referrer d'installation), passez-le directement dans `Activate()`. Dans le cas contraire, l'achat web reste invisible sur le terminal jusqu'à ce que vous appeliez `Identify("YOUR_USER_ID")` puis `RestorePurchases`. Pour les métadonnées à envoyer avec chaque checkout web, consultez : - [Stripe](stripe) - [Paddle](paddle) --- # File: unity-optimize-paywall-fetching --- --- title: "Optimiser la récupération des paywalls dans le SDK Unity" description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour Unity." --- Une récupération de paywall fiable dans Unity fait trois choses : s'affiche rapidement, renvoie le paywall ciblé par audience et bascule gracieusement sur un fallback quand le réseau est lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir. :::tip Les règles supposent que `Adapty.Activate()` et `Adapty.Identify()` ont déjà été résolus. Voir [Ordre des appels dans le SDK Unity](unity-sdk-call-order). ::: Les conseils ci-dessous utilisent les noms de méthodes de la v3. Dans le SDK v4, `GetPaywall` est renommé en `GetFlow` (voir le [guide de migration](migration-to-unity-sdk-v4)) — toutes les règles s'appliquent sans changement. ## Règles et pièges \{#rules-and-pitfalls\} | À faire | À ne pas faire | Pourquoi | |---|---|---| | Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements simultanément au démarrage. | Le pré-chargement en masse bloque le thread principal et provoque un écran noir pendant la rafale. | | Récupérez `GetPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `Activate` ou après le déclenchement de `OnLoadLatestProfile`. | Appeler `GetPaywall` dans `Awake()`. | L'attribution n'est pas encore arrivée. Le paywall est résolu par rapport à l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. | | Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre `GetPaywall` indéfiniment. | Sans timeout, les utilisateurs avec une mauvaise connexion voient un écran vide jusqu'à la résolution du réseau — ou ferment l'application. | Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products-unity) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement. ## Optimiser pour une connexion défaillante \{#tune-for-poor-connectivity\} Pour les marchés où la connexion est régulièrement mauvaise (zones rurales, transports en commun, régions touchées par des problèmes de routage) : - Définissez `fetchPolicy` sur `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour chaque appel, sauf le tout premier. - Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard. - Réglez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le délai expire. - Ne conditionnez pas l'affichage du paywall à `GetProfile`. Appelez `GetPaywall` indépendamment pour éviter qu'un profil lent ne bloque l'interface. --- # File: unity-test --- --- title: "Tester & publier avec le SDK Unity" description: "Apprenez à tester et publier votre application Unity avec le SDK Adapty." --- Si vous avez déjà intégré le SDK Adapty dans votre application Unity, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu sur les plateformes iOS et Android. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox d'Apple et l'environnement de test de Google Play. ## Tester votre application \{#test-your-app\} Pour tester vos achats intégrés de manière exhaustive, consultez nos guides de test spécifiques à chaque plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android). ## Se préparer pour la publication \{#prepare-for-release\} Avant de soumettre votre application au store, suivez la [liste de vérification pour la publication](release-checklist) afin de confirmer que : - La connexion au store et les notifications serveur sont configurées - Les achats s'effectuent et sont bien remontés à Adapty - L'accès se déverrouille et se restaure correctement - Les exigences en matière de confidentialité et d'évaluation sont respectées --- # File: unity-reference --- --- title: "Référence pour le SDK Unity" description: "Documentation de référence pour le SDK Unity Adapty." --- Cette page contient la documentation de référence pour le SDK Unity Adapty. Choisissez le sujet dont vous avez besoin : - **[Modèles SDK](https://unity.adapty.io/)** - Modèles de données et structures utilisés par le SDK - **[Gérer les erreurs](unity-handle-errors)** - Gestion des erreurs et dépannage --- # File: unity-handle-errors --- --- title: "Gérer les erreurs dans le SDK Unity" description: "Gérer les erreurs dans le SDK Unity." --- Chaque erreur retournée par le SDK est de type `AdaptyErrorCode`. Voici un exemple : :::tip **Activez les logs verbeux avant de déboguer.** La plupart des `AdaptyError`s encapsulent une erreur sous-jacente de StoreKit, Play Billing, réseau ou backend. Avec les logs verbeux activés (`Adapty.SetLogLevel(AdaptyLogLevel.Verbose, ...)` — voir [Journalisation](sdk-installation-unity#logging)), cette erreur encapsulée est affichée dans la console, ce qui vous indique généralement la cause réelle. ::: :::important Si ces solutions ne résolvent pas votre problème, consultez la section [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support, afin de nous aider à vous assister plus efficacement. ::: ```csharp showLineNumbers Adapty.MakePurchase(product, (profile, error) => { if (error != null && error.Code == Adapty.ErrorCode.PaymentCancelled) { // payment cancelled } }); ``` ## Codes système StoreKit \{#system-storekit-codes\} | Erreur | Code | Solution | |-----|----|-----------| | [unknown](https://developer.apple.com/documentation/storekit/skerror/code/unknown) | 0 | Code d'erreur indiquant qu'une erreur inconnue ou inattendue s'est produite. <br/> Réessayez ou consultez la section [Autres problèmes](#other-issues). | | [clientInvalid](https://developer.apple.com/documentation/storekit/skerror/code/clientinvalid) | 1 | Ce code d'erreur indique que le client n'est pas autorisé à effectuer l'action tentée. | | [paymentCancelled](https://developer.apple.com/documentation/storekit/skerror/code/paymentcancelled) | 2 | <p>Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.</p><p>Aucune action n'est requise, mais d'un point de vue logique métier, vous pouvez proposer une remise à votre utilisateur ou lui rappeler ultérieurement.</p> | | [paymentInvalid](https://developer.apple.com/documentation/storekit/skerror/code/paymentinvalid) | 3 | Cette erreur indique que l'un des paramètres de paiement n'a pas été reconnu par l'App Store. | | [paymentNotAllowed](https://developer.apple.com/documentation/storekit/skerror/code/paymentnotallowed) | 4 | Ce code d'erreur indique que l'utilisateur n'est pas autorisé à valider des paiements. | | [storeProductNotAvailable](https://developer.apple.com/documentation/storekit/skerror/code/storeproductnotavailable) | 5 | Ce code d'erreur indique que le produit demandé n'est pas disponible dans le store. <br/> Essayez de réinstaller l'application. | | [cloudServicePermissionDenied](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicepermissiondenied) | 6 | Ce code d'erreur indique que l'utilisateur n'a pas autorisé l'accès aux informations du service cloud. | | [cloudServiceNetworkConnectionFailed](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicenetworkconnectionfailed) | 7 | Ce code d'erreur indique que l'appareil n'a pas pu se connecter au réseau. | | [cloudServiceRevoked](https://developer.apple.com/documentation/storekit/skerror/code/cloudservicerevoked/) | 8 | Ce code d'erreur indique que l'utilisateur a révoqué l'autorisation d'utiliser ce service cloud. | | [privacyAcknowledgementRequired](https://developer.apple.com/documentation/storekit/skerror/code/privacyacknowledgementrequired) | 9 | Ce code d'erreur indique que l'utilisateur n'a pas encore accepté la politique de confidentialité d'Apple. | | [unauthorizedRequestData](https://developer.apple.com/documentation/storekit/skerror/code/unauthorizedrequestdata) | 10 | Ce code d'erreur indique que l'application tente d'utiliser une propriété pour laquelle elle ne dispose pas des droits requis. | | [invalidOfferIdentifier](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferidentifier) | 11 | <p>L'[`identifiant`](https://developer.apple.com/documentation/storekit/skpaymentdiscount/identifier) de l'offre n'est pas valide. Par exemple, vous n'avez pas configuré d'offre avec cet identifiant dans l'App Store, ou vous avez révoqué l'offre.</p><p>Assurez-vous de configurer les offres souhaitées dans AppStore Connect et de passer un identifiant d'offre valide.</p> | | [invalidSignature](https://developer.apple.com/documentation/storekit/skerror/code/invalidsignature) | 12 | Ce code d'erreur indique que la signature dans une remise de paiement n'est pas valide. | | [missingOfferParams](https://developer.apple.com/documentation/storekit/skerror/code/missingofferparams) | 13 | Ce code d'erreur indique que des paramètres sont manquants dans une remise de paiement. | | [invalidOfferPrice](https://developer.apple.com/documentation/storekit/skerror/code/invalidofferprice/) | 14 | Ce code d'erreur indique que le prix que vous avez spécifié dans App Store Connect n'est plus valide. Les offres doivent toujours représenter un prix réduit. | ## Codes Android personnalisés \{#custom-android-codes\} | Erreur | Code | Solution | |-----|----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | adaptyNotInitialized | 20 | Vous devez configurer correctement le SDK Adapty via la méthode `Adapty.activate`. Découvrez comment le faire [pour Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). | | productNotFound | 22 | Cette erreur indique que le produit demandé pour l'achat n'est pas disponible dans le store. | | invalidJson | 23 | Le JSON du paywall n'est pas valide. Corrigez-le dans l'Adapty Dashboard. Consultez la rubrique [Personnaliser le paywall avec Remote Config](customize-paywall-with-remote-config) pour savoir comment le corriger. | | currentSubscriptionToUpdateNotFoundInHistory | 24 | L'abonnement d'origine qui doit être renouvelé est introuvable. | | pendingPurchase | 25 | Cette erreur indique que l'état de l'achat est en attente plutôt que finalisé. Consultez la page [Gestion des transactions en attente](https://developer.android.com/google/play/billing/integrate#pending) dans la documentation Android Developer pour plus de détails. | | billingServiceTimeout | 97 | Cette erreur indique que la requête a atteint le délai d'attente maximum avant que Google Play puisse répondre. Cela peut être causé, par exemple, par un délai dans l'exécution de l'action demandée par l'appel à la bibliothèque Play Billing. | | featureNotSupported | 98 | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. | | billingServiceDisconnected | 99 | Cette erreur fatale indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. | | billingServiceUnavailable | 102 | Cette erreur transitoire indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau quelque part entre l'appareil client et les services Google Play Billing. | | billingUnavailable | 103 | <p>Cette erreur indique qu'une erreur de facturation utilisateur s'est produite pendant le processus d'achat. Exemples de situations où cela peut se produire :</p><p></p><p>1\. L'application Play Store sur l'appareil de l'utilisateur est obsolète.</p><p>2. L'utilisateur se trouve dans un pays non pris en charge.</p><p>3. L'utilisateur est un utilisateur entreprise et son administrateur a désactivé les achats pour les utilisateurs.</p><p>4. Google Play ne peut pas débiter le moyen de paiement de l'utilisateur. Par exemple, la carte de crédit de l'utilisateur a peut-être expiré.</p><p>5. L'utilisateur n'est pas connecté à l'application Play Store.</p> | | developerError | 105 | Il s'agit d'une erreur fatale indiquant que vous utilisez une API de manière incorrecte. | | billingError | 106 | Il s'agit d'une erreur fatale indiquant un problème interne avec Google Play lui-même. | | itemAlreadyOwned | 107 | Le produit consommable a déjà été acheté. | | itemNotOwned | 108 | Cette erreur indique que l'action demandée sur l'article a échoué car | ## Codes StoreKit personnalisés \{#custom-storekit-codes\} | Erreur | Code | Solution | |-----|----|-----------| | noProductIDsFound | 1000 | <p>Cette erreur indique qu'aucun des produits que vous avez demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, ignorez-le.</p><p>Si vous rencontrez cette erreur, suivez les étapes de la section [Correction de l'erreur Code-1000 `noProductIDsFound`](InvalidProductIdentifiers-unity).</p> | | productRequestFailed | 1002 | <p>Impossible de récupérer les produits disponibles pour le moment. Raison possible :</p><p></p><p>- Aucun cache n'a encore été créé et il n'y a pas de connexion Internet en même temps.</p> | | cantMakePayments | 1003 | Les achats intégrés ne sont pas autorisés sur cet appareil. Consultez le [guide](cantMakePayments-unity) de dépannage. | | noPurchasesToRestore | 1004 | Cette erreur indique que Google Play n'a pas trouvé d'achat à restaurer. | | cantReadReceipt | 1005 | <p>Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.</p><p>Aucune action n'est requise, mais d'un point de vue logique métier, vous pouvez proposer une remise à votre utilisateur ou lui rappeler ultérieurement.</p> | | productPurchaseFailed | 1006 | L'achat du produit a échoué. Cela encapsule une erreur StoreKit sous-jacente — lisez l'erreur encapsulée (ou activez les logs verbeux pour la voir dans la console) pour connaître la raison réelle. L'erreur encapsulée correspond généralement à l'un des codes StoreKit 0–14 du tableau ci-dessus — le plus souvent `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` ou `invalidOfferPrice`. Si vous ne pouvez pas identifier une raison précise, essayez un nouveau [profil sandbox](test-purchases-in-sandbox) ; si cela échoue encore, contactez le support Apple. | | refreshReceiptFailed | 1010 | Cette erreur indique que le reçu n'a pas été reçu. Applicable uniquement à StoreKit 1. | | receiveRestoredTransactionsFailed | 1011 | La restauration des achats a échoué. | ## Codes réseau personnalisés \{#custom-network-codes\} | Erreur | Code | Solution | |:---------------------|:-----|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | notActivated | 2002 | Le SDK Adapty n'est pas activé. <br/> Cas le plus fréquent : un écran de démarrage ou un hook de script précoce appelle des méthodes Adapty avant que `Adapty.Activate` soit terminé. Le symptôme est intermittent et peut ne pas se reproduire dans l'éditeur car les timings sur appareil réel sont différents. Attendez le callback de complétion d'`Activate` avant de planifier tout autre appel SDK. Voir [Ordre des appels dans le SDK Unity](unity-sdk-call-order) pour la séquence complète. | | badRequest | 2003 | Requête incorrecte. <br/> Assurez-vous d'avoir effectué toutes les étapes requises pour [l'intégration avec l'App Store](app-store-connection-configuration). | | serverError | 2004 | Erreur serveur. <br/> Réessayez après quelques instants. Si le problème persiste, contactez l'équipe support Adapty. | | networkFailed | 2005 | Cette erreur indique des problèmes de connexion réseau sur l'appareil de l'utilisateur. <br/> Essayez de désactiver le VPN ou de passer du réseau cellulaire au WiFi, ou inversement. | | decodingFailed | 2006 | Cette erreur indique que le décodage de la réponse a échoué. <br/> Vérifiez votre code et assurez-vous que les paramètres que vous envoyez sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. | | encodingFailed | 2009 | Cette erreur indique que l'encodage de la requête a échoué. | | missingURL | 2010 | L'URL demandée est nil. | | analyticsDisabled | 3000 | Nous ne pouvons pas traiter les événements d'analytics, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). | | wrongParam | 3001 | Cette erreur indique que certains de vos paramètres sont incorrects. <br/> Si vous utilisez le Paywall Builder Adapty et ne pouvez pas afficher un paywall à cause de cette erreur, activez **Show on device** dans le Paywall Builder.<br/> Une autre raison possible est que la version du fichier [fallback](fallback-paywalls) local ne correspond pas à la version du SDK. Téléchargez un nouveau fichier depuis le tableau de bord. | | activateOnceError | 3005 | Il n'est pas possible d'appeler la méthode `.activate` plus d'une fois. | | profileWasChanged | 3006 | Le profil utilisateur a été modifié pendant l'opération. <br/> Cela se produit lorsqu'une méthode est appelée pendant qu'`Adapty.Identify` est encore en cours — l'appel en vol arrive sur un profil qui est sur le point d'être remplacé, et le SDK le rejette. Attendez le callback de complétion d'`Identify` avant tout appel d'action utilisateur. Voir [Ordre des appels dans le SDK Unity](unity-sdk-call-order). | | unsupportedData | 3007 | Cette erreur indique que le format de données n'est pas pris en charge par le SDK. | | persistingDataError | 3100 | Une erreur s'est produite lors de l'enregistrement des données. | | fetchTimeoutError | 3101 | Cette erreur indique que l'opération de récupération a dépassé le délai d'attente. | ## Autres problèmes \{#other-issues\} Si vous n'avez pas encore trouvé de solution, voici les prochaines étapes : - **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de mettre à jour vers les dernières versions du SDK, car elles sont plus stables et incluent des correctifs pour les problèmes connus. - **Contacter l'équipe support ou obtenir de l'aide auprès d'autres développeurs** sur le [forum de support](https://adapty.featurebase.app/). - **Contacter l'équipe support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou si cela n'a pas résolu le problème, contactez notre équipe support. Notez que votre problème sera résolu plus rapidement si vous [activez la journalisation verbeux](sdk-installation-unity#logging) et partagez les logs avec l'équipe. Vous pouvez également joindre des extraits de code pertinents. --- # File: InvalidProductIdentifiers-unity --- --- title: "Correction de l'erreur Code-1000 noProductIDsFound dans le SDK Unity" description: "Résolvez les erreurs d'identifiant de produit invalide lors de la gestion des abonnements dans Adapty." --- L'erreur code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont référencés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, vous pouvez l'ignorer sans risque. Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre : ## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\} 1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**. 2. Copiez le **Bundle ID** dans la sous-section **General Information**. <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Ouvrez l'onglet [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) depuis le menu supérieur d'Adapty et collez la valeur copiée dans le champ **Bundle ID**. <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. Revenez à la page **App information** dans App Store Connect et copiez l'**Apple ID** qui s'y trouve. 5. Sur la page [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) dans l'Adapty Dashboard, collez l'identifiant dans le champ **Apple app ID**. ## Étape 2. Vérifier les produits \{#step-3-check-products\} 1. Rendez-vous dans **App Store Connect** et accédez à [**Monétisation** → **Abonnements**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) dans le menu de gauche. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. Vos produits apparaîtront dans la section **Subscriptions**. 3. Assurez-vous que le produit que vous testez est marqué **Ready to Submit**. <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Comparez l'identifiant du produit dans le tableau avec celui qui figure dans l'onglet [**Products**](https://app.adapty.io/products) de l'Adapty Dashboard. Si les identifiants ne correspondent pas, copiez l'identifiant du produit depuis le tableau et [créez un produit](create-product) avec cet identifiant dans l'Adapty Dashboard. <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 3. Vérifier la disponibilité du produit \{#step-4-check-product-availability\} 1. Retournez dans **App Store Connect** et ouvrez la même section **Subscriptions**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis y sont bien listés. <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. De nouveau, rendez-vous dans la section **Monetization** → **Subscriptions** d'**App Store Connect**. <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Faites défiler jusqu'à **Subscription Pricing** et dépliez la section **Current Pricing for New Subscribers**. <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Vérifiez que tous les prix requis sont bien listés. <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Étape 5. Vérifier le statut des apps payantes, le compte bancaire et les formulaires fiscaux \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. Sur la page d'accueil d'[**App Store Connect**](https://appstoreconnect.apple.com/), cliquez sur **Business**. <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Sélectionnez le nom de votre entreprise. <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Faites défiler vers le bas et vérifiez que votre **Paid Apps Agreement**, votre **Bank Account** et vos **Tax forms** affichent bien le statut **Active**. <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> En suivant ces étapes, vous devriez pouvoir résoudre l'avertissement `InvalidProductIdentifiers` et rendre vos produits disponibles dans le store. ## Étape 6. Recréer le produit s'il est bloqué \{#step-6-recreate-the-product-if-its-stuck\} Les étapes 1 à 5 peuvent toutes passer avec succès — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK continue de retourner `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre de produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit. Supprimez le produit dans App Store Connect et recréez-le avec le même identifiant. Attendez jusqu'à 24 heures après la recréation pour que la propagation soit effective. --- # File: cantMakePayments-unity --- --- title: "Correction de l'erreur Code-1003 cantMakePayment dans le SDK Unity" description: "Résolvez l'erreur de paiement lors de la gestion des abonnements dans Adapty." --- L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil. Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes : - Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous. - Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous. ## Problème : Restrictions de l'appareil \{#issue-device-restrictions\} | Problème | Solution | |--------------------------------|-------------------------------------------------------------------------------------------------------------| | Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) | | Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte | | Restrictions régionales | Utilisez un compte App Store d'une région prise en charge | ## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\} Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat. Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK. --- # File: unity-sdk-migration-guides --- --- title: "Guides de migration du SDK Unity" description: "Guides de migration pour les versions du SDK Unity d'Adapty." --- Cette page regroupe tous les guides de migration pour le SDK Unity d'Adapty. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées : - **[Migrer vers la v4.0 (bêta)](migration-to-unity-sdk-v4)** - **[Migrer vers la v3.14](migration-to-unity-sdk-314)** - **[Migrer vers la v3.4](migration-to-unity-sdk-34)** - **[Migrer vers la v3.3](migration-to-unity330)** - **[Migrer vers la v3.0](migration-to-unity-sdk-v3)** --- # File: migration-to-unity-sdk-v4 --- --- title: "Migrer le SDK Unity Adapty vers la v. 4.0" description: "Migrez vers le SDK Unity Adapty v4.0 (bêta) en remplaçant les API paywall par des API flow, compatibles avec Flow Builder et Paywall Builder." --- Le SDK Unity Adapty 4.0 (bêta) introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent à la fois avec le nouveau Flow Builder et le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard. ## Référence rapide \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.GetPaywall(placementId, locale, ...)` | `Adapty.GetFlow(placementId, ...)` | | `Adapty.GetPaywallForDefaultAudience(placementId, locale, ...)` | `Adapty.GetFlowForDefaultAudience(placementId, ...)` | | `Adapty.GetPaywallProducts(paywall, ...)` | `Adapty.GetPaywallProducts(flow, ...)` | | `Adapty.LogShowPaywall(paywall, ...)` | `Adapty.LogShowFlow(flow, ...)` | | `AdaptyPaywall` | `AdaptyFlow` | | `AdaptyUI.CreatePaywallView(paywall, ...)` | `AdaptyUI.CreateFlowView(flow, ...)` | | `AdaptyUICreatePaywallViewParameters` | `AdaptyUICreateFlowViewParameters` | | `AdaptyUIPaywallView` | `AdaptyUIFlowView` | | `AdaptyUI.PresentPaywallView(view, ...)` / `DismissPaywallView(view, ...)` | `AdaptyUI.PresentFlowView(view, ...)` / `DismissFlowView(view, ...)` | | `Adapty.SetPaywallsEventsListener(listener)` | `Adapty.SetFlowsEventsListener(listener)` | | `AdaptyPaywallsEventsListener` | `IAdaptyFlowsEventsListener` | | `AdaptyEventListener` | `IAdaptyEventListener` | | `AdaptyOnboardingsEventsListener` | `IAdaptyOnboardingsEventsListener` | | `PaywallViewDidPerformAction`, `PaywallViewDidAppear`, et autres callbacks `PaywallView...` | `FlowViewDidPerformAction`, `FlowViewDidAppear`, et autres callbacks `FlowView...` | | `PaywallViewDidFailRendering` | `FlowViewDidReceiveError` | | `Adapty.SetFallbackPaywalls(...)` (déprécié en v3) | supprimé — utilisez `Adapty.SetFallback(fileName, ...)` | | `Builder.SetIDFACollectionDisabled(...)` (déprécié en v3) | supprimé — utilisez `Builder.SetAppleIDFACollectionDisabled(...)` | | `paywall.Products` (une liste de `AdaptyProductReference`) | supprimé — utilisez `ProductIdentifiers` ou `VendorProductIds`, ou appelez `GetPaywallProducts(flow)` pour les produits complets | | `AdaptyProductReference` | supprimé en tant que type public — voir [Modèle de données](#data-model) | | `paywall.RemoteConfigString` | supprimé — utilisez `flow.RemoteConfig?.Data` | `AdaptyPaywallProduct` garde son nom — les produits appartiennent toujours à un flow, et `GetPaywallProducts` garde également son nom, prenant désormais un `AdaptyFlow`. Les méthodes `GetFlow` et `GetFlowForDefaultAudience` ne prennent plus de paramètre `locale`. Les API d'achat et de profil (`MakePurchase`, `RestorePurchases`, `GetProfile`, `Identify`, `UpdateProfile`) et les fallbacks via `SetFallback` sont inchangés. Les méthodes onboarding fonctionnent toujours mais sont dépréciées — voir [Dépréciation de l'API Onboarding](#onboarding-api-deprecation). Certains comportements par défaut ont changé — voir [Changements de comportement par défaut](#default-behavior-changes). ## Installation \{#installation\} La v4.0 est une pré-version, donc épinglez le tag bêta exact. Pour l'installer via le Unity Package Manager, ajoutez le tag à l'URL Git : ``` https://github.com/adaptyteam/AdaptySDK-Unity.git?path=/Packages/com.adapty.unity-sdk#4.0.0-beta.1 ``` Si vous installez via le package Unity, téléchargez `adapty-unity-plugin-4.0.0-beta.1.unitypackage` depuis la [version 4.0.0-beta.1](https://github.com/adaptyteam/AdaptySDK-Unity/releases/tag/4.0.0-beta.1). Consultez [Installer le SDK Adapty](sdk-installation-unity#install-adapty-sdk) pour la configuration complète. Deux changements de configuration de build sont introduits avec la v4 : - **Les dépendances iOS passent à Swift Package Manager.** Le SDK iOS natif Adapty 4.0 est déclaré comme package Swift distant au lieu d'un pod CocoaPods. Mettez à jour l'[External Dependency Manager](https://github.com/googlesamples/unity-jar-resolver#getting-started) vers la version **1.2.188 ou ultérieure** — les versions antérieures ne prennent pas en charge les dépendances Swift Package Manager. Les étapes CocoaPods (`iOS Resolver -> Install Cocoapods`, ouverture de `Unity-iPhone.xcworkspace`) ne s'appliquent plus. - **La cible de déploiement iOS doit être 15.0 ou supérieure.** Un nouveau validateur de build dans l'éditeur Unity bloque le build iOS si la cible est inférieure. Les SDK natifs Adapty sous-jacents passent à la version 4.x sur les deux plateformes et sont résolus automatiquement — aucune autre modification de build n'est nécessaire. ## Récupération des flows \{#fetching-flows\} ### GetPaywall → GetFlow Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et le paramètre `locale` est supprimé — lors du rendu d'un flow, la locale est résolue automatiquement ; pour les paywalls personnalisés, toutes les locales sont retournées dans `flow.RemoteConfigs` : ```diff showLineNumbers - Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { + Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => { if (error != null) { // handle the error return; } - // use the paywall + // use the flow }); ``` `GetPaywallForDefaultAudience` est renommé de la même façon : ```diff showLineNumbers - Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { /* ... */ }); + Adapty.GetFlowForDefaultAudience("YOUR_PLACEMENT_ID", (flow, error) => { /* ... */ }); ``` ### GetPaywallProducts(paywall) → GetPaywallProducts(flow) `GetPaywallProducts` conserve son nom mais prend désormais un `AdaptyFlow` : ```diff showLineNumbers - Adapty.GetPaywallProducts(paywall, (products, error) => { + Adapty.GetPaywallProducts(flow, (products, error) => { if (error != null) { // handle the error return; } // use the products }); ``` ## Modèle de données \{#data-model\} `GetFlow` retourne un `AdaptyFlow` au lieu d'un `AdaptyPaywall`, et la forme de l'objet a changé : | Propriété v3 `AdaptyPaywall` | Propriété v4 `AdaptyFlow` | Action | |---|---|---| | `RemoteConfig` (unique, nullable) | `RemoteConfigs` (liste) | Un flow contient une Remote Config par langue configurée. Lisez celle qui correspond à l'utilisateur via `flow.RemoteConfigs`. Le raccourci `flow.RemoteConfig` renvoie la première entrée. | | _(nouveau)_ | `Paywalls` (liste de `AdaptyFlowPaywall`) | Chaque entrée est une variation de paywall dans le flow, avec son propre `Name`, `VariationId` et `ProductIdentifiers`. Les méthodes de paywall web prennent un `AdaptyFlowPaywall` — voir [Méthodes de paywall web](#web-paywall-methods). | | `ProductIdentifiers`, `VendorProductIds` | conservé | Sur `AdaptyFlow`, ces propriétés agrègent les produits de toutes les variations de paywall. Chaque variation expose également ses propres `ProductIdentifiers` et `VendorProductIds`. Pour récupérer les produits, continuez d'appeler `GetPaywallProducts(flow)`. | | `HasViewConfiguration` | supprimé | Supprimez tout contrôle `HasViewConfiguration` de votre code — `CreateFlowView` renvoie une erreur à la place (voir [Affichage des flows](#displaying-flows)). | | `Products` (liste de `AdaptyProductReference`) | supprimé | `AdaptyProductReference` n'est plus public, et avec lui les valeurs `PromotionalOfferId`, `WinBackOfferId` et `AndroidOfferId` qu'il portait. Utilisez `ProductIdentifiers` — une liste de `AdaptyProductIdentifier` avec `VendorProductId` et le `BasePlanId` réservé à Android (le `AndroidBasePlanId` de la v3) — ou appelez `GetPaywallProducts(flow)` quand vous avez besoin d'objets `AdaptyPaywallProduct` complets avec les prix et les offres. | | `RemoteConfigString` | supprimé | Lisez la chaîne directement depuis la Remote Config : `flow.RemoteConfig?.Data`, ou l'entrée correspondante dans `flow.RemoteConfigs`. | | _(nouveau)_ | `FlowVersionId` (nullable) | L'identifiant de version du flow, ou `null` s'il n'est pas disponible. | `AdaptyPaywallProduct` gagne un champ supplémentaire : `FlowProductId`, l'identifiant du produit au sein du flow, qui est `null` pour les produits n'appartenant pas à un flow. ## Méthodes de paywall web \{#web-paywall-methods\} `OpenWebPaywall` et `CreateWebPaywallUrl` conservent leurs noms, mais l'argument `paywall` accepte désormais un `AdaptyFlowPaywall` — l'une des variantes dans `flow.Paywalls`. Vous pouvez toujours passer un `AdaptyPaywallProduct` à la place : ```diff showLineNumbers - Adapty.OpenWebPaywall(paywall, AdaptyWebPresentation.ExternalBrowser, (error) => { /* ... */ }); + var flowPaywall = flow.Paywalls.FirstOrDefault(); + if (flowPaywall != null) { + Adapty.OpenWebPaywall(flowPaywall, AdaptyWebPresentation.ExternalBrowser, (error) => { /* ... */ }); + } ``` ## Suivi des vues de flow \{#tracking-flow-views\} ### LogShowPaywall → LogShowFlow `LogShowPaywall` est renommé en `LogShowFlow` et prend désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modifications du tableau de bord. ```diff showLineNumbers - Adapty.LogShowPaywall(paywall, (error) => { /* ... */ }); + Adapty.LogShowFlow(flow, (error) => { /* ... */ }); ``` Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit automatiquement ces vues. ## Afficher des flows \{#displaying-flows\} ### CreatePaywallView → CreateFlowView Renommez la méthode factory et passez l'`AdaptyFlow`. Le type de vue retourné est renommé de `AdaptyUIPaywallView` en `AdaptyUIFlowView`, mais ses méthodes (`Present`, `Dismiss`) restent inchangées, et l'objet de paramètres optionnels conserve les mêmes champs (`LoadTimeout`, `PreloadProducts`, `CustomTags`, `CustomTimers`, `CustomAssets`, `ProductPurchaseParameters`) sous le nouveau nom `AdaptyUICreateFlowViewParameters`, plus deux nouveaux — `Locale` et `EnableSafeAreaPaddings` : ```diff showLineNumbers - AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { + AdaptyUI.CreateFlowView(flow, parameters, (view, error) => { if (error != null) { // handle the error return; } view.Present((error) => { /* handle the error */ }); }); ``` `CreateFlowView` retourne une erreur si le flow n'a pas de vue configurée — cela remplace la vérification `HasViewConfiguration` de la v3 : ```diff showLineNumbers - if (paywall.HasViewConfiguration) { - AdaptyUI.CreatePaywallView(paywall, null, (view, error) => { /* ... */ }); - } + AdaptyUI.CreateFlowView(flow, (view, error) => { + if (error != null) { + // the flow has no view configured, or view creation failed + return; + } + view.Present((error) => { /* handle the error */ }); + }); ``` :::note Une vue de flow est à usage unique : après avoir appelé `Dismiss`, la vue est détruite. Appelez donc à nouveau `CreateFlowView` pour afficher le flow une nouvelle fois. ::: ### Marges de zone sécurisée Android \{#android-safe-area-paddings\} `AdaptyUICreateFlowViewParameters` ajoute `EnableSafeAreaPaddings`, qui contrôle les marges de zone sécurisée Android à l'exécution. Il est ignoré sur iOS et vaut `true` par défaut : ```csharp showLineNumbers var parameters = new AdaptyUICreateFlowViewParameters() .SetEnableSafeAreaPaddings(false); ``` ## Gestion des événements \{#handling-events\} Les interfaces de listener suivent désormais la convention C# avec préfixe `I` — il n'existe plus d'alias hérités : renommez `AdaptyEventListener` en `IAdaptyEventListener` et `AdaptyOnboardingsEventsListener` en `IAdaptyOnboardingsEventsListener` partout où vous les implémentez. L'écouteur d'événements de flow est renommé de `AdaptyPaywallsEventsListener` en `IAdaptyFlowsEventsListener`, sa méthode d'enregistrement de `SetPaywallsEventsListener` en `SetFlowsEventsListener`, et ses callbacks remplacent le préfixe `PaywallView` par `FlowView`. Le corps des handlers existants ne nécessite aucune modification — il suffit de renommer l'interface et les méthodes : ```diff showLineNumbers - public class MyListener : MonoBehaviour, AdaptyPaywallsEventsListener { - public void PaywallViewDidFinishPurchase( - AdaptyUIPaywallView view, + public class MyListener : MonoBehaviour, IAdaptyFlowsEventsListener { + public void FlowViewDidFinishPurchase( + AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { // custom logic after purchase } // ... } - Adapty.SetPaywallsEventsListener(myListener); + Adapty.SetFlowsEventsListener(myListener); ``` Un callback est renommé : `PaywallViewDidFailRendering` devient `FlowViewDidReceiveError`. Il se déclenche pour les mêmes erreurs de rendu qu'auparavant, plus d'autres erreurs d'exécution non liées aux achats : ```diff showLineNumbers - public void PaywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { } + public void FlowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { } ``` Consultez [Gérer les événements de flow et de paywall](unity-handling-events) pour la liste complète des callbacks. ### Nouvelles API \{#new-apis\} - `Adapty.SetObserverModeResolver(...)` avec un `IAdaptyUIObserverModeResolver` — permet de gérer les achats et restaurations initiés depuis des flows lorsque le SDK fonctionne en [mode Observer](implement-observer-mode-unity). Auparavant, cette fonctionnalité n'était disponible que dans les SDKs natifs iOS et Android. Voir [Présenter des flows en mode Observer](unity-present-flows-in-observer-mode). - `Adapty.SetSystemRequestsHandler(...)` avec un `IAdaptyUISystemRequestsHandler` — réservé aux requêtes système issues d'un flow : demandes d'autorisation OS (`FlowViewDidAskPermission`) et demandes d'avis sur l'application (`FlowViewDidRequestAppReview`). Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler. - `AdaptyUICreateFlowViewParameters.Locale` (à définir avec `SetLocale`) — affiche un flow ou un paywall avec une [localisation Builder](add-paywall-locale-in-adapty-paywall-builder) spécifique au lieu de celle qu'Adapty déduit de l'appareil. Un flow est localisé au moment de la création de sa vue, c'est donc le seul endroit où choisir sa localisation ; la vue créée indique la localisation avec laquelle elle a été construite dans `view.Locale`. Voir [Utiliser les localisations et les codes de locale](unity-localizations-and-locale-codes). - Le nouveau callback `FlowViewDidReceiveAnalyticEvent` sur `IAdaptyFlowsEventsListener` est réservé aux événements analytiques personnalisés provenant d'un flow. Les flows n'émettent pas encore ces événements vers votre code, implémentez-le donc avec un corps vide. - `AdaptyUI.OpenUrl(url, openIn, ...)` et `AdaptyUI.RequestAppReview(...)` — la gestion native derrière les actions `open_url` et les demandes d'avis sur l'application. Appelez `OpenUrl` depuis `FlowViewDidPerformAction` pour conserver le comportement URL par défaut ; `RequestAppReview` prend en charge la demande d'avis intégrée, que les flows ne déclenchent pas encore. ## Changements de comportement par défaut \{#default-behavior-changes\} Ces changements ne provoquent pas d'erreurs de compilation, testez-les donc à l'exécution : - **Finalisation d'achat** : en v3, la vue se fermait automatiquement après un achat réussi. En v4, **un flow reste ouvert après un achat ou une erreur jusqu'à ce que vous le fermiez** — le SDK n'applique aucun comportement par défaut. Appelez vous-même `view.Dismiss(...)` dans `FlowViewDidFinishPurchase` dès que l'utilisateur obtient l'accès. - **Bouton retour Android** : le bouton retour système (ou le geste de retour) est transmis à `FlowViewDidPerformAction` sous la forme d'une action `SystemBack` et ne ferme plus le flow par lui-même — alignement avec iOS, où un flow ne peut pas être fermé par un geste système. Donnez aux utilisateurs un moyen de sortir explicite (un bouton **Close** ou une action `on_device_back`), ou fermez la vue vous-même lors du traitement de l'action. - **Les vues sont à usage unique** : après `Dismiss`, la vue est détruite. Appelez à nouveau `CreateFlowView` pour présenter le flow une nouvelle fois. - **Transactions en mode Observer** : `ReportTransaction` ne remonte plus d'erreur de décodage en cas de succès — en v3, la réponse de succès était mal analysée, si bien qu'un rapport réussi se terminait toujours avec une erreur. ## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\} L'ancienne API onboarding est dépréciée dans la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, mais sera supprimée dans une prochaine version. Prévoyez donc la migration de vos onboardings vers le Flow Builder. Symboles dépréciés : `GetOnboarding`, `GetOnboardingForDefaultAudience`, `AdaptyUI.CreateOnboardingView`, `AdaptyUI.PresentOnboardingView`, `AdaptyUI.DismissOnboardingView` et `Adapty.SetOnboardingsEventsListener`. --- # File: migration-to-unity-sdk-314 --- --- title: "Migrer le SDK Adapty Unity vers la v3.14" description: "Migrez vers le SDK Adapty Unity v3.14 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.14.0 est une version majeure qui apporte des améliorations nécessitant toutefois quelques étapes de migration de votre part : 1. Écouteur d'événements distinct pour les événements de paywall. 2. Renommer `AdaptyUI.CreateView` en `AdaptyUI.CreatePaywallView` et les méthodes associées. 3. Mettre à jour la méthode `MakePurchase` pour utiliser `AdaptyPurchaseParameters` à la place des paramètres individuels. 4. Remplacer `SetFallbackPaywalls` par la méthode `SetFallback`. 5. Mettre à jour l'accès aux propriétés du paywall pour utiliser `AdaptyPlacement`. 6. Mettre à jour l'accès à la configuration distante pour utiliser l'objet `AdaptyRemoteConfig`. 7. Remplacer `VendorProductIds` par `ProductIdentifiers` dans le modèle `AdaptyPaywall`. 8. Mettre à jour la politique de récupération de `GetPaywall` pour utiliser `AdaptyFetchPolicy`. ## Écouteur d'événements distinct pour les événements de paywall \{#separate-event-listener-for-paywall-events\} Si vous affichez des paywalls conçus avec le [Paywall Builder](adapty-paywall-builder), les événements de vue de paywall utilisent désormais l'interface dédiée `AdaptyPaywallsEventsListener` et la méthode `SetPaywallsEventsListener`. L'interface principale `AdaptyEventListener` reste utilisée pour les mises à jour de profil et les détails d'installation. ```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 } ``` [En savoir plus sur la gestion des événements de paywall](unity-handling-events). ## Renommer les méthodes de création et de présentation de vue \{#rename-view-creation-and-presentation-methods\} Les méthodes de création et de présentation de vue ont été renommées : ```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 }); }); } ``` De même, la méthode de fermeture a été renommée : ```diff showLineNumbers - AdaptyUI.DismissView(view, (error) => { + AdaptyUI.DismissPaywallView(view, (error) => { // handle the error }); ``` ## Mettre à jour la méthode MakePurchase \{#update-makepurchase-method\} La méthode `MakePurchase` utilise désormais `AdaptyPurchaseParameters` à la place des arguments individuels `subscriptionUpdateParams` et `isOfferPersonalized`. Cela offre une meilleure sécurité de type et permet d'étendre plus facilement les paramètres d'achat à l'avenir. ```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 aucun paramètre supplémentaire n'est nécessaire, vous pouvez simplement utiliser : ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { // handle purchase result }); } ``` ## Mettre à jour la méthode de fallback \{#update-fallback-method\} :::important Lors de la mise à niveau vers le SDK Unity 3.14, vous devrez télécharger les nouveaux fichiers de fallback depuis l'Adapty Dashboard et remplacer ceux existants dans votre projet. ::: La méthode de définition des fallbacks a été mise à jour. La méthode `SetFallbackPaywalls` a été renommée en `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 }); } ``` Consultez l'exemple de code final sur la page [Utiliser des paywalls de secours dans Unity](unity-use-fallback-paywalls). ## Mettre à jour l'accès aux propriétés du paywall \{#update-paywall-property-access\} Les propriétés suivantes ont été déplacées de `AdaptyPaywall` vers `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; } ``` ## Mettre à jour l'accès à la configuration distante \{#update-remote-config-access\} Les propriétés du Remote Config ont été restructurées dans un objet `AdaptyRemoteConfig` pour une meilleure organisation : ```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; } ``` ## Mettre à jour l'utilisation du modèle AdaptyPaywall \{#update-adapty-paywall-model-usage\} La propriété `VendorProductIds` est désormais dépréciée au profit de `ProductIdentifiers`. La nouvelle propriété retourne des objets `AdaptyProductIdentifier` au lieu de simples chaînes de caractères, offrant une information produit mieux structurée. ```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 + } } ``` L'objet `AdaptyProductIdentifier` donne accès à l'identifiant de produit du vendeur via la propriété `VendorProductId`, conservant la même fonctionnalité tout en offrant une meilleure structure pour les améliorations futures. ## Mettre à jour la politique de récupération de GetPaywall \{#update-getpaywall-fetch-policy\} Le type du paramètre `fetchPolicy` dans la méthode `GetPaywall` a été modifié de `AdaptyPaywallFetchPolicy` en `AdaptyPlacementFetchPolicy`. Ce changement unifie l'utilisation de la politique de récupération dans l'ensemble du 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: "Migrer le SDK Adapty Unity vers v3.4" description: "Migrez vers le SDK Adapty Unity v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté. ## Mettre à jour les fichiers de paywall de secours \{#update-fallback-paywall-files\} Mettez à jour vos fichiers de paywall de secours pour assurer la compatibilité avec la nouvelle version du SDK : 1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard. 2. [Remplacez les paywalls de secours existants dans votre application mobile](unity-use-fallback-paywalls) par les nouveaux fichiers. ## Mettre à jour l'implémentation du mode Observateur \{#update-implementation-of-observer-mode\} Si vous utilisez le mode Observateur, assurez-vous de mettre à jour son implémentation. Auparavant, différentes méthodes étaient utilisées pour signaler les transactions à Adapty. Dans la nouvelle version, la méthode `reportTransaction` doit être utilisée de manière cohérente sur Android et iOS. Cette méthode signale explicitement chaque transaction à Adapty, garantissant qu'elle est reconnue. Si un paywall a été utilisé, transmettez l'ID de variation pour associer la transaction à celui-ci. :::warning **Ne sautez pas le signalement des transactions !** Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations. ::: ```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: "Migrer le SDK Adapty Unity vers la v3.3" description: "Migrez vers le SDK Adapty Unity v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty 3.3.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre côté. 1. Mettre à jour vers le SDK Adapty v3.3.x. 2. Plusieurs classes, propriétés et méthodes ont été renommées dans les modules Adapty et AdaptyUI du SDK Adapty. 3. Désormais, la méthode `SetLogLevel` accepte un callback en argument. 4. Désormais, la méthode `PresentCodeRedemptionSheet` accepte un callback en argument. 5. Modifier la façon dont la vue paywall est créée 6. Supprimer la méthode `GetProductsIntroductoryOfferEligibility`. 7. Enregistrer les paywalls de secours dans des fichiers séparés (un par plateforme) dans `Assets/StreamingAssets/` et transmettre les noms de fichiers à la méthode `SetFallbackPaywalls`. 8. Mettre à jour le processus d'achat 9. Mettre à jour la gestion des événements du Paywall Builder. 10. Mettre à jour la gestion des erreurs de paywall du Paywall Builder. 11. Mettre à jour les configurations d'intégration pour Adjust, Amplitude, AppMetrica, Appsflyer, Branch, Firebase et Google Analytics, Mixpanel, OneSignal, Pushwoosh. 13. Mettre à jour l'implémentation du mode Observer. 14. Mettre à jour l'initialisation du plugin Unity avec un appel explicite à `Activate`. ## Mettre à jour le SDK Adapty Unity vers la version 3.3.x \{#upgrade-adapty-unity-sdk-to-33x\} Jusqu'à cette version, le SDK Adapty était le SDK principal et obligatoire pour le bon fonctionnement d'Adapty dans votre application, tandis que le SDK AdaptyUI était optionnel et ne devenait nécessaire que si vous utilisiez le Paywall Builder d'Adapty. À partir de la version 3.3.0, le SDK AdaptyUI est déprécié et AdaptyUI est fusionné dans le SDK Adapty en tant que module. Suite à ces changements, vous devez supprimer AdaptyUISDK et réinstaller AdaptySDK. 1. Supprimez les dépendances de packages **AdaptySDK** et **AdaptyUISDK** de votre projet. 2. Supprimez les dossiers **AdaptySDK** et **AdaptyUISDK**. 3. Importez à nouveau le package AdaptySDK comme décrit sur la page [Installation et configuration du SDK Adapty pour Unity](sdk-installation-unity). ## Renommages \{#renamings\} 1. Renommages dans le module Adapty : | Ancienne version | Nouvelle version | | ------------------------- | ------------------------ | | 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. Renommages dans le module AdaptyUI : | Ancienne version | Nouvelle version | | ------------------ | ------------------ | | CreatePaywallView | CreateView | | PresentPaywallView | PresentView | | DismissPaywallView | DismissView | | AdaptyUI.View | AdaptyUIView | | AdaptyUI.Action | AdaptyUIUserAction | ## Modifier la méthode SetLogLevel \{#change-the-setloglevel-method\} Désormais, la méthode `SetLogLevel` accepte un callback en argument. ```diff showLineNumbers - Adapty.SetLogLevel(Adapty.LogLevel.Verbose); + Adapty.SetLogLevel(Adapty.LogLevel.Verbose, null); // or you can pass the callback to handle the possible error ``` ## Modifier la méthode PresentCodeRedemptionSheet \{#change-the-presentcoderedemptionsheet-method\} Désormais, la méthode `PresentCodeRedemptionSheet` accepte un callback en argument. ```diff showLineNumbers - Adapty.PresentCodeRedemptionSheet(); + Adapty.PresentCodeRedemptionSheet(null); // or you can pass the callback to handle the possible error ``` ## Modifier la façon dont la vue paywall est créée \{#change-how-the-paywall-view-is-created\} Pour un exemple de code complet, consultez [Récupérer la configuration de vue d'un paywall conçu avec le 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 }); ``` ## Supprimer la méthode GetProductsIntroductoryOfferEligibility \{#remove-the-getproductsintroductoryoffereligibility-method\} Avant le SDK Adapty iOS 3.3.0, l'objet produit incluait toujours les offres, que l'utilisateur y soit éligible ou non. Vous deviez vérifier manuellement l'éligibilité avant d'utiliser l'offre. Désormais, l'objet produit n'inclut une offre que si l'utilisateur est éligible. Vous n'avez donc plus besoin de vérifier l'éligibilité — si une offre est présente, l'utilisateur y est éligible. ## Mettre à jour la méthode de fourniture des paywalls de secours \{#update-method-for-providing-fallback-paywalls\} Jusqu'à cette version, les paywalls de secours étaient transmis sous forme de JSON sérialisé. À partir de la v3.3.0, le mécanisme a changé : 1. Enregistrez les paywalls de secours dans des fichiers dans `/Assets/StreamingAssets/`, 1 fichier pour Android et un autre pour iOS. 2. Transmettez les noms de fichiers à la méthode `SetFallbackPaywalls`. Votre code changera de la façon suivante : ```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 }); } ``` Consultez l'exemple de code final sur la page [Utiliser les paywalls de secours dans Unity](unity-use-fallback-paywalls). ## Mettre à jour le processus d'achat \{#update-making-purchase\} Auparavant, les achats annulés et en attente étaient considérés comme des erreurs et retournaient respectivement les codes `PaymentCancelled` et `PendingPurchase`. Une nouvelle classe `AdaptyPurchaseResultType` est désormais utilisée pour traiter les achats annulés, réussis et en attente. Mettez à jour le code d'achat de la façon suivante : ```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; } }); } ``` Consultez l'exemple de code final sur la page [Effectuer des achats dans une application mobile](unity-making-purchases). ## Mettre à jour la gestion des événements du Paywall Builder \{#update-handling-of-paywall-builder-events\} Les achats annulés et en attente ne sont plus considérés comme des erreurs ; tous ces cas sont traités via la méthode `PaywallViewDidFinishPurchase`. 1. Supprimez le traitement de l'événement d'achat annulé. 2. Mettez à jour la gestion de l'événement d'achat réussi de la façon suivante : ```diff showLineNumbers - public void OnFinishPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Profile profile - ) { } + public void PaywallViewDidFinishPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyPurchaseResult purchasedResult + ) { } ``` 3. Mettez à jour la gestion des actions : ```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. Mettez à jour la gestion du démarrage d'un achat : ```diff showLineNumbers - public void OnSelectProduct( - AdaptyUI.View view, - Adapty.PaywallProduct product - ) { } + public void PaywallViewDidSelectProduct( + AdaptyUIView view, + string productId + ) { } ``` 5. Mettez à jour la gestion d'un achat échoué : ```diff showLineNumbers - public void OnFailPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Error error - ) { } + public void PaywallViewDidFailPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyError error + ) { } ``` 6. Mettez à jour la gestion d'une restauration réussie : ```diff showLineNumbers - public void OnFailRestore( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRestore( + AdaptyUIView view, + AdaptyError error + ) { } ``` Consultez l'exemple de code final sur la page [Gérer les événements du paywall](unity-handling-events). ## Mettre à jour la gestion des erreurs de paywall du Paywall Builder \{#update-handling-of-paywall-builder-paywall-errors\} La gestion des erreurs a également changé. Mettez à jour votre code selon les indications ci-dessous. 1. Mettez à jour la gestion des erreurs de chargement des produits : ```diff showLineNumbers - public void OnFailLoadingProducts( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailLoadingProducts( + AdaptyUIView view, + AdaptyError error + ) { } ``` 2. Mettez à jour la gestion des erreurs de rendu : ```diff showLineNumbers - public void OnFailRendering( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRendering( + AdaptyUIView view, + AdaptyError error + ) { } ``` ## Mettre à jour la configuration du SDK d'intégration tierce \{#update-third-party-integration-sdk-configuration\} À partir du SDK Adapty Unity 3.3.0, nous avons mis à jour l'API publique de la méthode `updateAttribution`. Auparavant, elle acceptait un dictionnaire `[AnyHashable: Any]`, vous permettant de passer directement des objets d'attribution de divers services. Désormais, elle requiert un `[String: any Sendable]`, vous devrez donc convertir les objets d'attribution avant de les transmettre. Pour garantir le bon fonctionnement des intégrations avec le SDK Adapty Unity 3.3.0 et versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes comme décrit dans les sections ci-dessous. ### Adjust Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers - using static AdaptySDK.Adapty; using AdaptySDK; Adjust.GetAdid((adid) => { - Adjust.GetAttribution((attribution) => { - Dictionary<String, object> data = new Dictionary<String, object>(); - - 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<String, object> data = new Dictionary<String, object>(); 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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<string, object> parameters, string error) { + string attributionString = JsonUtility.ToJson(parameters); + + Adapty.UpdateAttribution( + attributionString, + "branch", + (error) => { + // handle the error + }); + }); ``` ### Firebase et Google Analytics Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration Firebase et 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [configuration du SDK pour l'intégration 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 + }); ``` ## Mettre à jour l'implémentation du mode Observer \{#update-observer-mode-implementation\} Mettez à jour la façon dont vous associez les paywalls aux transactions. Auparavant, vous utilisiez la méthode `setVariationId` pour assigner le `variationId`. Désormais, vous pouvez inclure le `variationId` directement lors de l'enregistrement de la transaction grâce à la nouvelle méthode `reportTransaction`. Consultez l'exemple de code final dans [Associer les paywalls aux transactions d'achat en mode Observer](report-transactions-observer-mode-unity). ```diff showLineNumbers // every time when calling transaction.finish() - Adapty.SetVariationForTransaction("<variationId>", "<transactionId>", (error) => { - if(error != null) { - // handle the error - return; - } - - // successful binding - }); + Adapty.ReportTransaction( + "YOUR_TRANSACTION_ID", + "PAYWALL_VARIATION_ID", // optional + (error) => { + // handle the error + }); ``` ## Mettre à jour l'initialisation du plugin Unity \{#update-the-unity-plugin-initialization\} À partir du SDK Adapty Unity 3.3.0, l'appel explicite à la méthode `Activate` lors de l'initialisation du plugin est obligatoire : ```csharp showLineNumbers Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: migration-to-unity-sdk-v3 --- --- title: "Migrer le SDK Adapty Unity vers v3.0" description: "Migrez vers le SDK Adapty Unity v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation." --- Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Adapty Paywall Builder](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et à ses riches capacités de design, vos paywalls deviendront plus efficaces et rentables que jamais. ## Processus de migration \{#upgrade-process\} Le processus de migration pour Unity suit les mêmes étapes que pour les autres plateformes : 1. Mettre à niveau vers le SDK Adapty v3.x 2. Migrer vos paywalls existants vers le nouveau Paywall Builder Pour des instructions de migration spécifiques à Unity, consultez le [guide d'installation du SDK Unity](sdk-installation-unity) et suivez les étapes de migration générales décrites dans le guide de migration principal. --- # File: unity-migration-guide --- --- title: "Guide de migration SDK" description: "Guides de migration pour le SDK Adapty Unity." --- ## Guides de migration ### [Guide de migration vers le SDK Adapty Unity 3.x](unity-sdk-migration-guides) Apprenez à migrer depuis les versions antérieures vers le SDK Adapty Unity 3.x. ## Nouveautés ### Version 3.x - Présentation des paywalls améliorée - Gestion des erreurs améliorée - Meilleur support C# - Optimisations des performances ### Version 2.x - Nouvelles fonctionnalités d'onboarding - Analytics améliorée - Flow d'achat amélioré - Corrections de bugs et améliorations de stabilité ## Changements majeurs ### Version 3.x - API Observer mise à jour - Méthodes de présentation des paywalls modifiées - Structure de gestion des erreurs modifiée ### Version 2.x - API d'onboarding mise à jour - Structure du profil modifiée - Flow d'achat modifié ## Liste de contrôle pour la migration Lors de la migration vers une nouvelle version : - [ ] Vérifier les changements majeurs - [ ] Mettre à jour les appels API - [ ] Tester toutes les fonctionnalités - [ ] Mettre à jour la gestion des erreurs - [ ] Vérifier le suivi des analytics - [ ] Tester sur toutes les plateformes --- # End of Documentation _Generated on: 2026-08-04T15:08:26.353Z_ _Successfully processed: 52/52 files_