# FLUTTER - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: fr Generated on: 2026-08-11T20:58:32.171Z 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: ^ ``` 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 { @override void initState() { _initializeAdapty(); super.initState(); } Future _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 `` inclut tools : ```xml ... ``` #### 2. Remplacez les attributs de sauvegarde dans `` \{#2-override-backup-attributes-in-application\} Dans le même fichier `AndroidManifest.xml`, mettez à jour la balise `` afin que votre application fournisse les valeurs finales et indique au gestionnaire de fusion 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 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" ``` **Pour Android 11 et inférieur** (utilise l'ancien format de sauvegarde complète) : ```xml title="sample_backup_rules.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 ``` #### 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 createState() => _FlowScreenState(); } class _FlowScreenState extends State { @override void initState() { super.initState(); _showFlowIfNeeded(); } Future _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 _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 _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. ::: ### 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. ::: Le [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration d'Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Il détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape. **Outils pris en charge** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI. Pour l'installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README du skill](https://github.com/adaptyteam/adapty-sdk-integration-skill). Le dépôt contient deux skills — `adapty-sdk-integration` et `ads-manager`, qui exécute Apple Search Ads via le CLI Adapty. Chaque commande ci-dessous installe les deux. **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` git clone https://github.com/adaptyteam/adapty-sdk-integration-skill.git cp -r adapty-sdk-integration-skill/skills/* ~/.copilot/skills/ ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex ou tout autre outil** — utilisez le [skills CLI](https://skills.sh) (notez que les skills installés de cette façon ne se mettent pas à jour automatiquement) : ``` npx skills add adaptyteam/adapty-sdk-integration-skill --all ``` `--all` installe les deux skills dans chaque agent détecté. Sans ce paramètre, le CLI vous demande lequel des deux vous souhaitez installer. Vous pouvez aussi cloner le dépôt et copier les répertoires sous `skills/` dans le répertoire des skills de votre outil. Après l'installation, exécutez le skill dans votre projet : ``` /adapty-sdk-integration ``` Le skill 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. **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. ::: **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. ::: **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. ::: ### 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\} :::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\} 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\} --- # 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." --- 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. :::
Avant de commencer à afficher des flows et 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 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.
## 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` |

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 durant la session pour éviter les requêtes réseau.

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.

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.

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

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.

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.

| ## 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` |

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.

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.

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.

| ## 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.
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. :::
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-flutter) 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. 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** |

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` désigne l'anglais, `pt-br` représente le portugais brésilien.

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.

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

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.

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.

| | **loadTimeout** | par 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 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 pas définir de limite, utilisez `TimeInterval.INFINITE`.

| ## 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** |

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](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et notre recommandation d'utilisation.

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

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.

| ## 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.
--- # 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." --- 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) } } ``` ::: 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) } } ``` ::: --- # 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." --- 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; } } ``` 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; } } ``` --- # 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." --- :::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) { } ```
Exemple d'événement (cliquer pour développer) ```dart void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ```
#### 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) { } ```
Exemple d'événement (cliquer pour développer) ```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' } ```
#### 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; } } ```
Exemples d'événements (cliquer pour développer) ```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; } } ```
:::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) { } ```
Exemple d'événement (cliquer pour développer) ```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) } ```
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.
:::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) { } ```
Exemple d'événement (cliquer pour développer) ```dart void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ```
#### 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) { } ```
Exemple d'événement (cliquer pour développer) ```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' } ```
#### 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; } } ```
Exemples d'événements (cliquer pour développer) ```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; } } ```
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. |
Exemples d'événements (cliquer pour développer) ```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 } } ```
#### 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) { } ```
Exemple d'événement (cliquer pour développer) ```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 } ```
#### 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) { } ```
Exemple d'événement (cliquer pour développer) ```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) } ```
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) { } ```
Exemple d'événement (cliquer pour développer) ```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 } ```
### 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) { } ```
Exemple d'événement (cliquer pour développer) ```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 } ```
#### 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 } ```
Exemple d'événement (cliquer pour développer) ```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() } ```
Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le signaler.
--- # 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." --- ## Pourquoi c'est important \{#why-this-is-important\} Les codes de langue entrent en jeu lorsqu'Adapty choisit la localisation pour un flow ou un onboarding, 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\} Dans le SDK v4, les flows et les onboardings associent les codes de langue différemment : les flows sont localisés par le SDK sur l'appareil, les onboardings par le serveur Adapty. ### Flows et paywalls Paywall Builder Un paywall créé dans le Paywall Builder est livré en tant que flow dans le SDK v4, donc la règle ci-dessous couvre les deux. La correspondance est exacte. Le SDK compare le code que vous transmettez avec les codes de localisation du flow caractère par caractère : il ne modifie pas la casse, ne remplace pas les tirets bas (`_`) par des tirets (`-`), et ne se replie pas sur le sous-tag de langue. Pour un flow avec une localisation `pt-br`, seul `pt-br` correspond : `pt-BR`, `pt_BR` et `pt-PT` ne correspondent pas. Lorsque le code ne correspond à aucune localisation, le flow s'affiche silencieusement dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) — le SDK ne retourne pas d'erreur et ne consigne pas d'avertissement. Lorsque le code correspond, Adapty fusionne la localisation avec la localisation par défaut : les chaînes et les ressources que la localisation correspondante ne définit pas sont issues de la localisation par défaut. Omettre le code de langue ne revient pas à demander la localisation par défaut du flow : le SDK substitue un `en` fixe. Un flow dont la langue par défaut est `de` s'affiche quand même en `en` s'il possède une localisation `en`, et ne revient au `de` qu'en l'absence de celle-ci. :::warning Passez le code de langue exactement tel qu'il est configuré dans le tableau de bord — sous-balises en minuscules séparées par des tirets. Ne passez pas directement un identifiant de locale système : `Platform.localeName` renvoie `pt_BR` et `PlatformDispatcher.instance.locale.toLanguageTag()` renvoie `pt-BR`, et les deux utilisent la localisation par défaut en repli. Convertissez la valeur dans votre application avant de la passer. ::: ### Onboardings Les onboardings sont localisés côté serveur, et les règles du serveur tolèrent d'autres formats. Lorsque vous passez un `locale` à [`getOnboarding`](flutter-get-onboardings) : 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 cherche la localisation correspondante 4. Si aucune correspondance n'est encore trouvée, Adapty renvoie le contenu dans la locale par défaut de l'onboarding Cette approche permet à `pt_BR`, `pt-BR` et `pt-br` de tous pointer vers la même localisation d'onboarding. ## 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 créés dans le builder** : le SDK ne lit pas les paramètres régionaux de l'appareil, donc résolvez-les dans votre application et passez-les comme argument `locale` de `createFlowView` ou `AdaptyUIFlowPlatformView`. L'argument est facultatif — omettez-le 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) quand le flow n'a pas de localisation `en`. `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 ``` Adapty stocke ces codes `locale` dans le format décrit dans [Standard de code locale dans Adapty](#locale-code-standard-at-adapty). Le SDK ne fait pas correspondre les Remote Configs à une locale, c'est donc à votre application de choisir quelle entrée appliquer. ## 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. --- # 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: ); // 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: , 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. ## 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. :::
Avant de commencer à présenter des flows (cliquez pour développer) 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.
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). ::: ## 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). ::: --- # 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 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 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 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 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." --- 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. :::
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-flutter) 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 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` |

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.

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.

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.

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.

| | **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 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 différentes requêtes en interne.

| :::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 :
• `paymentMode` : un enum avec les valeurs `AdaptyPaymentMode.freeTrial`, `AdaptyPaymentMode.payAsYouGo`, `AdaptyPaymentMode.payUpFront` et `AdaptyPaymentMode.unknown`. Les essais gratuits correspondent au type `AdaptyPaymentMode.freeTrial`.
• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, cette valeur est `0`.
• `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.
• `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.
• `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` |

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

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 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. :::
Avant de commencer à récupérer des paywalls et des 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-flutter) dans votre application mobile.
## 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** |

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](flutter-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.

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.

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.

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.

| | **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 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 différentes requêtes en interne.

| 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 :
• `paymentMode` : un enum avec les valeurs `AdaptyPaymentMode.freeTrial`, `AdaptyPaymentMode.payAsYouGo`, `AdaptyPaymentMode.payUpFront` et `AdaptyPaymentMode.unknown`. Les essais gratuits seront de type `AdaptyPaymentMode.freeTrial`.
• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, cette valeur sera `0`.
• `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 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.
• `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** |

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](flutter-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 reçoivent toujours les 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 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.

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.

|
--- # 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." --- 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`. | 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). | --- # 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** |

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.

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 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\}
À propos des codes d'offre 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.
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** |

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.

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-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." --- 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 |
  • Pour iOS : identifiant de la transaction.
  • 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.
| | 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). |
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 |
  • 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 : 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.
| | 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). |
**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. **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. ::: **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) { } ```
--- # 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." --- --- # 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 `` de `AdaptyProfileParameters.Builder` et les valeurs `` correspondantes sont listées ci-dessous : | Clé | Valeur | |---|-----| |

email

phoneNumber

firstName

lastName

| 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.
Avant de vérifier le statut d'abonnement (cliquez pour développer) - 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)
## 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 |

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.

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.

| 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 `` 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." --- --- # 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** |

optionnel

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 est pour la langue, le second est pour la région.

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

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

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.

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

| | **loadTimeout** | 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 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 impliquer différentes requêtes en coulisses.

| 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** |

optionnel

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 est pour la langue, le second est pour la région.

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

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

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.

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

| --- # 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` : ```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 } ``` ```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) { }, ) ``` ## 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 false ``` 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. 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); } ```
Exemple d'événement (Cliquer pour développer) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
### 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}'); } ```
Exemple d'événement (Cliquer pour développer) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
### 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. :::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(); } ```
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 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 _openPaywall(String actionId) async { // Implement your paywall opening logic here } // Embedded widget onPaywallAction: (meta, actionId) { _openPaywall(actionId); } ```
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 } } ```
### 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 |
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: 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).
Formes des propriétés pour chaque type de params (cliquez pour développer) ```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; } } ```
## 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." --- --- # 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 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(); late final StreamSubscription subscription; late final Timer timer; void resolve(Future 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.
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 |

Ce code d'erreur indique que l'utilisateur a annulé une demande de paiement.

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.

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

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.

Assurez-vous de configurer les offres souhaitées dans AppStore Connect et de transmettre un identifiant d'offre valide.

| | [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 |

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 :

1\. L'application Play Store sur l'appareil de l'utilisateur n'est pas à jour.

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

3. L'utilisateur est un utilisateur entreprise et son administrateur a désactivé les achats pour les utilisateurs.

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

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

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

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.

Si vous rencontrez cette erreur, suivez les étapes de la section [Correctif pour l'erreur Code-1000 `noProductIDsFound`](InvalidProductIdentifiers-flutter).

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

Aucun reçu valide n'est disponible sur l'appareil. Cela peut poser problème lors des tests en sandbox.

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.

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

Cette erreur indique un problème d'intégration Adapty ou avec les offres.

Consultez [Configurer l'intégration App Store](app-store-connection-configuration) et [Offres](offers) pour savoir comment les configurer.

| | 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é.
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.
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.
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.
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é.
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.
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.
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.
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**. 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**. 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. 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**. 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. ## É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**. 2. Cliquez sur le nom du groupe d'abonnements pour afficher vos produits. 3. Sélectionnez le produit que vous testez. 4. Faites défiler jusqu'à la section **Availability** et vérifiez que tous les pays et régions requis y sont listés. ## Étape 4. Vérifier les prix du produit \{#step-5-check-product-prices\} 1. Retournez dans la section **Monetization** → **Subscriptions** d'**App Store Connect**. 2. Cliquez sur le nom du groupe d'abonnements. 3. Sélectionnez le produit que vous testez. 4. Faites défiler jusqu'à **Subscription Pricing** et développez la section **Current Pricing for New Subscribers**. 5. Assurez-vous que tous les prix requis sont bien listés. ## É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**. 2. Sélectionnez le nom de votre entreprise. 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**. 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 le SDK Flutter Adapty vers v4.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.3 ``` 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.3 ``` 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(); 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(); 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: , + ); - 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 :
  • 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 messages d'information importants, comme ceux qui tracent le cycle de vie des différents modules, 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.
| | **withObserverMode** | optionnel |

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.

La valeur par défaut est `false`.

🚧 En mode Observer, le SDK Adapty ne fermera aucune transaction. Assurez-vous donc de les gérer vous-même.

| | **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 |

Définissez à `true` pour désactiver la collecte et le partage de l'IDFA.

le partage de l'adresse IP de l'utilisateur.

La valeur par défaut est `false`.

Pour plus de détails sur la collecte de l'IDFA, consultez la section [Intégration Analytics](analytics-integration#disable-collection-of-advertising-identifiers).

| | **withIpAddressCollectionDisabled** | optionnel |

Définissez à `true` pour désactiver la collecte et le partage de l'adresse IP de l'utilisateur.

La valeur par défaut est `false`.

| ### 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: , ); } 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-11T20:58:32.197Z_ _Successfully processed: 53/53 files_