:::important
Dans un projet Kotlin Multiplatform, appliquez ces modifications dans le module d'application Android (celui qui génère l'APK/AAB), par exemple `androidApp` ou `app` :
- Manifeste : `androidApp/src/main/AndroidManifest.xml`
- XML des règles de sauvegarde : `androidApp/src/main/res/xml/`
:::
#### Les achats échouent après le retour depuis une autre application sous Android \{#purchases-fail-after-returning-from-another-app-in-android\}
Si l'Activity qui lance le processus 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 annulé.
Pour que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui lance le processus d'achat, et évitez tout autre mode.
Dans votre `AndroidManifest.xml`, assurez-vous que l'Activity qui lance le processus d'achat est définie sur `standard` ou `singleTop` :
```xml
```
---
# File: kmp-quickstart-paywalls
---
---
title: "Activer les achats avec Flow Builder dans le SDK Kotlin Multiplatform"
description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder."
---
Ce guide utilise les API du SDK Adapty Kotlin Multiplatform v4 (bêta). Si vous utilisez la v3, consultez le [guide de migration](migration-to-kmp-sdk-v4) pour les noms de méthodes correspondants.
Pour activer les achats intégrés, vous devez comprendre trois concepts clés :
- [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie)
- [**Flows**](adapty-flow-builder) – des séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez plutôt un paywall — voir [Implémenter les paywalls manuellement](kmp-quickstart-manual).
- [**Placements**](placements) – où et quand vous affichez les flows dans votre application (par exemple `main`, `onboarding`, `settings`). Vous associez des flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs.
Adapty vous propose trois façons d'activer les achats dans votre application. Choisissez celle qui correspond à vos besoins :
| Implémentation | Complexité | Quand l'utiliser |
|---|---|---|
| Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère tout le flux d'achat, la validation des reçus et la gestion des abonnements en coulisses. |
| Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre application, mais récupérez quand même l'objet flow depuis Adapty pour garder de la flexibilité sur les offres produits. Voir le [guide](kmp-quickstart-manual). |
| Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur présente des limitations dans Adapty. Voir l'[article](observer-vs-full-mode). |
:::important
**Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.**
Si vous préférez construire l'interface du paywall vous-même, voir [Implémenter les paywalls manuellement](kmp-quickstart-manual).
:::
Pour afficher un flow créé dans Adapty Flow Builder, vous n'avez besoin que de :
1. **Récupérer le flow** : Obtenez-le depuis Adapty.
2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre application.
3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre application. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons.
## Avant de commencer \{#before-you-start\}
Avant de commencer, effectuez ces étapes :
1. Connectez votre application à l'[App Store](initial_ios) et/ou à [Google Play](initial-android) dans l'Adapty Dashboard.
2. [Créez vos produits](create-product) dans Adapty.
3. [Créez un flow et ajoutez-y des produits](create-paywall).
4. [Créez un placement et ajoutez-y votre flow](create-placement).
5. [Installez et activez le SDK Adapty](sdk-installation-kotlin-multiplatform) dans le code de votre application.
:::tip
La façon la plus rapide de réaliser ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des flows et des placements avec la [Developer CLI](developer-cli-quickstart).
:::
## 1. Récupérer le flow \{#1-get-the-flow\}
Vos flows sont associés à des placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter différents flows pour différentes audiences ou de lancer des [tests A/B](ab-tests).
Pour récupérer un flow créé dans Adapty Flow Builder, vous devez :
1. Obtenir l'objet `flow` par l'ID du [placement](placements) en utilisant la méthode `getFlow`.
2. Créer la vue du flow avec la méthode `createFlowView`. La vue contient les éléments d'interface et le style nécessaires pour afficher le flow. Si aucune vue n'est configurée pour le flow, `createFlowView` retourne une erreur — gérez-la dans `onError`.
:::important
Pour obtenir la vue, vous devez activer le bouton **Show on device** dans le Flow Builder. Sinon, `createFlowView` retournera une erreur et le flow ne sera pas affiché.
:::
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID")
.onSuccess { flow ->
AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// the flow has no view configured, or view creation failed
}
}
.onError { error ->
// handle the error
}
```
## 2. Afficher le flow \{#2-display-the-flow\}
Une fois que vous avez le flow, quelques lignes suffisent pour l'afficher.
Pour afficher le flow visuel à l'écran de l'appareil, vous devez d'abord créer la vue. Pour ce faire, appelez la méthode `AdaptyUI.createFlowView()` :
```kotlin showLineNumbers
AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// handle the error
}
```
Une fois la vue créée avec succès, vous pouvez la présenter à l'écran de l'appareil. Chaque vue ne peut être utilisée qu'une seule fois : après avoir appelé `dismiss()`, appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois.
:::tip
Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](kmp-present-paywalls).
:::
## 3. Gérer les actions des boutons \{#3-handle-button-actions\}
Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Kotlin Multiplatform gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des liens.
Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Ou vous souhaitez peut-être remplacer leur comportement par défaut.
Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire.
Notez que, par défaut, le flow reste ouvert après un achat réussi. Si vous souhaitez le fermer une fois l'achat terminé, ignorez la vue dans le callback `flowViewDidFinishPurchase`.
:::tip
Consultez nos guides sur la gestion des [actions](kmp-handle-paywall-actions) et des [événements](kmp-handling-events) des boutons.
:::
```kotlin showLineNumbers
AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() }
else -> Unit
}
}
override fun flowViewDidFinishPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) {
mainUiScope.launch { view.dismiss() }
}
}
})
```
## Prochaines étapes \{#next-steps\}
Votre flow est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow.
Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](kmp-check-subscription-status) pour vous assurer d'afficher un flow ou d'accorder l'accès aux fonctionnalités payantes aux bons utilisateurs.
## Exemple complet \{#full-example\}
Voici comment toutes ces étapes peuvent être intégrées ensemble dans votre application.
```kotlin showLineNumbers
// Set up the observer for handling flow events
AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() }
else -> Unit
}
}
override fun flowViewDidFinishPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) {
mainUiScope.launch { view.dismiss() }
}
}
})
// Get and display the flow
Adapty.getFlow("YOUR_PLACEMENT_ID")
.onSuccess { flow ->
AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// the flow has no view configured — use custom logic
}
}
.onError { error ->
// handle the error
}
```
---
# File: kmp-check-subscription-status
---
---
title: "Vérifier le statut d'abonnement dans le SDK Kotlin Multiplatform"
description: "Apprenez à vérifier le statut d'abonnement dans votre application Kotlin Multiplatform avec Adapty."
---
Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil.
Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — afficher un paywall ou leur donner accès aux fonctionnalités payantes.
## Obtenir le statut d'abonnement \{#get-subscription-status\}
Quand vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Vous avez deux options :
- Appelez `getProfile` si vous avez besoin des données de profil les plus récentes immédiatement (comme au lancement de l'application) ou si vous souhaitez forcer une mise à jour.
- Configurez des **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement à chaque changement de statut d'abonnement.
### Récupérer le profil \{#get-profile\}
La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil :
```kotlin showLineNumbers
Adapty.getProfile()
.onSuccess { profile ->
// check the access
}
.onError { error ->
// handle the error
}
```
### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\}
Pour recevoir automatiquement les mises à jour du profil dans votre application :
1. Utilisez `Adapty.setOnProfileUpdatedListener()` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode chaque fois que le statut d'abonnement de l'utilisateur change.
2. Stockez les données du profil mis à jour quand cette méthode est appelée, afin de pouvoir les utiliser partout dans votre application sans effectuer de requêtes réseau supplémentaires.
```kotlin showLineNumbers
class SubscriptionManager {
private var currentProfile: AdaptyProfile? = null
init {
// Listen for profile updates
Adapty.setOnProfileUpdatedListener { profile ->
currentProfile = profile
// Update UI, unlock content, etc.
}
}
// Use stored profile instead of calling getProfile()
fun hasAccess(): Boolean {
return currentProfile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true
}
}
```
:::note
Adapty appelle automatiquement le listener de mise à jour du profil au démarrage de votre application, fournissant ainsi les données d'abonnement en cache même si l'appareil est hors ligne.
:::
## Associer le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\}
Lorsque vous devez prendre des décisions immédiates sur l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'accès aux sections premium ou avant l'affichage de contenu spécifique.
```kotlin showLineNumbers
private fun checkAccessAndShowPaywall() {
// First, check if user has access
Adapty.getProfile()
.onSuccess { profile ->
val hasAccess = profile.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true
if (!hasAccess) {
// User doesn't have access, show paywall
showPaywall()
} else {
// User has access, show premium content
showPremiumContent()
}
}
.onError { error ->
// If we can't check access, show paywall as fallback
showPaywall()
}
}
private fun showPaywall() {
// Get and display paywall using the KMP SDK
Adapty.getPaywall("YOUR_PLACEMENT_ID")
.onSuccess { paywall ->
if (paywall.hasViewConfiguration) {
val paywallView = AdaptyUI.createPaywallView(paywall = paywall)
paywallView?.present()
} else {
// Handle remote config paywall or show custom UI
handleRemoteConfigPaywall(paywall)
}
}
.onError { error ->
// Handle paywall loading error
showError("Unable to load paywall")
}
}
private fun showPremiumContent() {
// Show your premium content here
// This is where you unlock paid features
}
```
## Étapes suivantes \{#next-steps\}
Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](kmp-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce qu'ils ont payé.
---
# File: kmp-quickstart-identify
---
---
title: "Identifier les utilisateurs dans le SDK Kotlin Multiplatform"
description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés dans KMP."
---
:::important
Ce guide vous concerne si vous disposez de votre propre système d'authentification. Vous apprendrez ici comment gérer les profils utilisateurs dans Adapty afin de les aligner avec votre système d'authentification existant.
:::
La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application :
- Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users).
- Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users).
**Concepts clés** :
- Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement.
- Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**.
- Vous fournissez un **customer user ID** afin de faire le lien entre les profils Adapty et votre système d'authentification interne.
Voici les différences entre les utilisateurs anonymes et identifiés :
| | Utilisateurs anonymes | Utilisateurs identifiés |
|------------------------------|----------------------------------------------------------------|--------------------------------------------------------------------------------------|
| **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID |
| **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil entre les sessions et les appareils |
| **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'application | Les données des utilisateurs identifiés persistent entre les installations de l'application |
## Utilisateurs anonymes \{#anonymous-users\}
Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** :
1. Lors de l'activation du SDK au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**.
2. Lorsque l'utilisateur effectue un achat dans l'application, celui-ci est **associé à son profil Adapty et à son compte store**.
3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe depuis un **nouvel appareil**, Adapty **crée un nouveau profil anonyme à l'activation**.
4. Si l'utilisateur a déjà effectué des achats dans votre application, ses achats sont par défaut automatiquement synchronisés depuis l'App Store lors de l'activation du SDK.
Ainsi, avec les utilisateurs anonymes, de nouveaux profils sont créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics).
Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations.
:::note
Les restaurations à partir d'une sauvegarde se comportent différemment des réinstallations. Par défaut, lorsqu'un utilisateur restaure depuis une sauvegarde, le SDK conserve les données en cache et ne crée pas de nouveau profil. Vous pouvez configurer ce comportement à l'aide du paramètre `withAppleClearDataOnBackup`. [En savoir plus](sdk-installation-kotlin-multiplatform#clear-data-on-backup-restore).
:::
## Utilisateurs identifiés \{#identified-users\}
Vous avez deux options pour identifier les utilisateurs dans l'application :
- [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient.
- [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`.
:::important
Par défaut, lorsqu'Adapty reçoit un achat d'un Customer User ID actuellement associé à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils bénéficient d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails.
:::
### Lors de la connexion/inscription \{#during-loginsignup\}
Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après qu'ils se sont connectés ou inscrits), utilisez la méthode `identify` pour définir leur customer user ID.
- Si vous **n'avez pas encore utilisé ce customer user ID**, Adapty le liera automatiquement au profil actuel.
- Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID.
:::important
Les customer user IDs doivent être uniques pour chaque utilisateur. Si vous codez la valeur du paramètre en dur, tous les utilisateurs seront considérés comme un seul et même utilisateur.
:::
Attendez que `identify` se termine (dans son callback `onSuccess`) avant d'appeler d'autres méthodes du SDK. Des appels simultanés peuvent atterrir sur le profil anonyme. Voir [Ordre des appels dans le SDK Kotlin Multiplatform](kmp-sdk-call-order).
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") // Unique for each user
.onSuccess {
// successful identify
}
.onError { error ->
// handle the error
}
```
### Lors de l'activation du SDK \{#during-the-sdk-activation\}
Si vous connaissez déjà un customer user ID au moment d'activer le SDK, vous pouvez l'envoyer dans la méthode `activate` au lieu d'appeler `identify` séparément.
Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`.
Vous pouvez passer un customer user ID existant (que vous avez déjà utilisé) ou un nouveau. Si vous en passez un nouveau, le nouveau profil créé lors de l'activation sera automatiquement lié au customer user ID.
:::note
Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées en fonction des ID d'appareil.
Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application.
Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une énième installation, ni de l'utilisation d'un customer user ID existant.
La création d'un profil (lors de l'activation du SDK ou de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génèrent pas d'événements d'installation supplémentaires.
Si vous souhaitez compter les installations en fonction des utilisateurs uniques plutôt que des appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```kotlin showLineNumbers
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
.build()
```
### Déconnecter les utilisateurs \{#log-users-out\}
Si vous avez un bouton pour déconnecter les utilisateurs, utilisez la méthode `logout`.
:::important
La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur.
:::
```kotlin showLineNumbers
Adapty.logout()
.onSuccess {
// successful logout
}
.onError { error ->
// handle the error
}
```
:::info
Pour reconnecter des utilisateurs à l'application, utilisez la méthode `identify`.
:::
### Autoriser les achats sans connexion \{#allow-purchases-without-login\}
Si vos utilisateurs peuvent effectuer des achats avant et après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion :
1. Lorsqu'un utilisateur non connecté effectue un achat, Adapty l'associe à son ID de profil anonyme.
2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié.
- S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé.
- S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez obtenir le niveau d'accès réel après le changement de profil. Vous pouvez soit appeler [`getProfile`](kmp-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](kmp-check-subscription-status) pour que les données se synchronisent automatiquement.
## Étapes suivantes \{#next-steps\}
Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons beaucoup de succès dans la monétisation de votre application !
Pour tirer encore plus parti d'Adapty, vous pouvez explorer ces sujets :
- [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu
- [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code
- [**Définir des attributs de profil personnalisés**](kmp-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher des paywalls différents à différents utilisateurs
---
# File: adapty-sdk-integration-skill-kmp
---
---
title: "Intégrer Adapty dans votre application Kotlin Multiplatform avec la compétence d'intégration SDK"
description: "Utilisez la compétence adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Kotlin Multiplatform de bout en bout avec votre outil de codage IA."
---
:::important
La compétence est en version bêta. Si elle se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-kmp) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée.
:::
La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape.
**Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) :
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil.
Après l'installation, exécutez la compétence dans votre projet :
```
/adapty-sdk-integration
```
La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification.
---
# File: adapty-cursor-kmp
---
---
title: "Intégrer Adapty dans votre application Kotlin Multiplatform avec l'aide de l'IA"
description: "Un guide étape par étape pour intégrer Adapty dans votre application Kotlin Multiplatform avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA."
---
Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Kotlin Multiplatform à l'aide d'un outil IA — vous lui fournissez la bonne documentation Adapty dans le bon ordre.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\}
Adapty nécessite une configuration préalable dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire via un skill LLM interactif ou manuellement depuis le Dashboard.
### Approche par skill (recommandée) \{#skill-approach-recommended\}
Le skill Adapty CLI permet à votre LLM de configurer votre application, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Vous devez uniquement [connecter vos stores](integrate-payments) dans le Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris quand ouvrir le Dashboard pour connecter vos stores.
### Approche manuelle \{#dashboard-approach\}
Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les fournir vous-même.
1. **Connectez vos stores** : dans l'Adapty Dashboard, rendez-vous dans **App settings → General**. Connectez l'App Store et Google Play si votre application KMP cible les deux plateformes. C'est indispensable pour que les achats fonctionnent.
[Connecter les stores](integrate-payments)
2. **Copiez votre clé SDK publique** : dans l'Adapty Dashboard, rendez-vous dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez au builder de configuration Adapty.
3. **Créez au moins un produit** : dans l'Adapty Dashboard, rendez-vous sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les transmet via les paywalls.
[Ajouter des produits](quickstart-products)
4. **Créez un paywall et un placement** : dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis associez-le à un placement sur la page **Placements**. Dans le code, l'ID du placement est la chaîne que vous passez à `Adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Créer un paywall](quickstart-paywalls)
5. **Configurez les niveaux d'accès** : dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels["premium"]?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants ont accès à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` vs. un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder.
:::tip
Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Dites à votre LLM : « Ma clé SDK publique est X, mon ID de placement est Y » pour qu'il génère le code d'initialisation et de récupération des paywalls correct.
:::
### À configurer quand vous êtes prêt \{#set-up-when-ready\}
Ces éléments ne sont pas requis pour commencer à coder, mais vous en aurez besoin au fil de votre intégration :
- **Tests A/B** : à configurer sur la page **Placements**. Aucune modification de code nécessaire.
[Tests A/B](ab-tests)
- **Paywalls et placements supplémentaires** : ajoutez des appels `getPaywall` avec différents IDs de placement.
- **Intégrations analytics** : à configurer sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytics](analytics-integration) et [intégrations attribution](attribution-integration).
## Alimenter votre LLM avec la documentation Adapty \{#feed-adapty-docs-to-your-llm\}
### Utiliser Context7 (recommandé) \{#use-context7-recommended\}
[Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bonnes docs en fonction de ce que vous demandez — plus besoin de coller des URL manuellement.
Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez :
```
npx ctx7 setup
```
Cette commande détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7).
Une fois configuré, référencez la bibliothèque Adapty dans vos prompts :
```
Use the adaptyteam/adapty-docs library to look up how to install the Kotlin Multiplatform SDK
```
:::warning
Même si Context7 évite de coller des liens de documentation manuellement, l'ordre d'implémentation reste important. Suivez la [procédure d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne.
:::
### Utiliser la documentation en texte brut \{#use-plain-text-docs\}
Vous pouvez accéder à n'importe quelle page de documentation Adapty en Markdown brut. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-kmp.md](https://adapty.io/docs/fr/adapty-cursor-kmp.md).
Chaque étape de la [procédure d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc « À envoyer à votre LLM » avec des liens `.md` à coller.
Pour accéder à plus de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous.
## Procédure d'implémentation \{#implementation-walkthrough\}
La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les docs à envoyer à votre LLM, ce que vous devriez observer une fois terminé, et les problèmes courants.
### Planifier votre intégration \{#plan-your-integration\}
Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA dispose d'un mode de planification (comme le mode plan de Cursor ou Claude Code), utilisez-le pour que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire du code.
Indiquez à votre LLM quelle approche vous utilisez pour les achats — cela détermine les guides à suivre :
- [**Adapty Paywall Builder**](adapty-paywall-builder) : vous créez des paywalls dans le builder no-code d'Adapty, et le SDK les affiche automatiquement.
- [**Paywalls créés manuellement**](kmp-making-purchases) : vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats.
- [**Mode Observer**](observer-vs-full-mode) : vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour les analytics et les intégrations.
Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le guide de démarrage rapide](kmp-quickstart-paywalls).
### Installer et configurer le SDK \{#install-and-configure-the-sdk\}
Ajoutez la dépendance du SDK Adapty via Gradle et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans ça.
**Guide :** [Installer et configurer le SDK Adapty](sdk-installation-kotlin-multiplatform)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/sdk-installation-kotlin-multiplatform.md
```
:::tip[Checkpoint]
- **Attendu :** L'application se compile et se lance. Logcat (Android) ou la console Xcode (iOS) affiche le log d'activation Adapty.
- **Point d'attention :** « Public API key is missing » → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings.
:::
### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\}
Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides nécessaires dépendent de la façon dont vous gérez les achats.
Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration.
**Guides :**
- [Activer les achats avec les paywalls (démarrage rapide)](kmp-quickstart-paywalls)
- [Récupérer les paywalls du Paywall Builder et leur configuration](kmp-get-pb-paywalls)
- [Afficher les paywalls](kmp-present-paywalls)
- [Gérer les événements de paywall](kmp-handling-events)
- [Répondre aux actions des boutons](kmp-handle-paywall-actions)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/kmp-quickstart-paywalls.md
- https://adapty.io/docs/fr/kmp-get-pb-paywalls.md
- https://adapty.io/docs/fr/kmp-present-paywalls.md
- https://adapty.io/docs/fr/kmp-handling-events.md
- https://adapty.io/docs/fr/kmp-handle-paywall-actions.md
```
:::tip[Checkpoint]
- **Attendu :** Le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox.
- **Point d'attention :** Paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement au tableau de bord et que le placement a bien une audience assignée.
:::
**Guides :**
- [Activer les achats dans votre paywall personnalisé (démarrage rapide)](kmp-quickstart-manual)
- [Récupérer les paywalls et les produits](fetch-paywalls-and-products-kmp)
- [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-kmp)
- [Effectuer des achats](kmp-making-purchases)
- [Restaurer des achats](kmp-restore-purchase)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/kmp-quickstart-manual.md
- https://adapty.io/docs/fr/fetch-paywalls-and-products-kmp.md
- https://adapty.io/docs/fr/present-remote-config-paywalls-kmp.md
- https://adapty.io/docs/fr/kmp-making-purchases.md
- https://adapty.io/docs/fr/kmp-restore-purchase.md
```
:::tip[Checkpoint]
- **Attendu :** Votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox.
- **Point d'attention :** Tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience.
:::
**Guides :**
- [Vue d'ensemble du mode Observer](observer-vs-full-mode)
- [Implémenter le mode Observer](implement-observer-mode-kmp)
- [Signaler les transactions en mode Observer](report-transactions-observer-mode-kmp)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/observer-vs-full-mode.md
- https://adapty.io/docs/fr/implement-observer-mode-kmp.md
- https://adapty.io/docs/fr/report-transactions-observer-mode-kmp.md
```
:::tip[Checkpoint]
- **Attendu :** Après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty.
- **Point d'attention :** Aucun événement → vérifiez que vous signalez bien les transactions à Adapty et que les notifications serveur sont configurées pour les deux stores.
:::
### Vérifier le statut de l'abonnement \{#check-subscription-status\}
Après un achat, vérifiez dans le profil utilisateur la présence d'un niveau d'accès actif pour restreindre l'accès au contenu premium.
**Guide :** [Vérifier le statut de l'abonnement](kmp-check-subscription-status)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/kmp-check-subscription-status.md
```
:::tip[Checkpoint]
- **Attendu :** Après un achat sandbox, `profile.accessLevels["premium"]?.isActive` retourne `true`.
- **Point d'attention :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord.
:::
### Identifier les utilisateurs \{#identify-users\}
Liez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent d'un appareil à l'autre.
:::important
Ignorez cette étape si votre application ne dispose pas d'authentification.
:::
**Guide :** [Identifier les utilisateurs](kmp-quickstart-identify)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/kmp-quickstart-identify.md
```
:::tip[Checkpoint]
- **Attendu :** Après avoir appelé `Adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé.
- **Point d'attention :** Appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter une attribution à un profil anonyme.
:::
### Préparer la mise en production \{#prepare-for-release\}
Une fois votre intégration validée en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt pour la production.
**Guide :** [Checklist de mise en production](release-checklist)
À envoyer à votre LLM :
```
Read these Adapty docs before releasing:
- https://adapty.io/docs/fr/release-checklist.md
```
:::tip[Checkpoint]
- **Attendu :** Tous les éléments de la checklist confirmés : connexions aux stores, notifications serveur, flux d'achat, vérifications des niveaux d'accès et exigences de confidentialité.
- **Point d'attention :** Notifications serveur manquantes → configurez les App Store Server Notifications dans **App settings → iOS SDK** et les Google Play Real-Time Developer Notifications dans **App settings → Android SDK**.
:::
## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\}
Si vous avez besoin de donner à votre LLM un contexte plus large au-delà des pages individuelles, nous hébergeons des fichiers d'index qui listent ou combinent toute la documentation Adapty :
- [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par exemple ChatGPT), vous devrez télécharger `llms.txt` et le joindre à la conversation en tant que fichier.
- [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : toute la documentation Adapty combinée en un seul fichier. Très volumineux — à utiliser uniquement quand vous avez besoin d'une vue d'ensemble complète.
- Sous-ensembles spécifiques à Kotlin Multiplatform [`kmp-llms.txt`](https://adapty.io/docs/fr/kmp-llms.txt) et [`kmp-llms-full.txt`](https://adapty.io/docs/fr/kmp-llms-full.txt) : sous-ensembles par plateforme qui économisent des tokens par rapport au site complet.
---
# File: kmp-paywalls
---
---
title: "Flows et paywalls - Kotlin Multiplatform"
description: "Affichez et gérez les flows et paywalls créés avec l'Adapty Flow Builder ou le Paywall Builder dans votre application Kotlin Multiplatform."
---
## Afficher les paywalls \{#display-paywalls\}
### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\}
:::tip
Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](kmp-quickstart-paywalls).
:::
### Implémenter les paywalls manuellement \{#implement-paywalls-manually\}
Pour d'autres guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](kmp-implement-paywalls-manually).
## Fonctionnalités utiles \{#useful-features\}
---
# File: kmp-get-pb-paywalls
---
---
title: "Récupérer les flows et paywalls - Kotlin Multiplatform"
description: "Récupérez les flows et paywalls depuis Adapty dans votre application Kotlin Multiplatform."
---
Après avoir [conçu votre flow ou paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement et à sa configuration d'affichage, comme décrit ci-dessous.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à afficher des flows dans votre application mobile (cliquer pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard.
4. Installez le [SDK Adapty](sdk-installation-kotlin-multiplatform) 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 façon 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 flow ou le paywall et sa [configuration de vue](kmp-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les afficher à l'utilisateur.
Pour obtenir un flow ou un paywall, utilisez la méthode `getFlow` :
```kotlin showLineNumbers
Adapty.getFlow(
placementId = "YOUR_PLACEMENT_ID",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { flow ->
// the requested flow/paywall
}.onError { error ->
// handle the error
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. |
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.
Toutefois, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les flows et les paywalls localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour les récupérer plus rapidement ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour garantir que vous disposez toujours de la dernière version tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en arrière-plan.
Pour Kotlin Multiplatform : vous pouvez créer une `Duration` avec des fonctions d'extension comme `5.seconds`, où `.seconds` provient de `kotlin.time.Duration.Companion.seconds`.
|
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :---------- |
| Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`instanceIdentity`, `variationId`), le nom, les variantes de paywall (`paywalls` — une liste d'`AdaptyFlowPaywall`), et les Remote Configs (`remoteConfigs` — une liste avec une entrée par locale). Pour récupérer les produits réels en vue d'un préchargement, d'une interface personnalisée ou de vérifications programmatiques, appelez `getPaywallProducts(flow)`. |
## Récupérer la configuration de la vue \{#fetch-the-view-configuration\}
Après avoir récupéré le flow ou le paywall, chargez sa configuration de vue et créez la vue en une seule étape avec la méthode `createFlowView`. Il n'y a pas de flag distinct à vérifier : si le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall), `createFlowView` renvoie la vue prête à être affichée. Si le placement est un paywall personnalisé sans interface Builder, `createFlowView` renvoie une `AdaptyResult.Error` — [traitez-le comme un paywall Remote Config](present-remote-config-paywalls-kmp).
:::important
Assurez-vous d'activer le bouton **Show on device** dans le Flow Builder. Si cette option n'est pas activée, la configuration de la vue ne sera pas disponible pour être récupérée.
:::
```kotlin showLineNumbers
AdaptyUI.createFlowView(
flow = flow,
loadTimeout = 5.seconds,
preloadProducts = true
).onSuccess { view ->
// use view
}.onError { error ->
// the flow has no view configured, or view creation failed
}
```
| Paramètre | Présence | Description |
| :--------------------------- | :------------- | :----------------------------------------------------------- |
| **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. |
| **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) avec laquelle afficher la vue — par exemple, `en` ou `pt-br`. Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de version `en`. Voir [Localisations et codes de langue](kmp-localizations-and-locale-codes). |
| **loadTimeout** | optionnel | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront renvoyés. Notez que dans de rares cas, cette méthode peut expirer légèrement après la valeur spécifiée dans `loadTimeout`, car l'opération peut inclure différentes requêtes en interne. Vous pouvez utiliser des fonctions d'extension comme `5.seconds` de `kotlin.time.Duration.Companion`. |
| **preloadProducts** | optionnel | Définissez à `true` pour précharger les produits et améliorer les performances. Lorsque cette option est activée, les produits sont chargés à l'avance, réduisant le temps nécessaire à l'affichage du flow ou du paywall. |
| **productPurchaseParams** | optionnel | Une map de [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) vers [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Utilisez ceci pour configurer des paramètres d'achat spécifiques, comme des offres personnalisées ou des paramètres de mise à jour d'abonnement, pour des produits individuels dans le flow ou le paywall. |
:::note
Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Builder](add-paywall-locale-in-adapty-paywall-builder).
:::
Une fois chargé, [présentez le flow ou le paywall](kmp-present-paywalls).
## Obtenir un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\}
En général, les flows et les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ces situations, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout.
Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée consiste à 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 compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (héritée), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus.
- **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow ou du paywall, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall).
:::
```kotlin showLineNumbers
Adapty.getFlowForDefaultAudience(
placementId = "YOUR_PLACEMENT_ID",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
).onSuccess { flow ->
// the requested flow
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles sont disponibles. Dans ce cas, les utilisateurs risquent de ne pas obtenir les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter des requêtes réseau.
Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.
|
## Personnaliser les ressources \{#customize-assets\}
Pour personnaliser les images et vidéos de votre flow ou paywall, implémentez des ressources personnalisées.
Les images hero et les vidéos ont des IDs prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leur ID et personnalisez leur comportement.
Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans l'Adapty Dashboard.
Par exemple, vous pouvez :
- Afficher une image ou vidéo différente à certains utilisateurs.
- Afficher une image d'aperçu locale pendant le chargement d'une image principale distante.
- Afficher une image d'aperçu avant de lancer une vidéo.
Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via une map :
:::info
Le SDK Kotlin Multiplatform ne prend en charge que les ressources locales. Pour le contenu distant, vous devez télécharger et mettre en cache les ressources localement avant de les utiliser dans les ressources personnalisées.
:::
```kotlin showLineNumbers
// Import generated Res class for accessing resources
viewModelScope.launch {
// Get URIs for bundled resources using Res.getUri()
val heroImagePath = Res.getUri("files/images/hero_image.png")
val demoVideoPath = Res.getUri("files/videos/demo_video.mp4")
// Or read image as byte data
val imageByteData = Res.readBytes("files/images/avatar.png")
// Create custom assets map
val customAssets: Map = mapOf(
// Load image from app resources (bundled with the app)
// Files should be placed in commonMain/composeResources/files/
"hero_image" to AdaptyCustomAsset.localImageResource(
path = heroImagePath
),
// Or use image byte data
"avatar" to AdaptyCustomAsset.localImageData(
data = imageByteData
),
// Load video from app resources
"demo_video" to AdaptyCustomAsset.localVideoResource(
path = demoVideoPath
),
// Or use a video file from device storage
"intro_video" to AdaptyCustomAsset.localVideoFile(
path = "/path/to/local/video.mp4"
),
// Apply custom brand colors
"brand_primary" to AdaptyCustomAsset.color(
colorHex = "#FF6B35"
),
// Create gradient background
"card_gradient" to AdaptyCustomAsset.linearGradient(
colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"),
stops = listOf(0.0f, 0.5f, 1.0f)
)
)
// Use custom assets when creating the flow view
AdaptyUI.createFlowView(
flow = flow,
customAssets = customAssets
).onSuccess { view ->
// Present the flow with custom assets
view.present()
}.onError { error ->
// Handle the error - the flow will fall back to default appearance
}
}
```
:::note
Si un asset est introuvable ou ne se charge pas, le flow ou le paywall reviendra à son apparence par défaut configurée dans le Builder.
:::
Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape de ce processus consiste à récupérer le paywall associé au placement et sa configuration d'affichage, comme décrit ci-dessous.
Veuillez noter que ce sujet concerne les paywalls personnalisées 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-kmp).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
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 incorporez-y les produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et incorporez-y votre paywall](create-placement) dans l'Adapty Dashboard.
4. Installez le [SDK Adapty](sdk-installation-kotlin-multiplatform) 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 façon 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 crucial de récupérer le paywall et sa [configuration de vue](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images de se télécharger avant de les présenter à l'utilisateur.
Pour obtenir un paywall, utilisez la méthode `getPaywall` :
```kotlin showLineNumbers
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | 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](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.
|
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | 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.
Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour retourner les données en cache lorsqu'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 un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les paywalls localement sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls, tout en assurant une fiabilité optimale même en cas de connexion internet limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront 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 interne.
Pour Kotlin Multiplatform : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne fixer aucune limite, utilisez `TimeInterval.INFINITE`.
|
Paramètres de réponse :
| Paramètre | Description |
| :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Paywall | Un objet [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) contenant une liste d'identifiants de produits, l'identifiant du paywall, 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 sera pas disponible.
:::
Après avoir récupéré le paywall, vérifiez s'il contient une `ViewConfiguration`, ce qui indique qu'il a été créé avec le Paywall Builder. Cela vous permettra de savoir comment afficher le paywall. Si la `ViewConfiguration` est présente, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls-kmp).
Utilisez la méthode `createPaywallView` pour charger la configuration de la vue.
```kotlin showLineNumbers
if (paywall.hasViewConfiguration) {
AdaptyUI.createPaywallView(
paywall = paywall,
loadTimeout = 5.seconds,
preloadProducts = true
).onSuccess { paywallView ->
// use paywallView
}.onError { error ->
// handle the error
}
} else {
// use your custom logic
}
```
| Paramètre | Présence | Description |
| :--------------------------- | :------------- | :----------------------------------------------------------- |
| **paywall** | obligatoire | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. |
| **loadTimeout** | optionnel | Cette valeur limite le délai d'attente pour cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront 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. Vous pouvez utiliser des fonctions d'extension telles que `5.seconds` de `kotlin.time.Duration.Companion`. |
| **preloadProducts** | optionnel | Définissez à `true` pour précharger les produits et améliorer les performances. Lorsque cette option est activée, les produits sont chargés à l'avance, ce qui réduit le temps nécessaire à l'affichage du paywall. |
| **productPurchaseParams** | optionnel | Une map de [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) vers [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Utilisez-la pour configurer des paramètres d'achat spécifiques tels que des offres personnalisées ou des paramètres de mise à jour d'abonnement pour des produits individuels dans le paywall. |
:::note
Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation du Paywall Builder](add-paywall-locale-in-adapty-paywall-builder).
:::
Une fois chargé, [affichez le paywall](kmp-present-paywalls).
## Obtenir un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\}
En règle générale, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et paywalls, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout.
Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getPaywall`
La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs :
- **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non rendus.
- **Perte de ciblage** : Tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder).
:::
```kotlin showLineNumbers
Adapty.getPaywallForDefaultAudience(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). 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 locale](localizations-and-locale-codes) pour plus d'informations sur les codes de locale et notre recommandation d'utilisation.
|
| **fetchPolicy** | défaut : `AdaptyPaywallFetchPolicy.Default` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs 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 est conservé après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
|
## Personnaliser les ressources \{#customize-assets\}
Pour personnaliser les images et vidéos de votre paywall, mettez en place 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é, vous ciblez ces éléments par leur ID et personnalisez leur comportement.
Pour les autres images et vidéos, vous devez [définir un ID personnalisé](custom-media) dans le dashboard Adapty.
Par exemple, vous pouvez :
- Afficher une image ou une vidéo différente à certains utilisateurs.
- Afficher une image d'aperçu locale pendant le chargement d'une image principale distante.
- Afficher une image d'aperçu avant de lancer une vidéo.
:::important
Pour utiliser cette fonctionnalité, mettez à jour le SDK Adapty vers la version 3.7.0 ou supérieure.
:::
Voici un exemple de la façon dont vous pouvez fournir des ressources personnalisées via une map :
:::info
Le SDK Kotlin Multiplatform ne prend en charge que les ressources locales. Pour le contenu distant, vous devez télécharger et mettre en cache les ressources localement avant de les utiliser dans les ressources personnalisées.
:::
```kotlin showLineNumbers
// Import generated Res class for accessing resources
viewModelScope.launch {
// Get URIs for bundled resources using Res.getUri()
val heroImagePath = Res.getUri("files/images/hero_image.png")
val demoVideoPath = Res.getUri("files/videos/demo_video.mp4")
// Or read image as byte data
val imageByteData = Res.readBytes("files/images/avatar.png")
// Create custom assets map
val customAssets: Map = mapOf(
// Load image from app resources (bundled with the app)
// Files should be placed in commonMain/composeResources/files/
"hero_image" to AdaptyCustomAsset.localImageResource(
path = heroImagePath
),
// Or use image byte data
"avatar" to AdaptyCustomAsset.localImageData(
data = imageByteData
),
// Load video from app resources
"demo_video" to AdaptyCustomAsset.localVideoResource(
path = demoVideoPath
),
// Or use a video file from device storage
"intro_video" to AdaptyCustomAsset.localVideoFile(
path = "/path/to/local/video.mp4"
),
// Apply custom brand colors
"brand_primary" to AdaptyCustomAsset.color(
colorHex = "#FF6B35"
),
// Create gradient background
"card_gradient" to AdaptyCustomAsset.linearGradient(
colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"),
stops = listOf(0.0f, 0.5f, 1.0f)
)
)
// Use custom assets when creating paywall view
AdaptyUI.createPaywallView(
paywall = paywall,
customAssets = customAssets
).onSuccess { paywallView ->
// Present the paywall with custom assets
paywallView.present()
}.onError { error ->
// Handle the error - paywall will fall back to default appearance
}
}
```
:::note
Si une ressource est introuvable ou ne parvient pas à se charger, le paywall reviendra à son apparence par défaut configurée dans le Paywall Builder.
:::
---
# File: kmp-present-paywalls
---
---
title: "Afficher les flows et paywalls - Kotlin Multiplatform"
description: "Présentez les flows et paywalls aux utilisateurs dans votre application Kotlin Multiplatform."
---
Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être.
:::warning
Ce guide couvre les flows et les **paywalls du nouveau Paywall Builder** rendus par Adapty. Le processus diffère pour les paywalls en Remote Config et le [mode Observateur](observer-vs-full-mode).
- Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-kmp).
- Pour présenter des flows en **mode Observateur**, consultez [Présenter des flows en mode Observateur](kmp-present-flows-in-observer-mode).
:::
Pour obtenir l'objet `flow` utilisé ci-dessous, consultez [Récupérer les flows et paywalls](kmp-get-pb-paywalls).
Le SDK Kotlin Multiplatform d'Adapty offre deux façons de présenter les flows et les paywalls :
- **Avec Compose Multiplatform**
- **Sans Compose Multiplatform**
## Avec Compose Multiplatform \{#with-compose-multiplatform\}
Pour afficher un flow ou un paywall, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createFlowView`](kmp-get-pb-paywalls#fetch-the-view-configuration). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le flow à nouveau, appelez `createFlowView` une nouvelle fois pour créer une nouvelle instance de `view`.
:::warning
Réutiliser la même `view` sans la recréer peut entraîner une erreur.
:::
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
AdaptyUI.createFlowView(flow = flow).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
### Afficher une boîte de dialogue \{#show-dialog\}
Utilisez cette méthode plutôt que les boîtes de dialogue natives lorsqu'un flow ou un paywall est présenté sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du flow, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du flow sur toutes les plateformes.
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
view.showDialog(
title = "Close this screen?",
content = "You will lose access to exclusive offers.",
primaryActionTitle = "Stay",
secondaryActionTitle = "Close"
).onSuccess { action ->
if (action == AdaptyUIDialogActionType.SECONDARY) {
// User confirmed - close the flow
view.dismiss()
}
// If primary - do nothing, user stays
}.onError { error ->
// handle the error
}
}
```
### Configurer le style de présentation iOS \{#configure-ios-presentation-style\}
Configurez la façon dont le flow ou le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`.
```kotlin showLineNumbers
viewModelScope.launch {
val view = AdaptyUI.createFlowView(flow = flow).getOrNull()
view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET)
}
```
## Sans Compose Multiplatform \{#without-compose-multiplatform\}
:::note
`createNativeFlowView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`.
:::
Pour intégrer un flow ou un paywall sans Compose Multiplatform, appelez `createNativeFlowView`. La méthode retourne un `AdaptyNativeFlowView` que vous ajoutez à votre mise en page :
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val nativeView = AdaptyUI.createNativeFlowView(
context = context,
viewModelStoreOwner = activity,
flow = flow,
observer = myFlowObserver,
)
// Embed in your Compose layout:
AndroidView(
factory = { nativeView.view },
modifier = Modifier.fillMaxSize()
)
```
Par défaut, une vue intégrée n'applique pas les marges de zone de sécurité — votre mise en page est censée gérer les insets elle-même. Si vous souhaitez que la vue les applique elle-même, passez `androidEnableSafeArea = true` à `createNativeFlowView`. Ce paramètre est spécifique à Android.
Comme les méthodes par défaut des interfaces KMP deviennent `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIFlowsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` :
```kotlin showLineNumbers title="iosMain (Kotlin)"
open class BaseFlowObserver : AdaptyUIFlowsEventsObserver
```
Créez ensuite une sous-classe en Swift, en ne redéfinissant que ce dont vous avez besoin :
```swift showLineNumbers title="Swift"
class MyFlowObserver: BaseFlowObserver {
override func flowViewDidPerformAction(view: AdaptyUIFlowView, action: any AdaptyUIAction) {
if action is AdaptyUIActionCloseAction {
// remove nativeView from your view hierarchy
}
}
}
let nativeView = AdaptyUI.shared.createNativeFlowView(
flow: flow,
observer: MyFlowObserver()
)
// nativeView.viewController is a UIViewController.
// Add it to your SwiftUI view or UIKit hierarchy.
```
### Libérer la vue \{#dispose-the-view\}
Appelez `dispose()` lorsque vous retirez la vue de votre mise en page. Cela désenregistre l'écouteur d'événements et libère les ressources internes.
```kotlin showLineNumbers title="Kotlin Multiplatform"
nativeView.dispose()
```
## Tags personnalisés \{#custom-tags\}
Les tags personnalisés vous permettent d'éviter de créer des flows ou des paywalls distincts pour différents scénarios. Imaginez un seul flow qui s'adapte dynamiquement selon les données de l'utilisateur. Par exemple, au lieu d'un générique « Bonjour ! », vous pourriez accueillir les utilisateurs personnellement avec « Bonjour, John ! » ou « Bonjour, Ann ! »
Voici quelques façons d'utiliser les tags personnalisés :
- Afficher le nom ou l'e-mail de l'utilisateur sur le flow ou le paywall.
- Afficher le jour de la semaine actuel pour stimuler les ventes (par ex., « Bonne journée de jeudi »).
- Ajouter des détails personnalisés sur les produits que vous vendez (comme le nom d'un programme fitness ou un numéro de téléphone dans une application VoIP).
Les tags personnalisés vous aident à créer un flow flexible qui s'adapte à diverses situations, rendant l'interface de votre application plus personnalisée et engageante.
:::warning
Dans certains cas, votre application peut ne pas savoir par quoi remplacer un tag personnalisé — notamment si les utilisateurs utilisent une ancienne version du SDK AdaptyUI. Pour éviter ce problème, ajoutez toujours un texte de repli qui remplacera les lignes contenant des tags inconnus. Sans cela, les utilisateurs pourraient voir les tags affichés sous forme de code (``).
:::
Pour utiliser des tags personnalisés dans votre flow ou paywall, passez-les lors de la création de la vue de flow :
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
AdaptyUI.createFlowView(
flow = flow,
customTags = customTags
).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
val nativeView = AdaptyUI.createNativeFlowView(
context = context,
viewModelStoreOwner = activity,
flow = flow,
observer = myFlowObserver,
customTags = customTags,
)
```
```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)"
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
val nativeView = AdaptyUI.createNativeFlowView(
flow = flow,
observer = myFlowObserver,
customTags = customTags,
)
```
## Minuteries personnalisées \{#custom-timers\}
La minuterie est un excellent outil pour promouvoir des offres spéciales et saisonnières avec une limite de temps. Notez cependant que cette minuterie n'est pas liée à la validité de l'offre ni à la durée de la campagne. Il s'agit simplement d'un compte à rebours autonome qui démarre à partir de la valeur que vous définissez et diminue jusqu'à zéro. Lorsque la minuterie atteint zéro, rien ne se passe — elle reste simplement à zéro.
Vous pouvez personnaliser le texte avant et après la minuterie pour créer le message souhaité, par exemple : « Offre se termine dans : 10:00 sec. »
Pour utiliser des minuteries personnalisées dans votre flow ou paywall, passez-les lors de la création de la vue de flow :
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
AdaptyUI.createFlowView(
flow = flow,
customTimers = customTimers
).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
val nativeView = AdaptyUI.createNativeFlowView(
context = context,
viewModelStoreOwner = activity,
flow = flow,
observer = myFlowObserver,
customTimers = customTimers,
)
```
```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)"
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
val nativeView = AdaptyUI.createNativeFlowView(
flow = flow,
observer = myFlowObserver,
customTimers = customTimers,
)
```
Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et comment il doit l'être.
:::warning
Ce guide concerne uniquement les **paywalls du nouveau Paywall Builder**. Le processus de présentation diffère pour les paywalls conçus avec Remote Config et le [mode Observateur](observer-vs-full-mode).
Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec Remote Config](present-remote-config-paywalls-kmp).
:::
Le SDK Kotlin Multiplatform d'Adapty offre deux façons de présenter les paywalls :
- **Avec Compose Multiplatform**
- **Sans Compose Multiplatform**
## Avec Compose Multiplatform \{#with-compose-multiplatform\}
Pour afficher un paywall, utilisez la méthode `view.present()` sur la `view` créée par la méthode [`createPaywallView`](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher le paywall à nouveau, appelez `createPaywallView` une nouvelle fois pour créer une nouvelle instance de `view`.
:::warning
Réutiliser la même `view` sans la recréer peut entraîner une erreur.
:::
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
AdaptyUI.createPaywallView(paywall = paywall).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
### Afficher une boîte de dialogue \{#show-dialog\}
Utilisez cette méthode plutôt que les boîtes de dialogue natives lorsqu'une vue de paywall est présentée sur Android. Sur Android, les alertes classiques apparaissent derrière la vue du paywall, ce qui les rend invisibles pour les utilisateurs. Cette méthode garantit un affichage correct de la boîte de dialogue au-dessus du paywall sur toutes les plateformes.
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
view.showDialog(
title = "Close paywall?",
content = "You will lose access to exclusive offers.",
primaryActionTitle = "Stay",
secondaryActionTitle = "Close"
).onSuccess { action ->
if (action == AdaptyUIDialogActionType.SECONDARY) {
// User confirmed - close the paywall
view.dismiss()
}
// If primary - do nothing, user stays
}.onError { error ->
// handle the error
}
}
```
### Configurer le style de présentation iOS \{#configure-ios-presentation-style\}
Configurez la façon dont le paywall est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`.
```kotlin showLineNumbers
viewModelScope.launch {
val view = AdaptyUI.createPaywallView(paywall = paywall).getOrNull()
view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET)
}
```
## Sans Compose Multiplatform \{#without-compose-multiplatform\}
:::note
`createNativePaywallView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`.
:::
Pour intégrer un paywall sans Compose Multiplatform, appelez `createNativePaywallView`. La méthode retourne un `AdaptyNativePaywallView` que vous ajoutez à votre mise en page :
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val nativeView = AdaptyUI.createNativePaywallView(
context = context,
viewModelStoreOwner = activity,
paywall = paywall,
observer = myPaywallObserver,
)
// Embed in your Compose layout:
AndroidView(
factory = { nativeView.view },
modifier = Modifier.fillMaxSize()
)
```
Comme les méthodes par défaut des interfaces KMP deviennent `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIPaywallsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` :
```kotlin showLineNumbers title="iosMain (Kotlin)"
open class BasePaywallObserver : AdaptyUIPaywallsEventsObserver
```
Créez ensuite une sous-classe en Swift, en ne redéfinissant que ce dont vous avez besoin :
```swift showLineNumbers title="Swift"
class MyPaywallObserver: BasePaywallObserver {
override func paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: any AdaptyUIAction) {
if action is AdaptyUIActionCloseAction {
// remove nativeView from your view hierarchy
}
}
}
let nativeView = AdaptyUI.shared.createNativePaywallView(
paywall: paywall,
observer: MyPaywallObserver()
)
// nativeView.viewController is a UIViewController.
// Add it to your SwiftUI view or UIKit hierarchy.
```
### Libérer la vue \{#dispose-the-view\}
Appelez `dispose()` lorsque vous retirez la vue de votre mise en page. Cela désenregistre l'écouteur d'événements et libère les ressources internes.
```kotlin showLineNumbers title="Kotlin Multiplatform"
nativeView.dispose()
```
## Tags personnalisés \{#custom-tags\}
Les tags personnalisés vous permettent d'éviter de créer des paywalls distincts pour différents scénarios. Imaginez un seul paywall qui s'adapte dynamiquement selon les données de l'utilisateur. Par exemple, au lieu d'un générique « Bonjour ! », vous pourriez accueillir les utilisateurs personnellement avec « Bonjour, John ! » ou « Bonjour, Ann ! »
Voici quelques façons d'utiliser les tags personnalisés :
- Afficher le nom ou l'e-mail de l'utilisateur sur le paywall.
- Afficher le jour de la semaine actuel pour stimuler les ventes (par ex., « Bonne journée de jeudi »).
- Ajouter des détails personnalisés sur les produits que vous vendez (comme le nom d'un programme fitness ou un numéro de téléphone dans une application VoIP).
Les tags personnalisés vous aident à créer un paywall flexible qui s'adapte à diverses situations, rendant l'interface de votre application plus personnalisée et engageante.
:::warning
Dans certains cas, votre application peut ne pas savoir par quoi remplacer un tag personnalisé — notamment si les utilisateurs utilisent une ancienne version du SDK AdaptyUI. Pour éviter ce problème, ajoutez toujours un texte de repli qui remplacera les lignes contenant des tags inconnus. Sans cela, les utilisateurs pourraient voir les tags affichés sous forme de code (``).
:::
Pour utiliser des tags personnalisés dans votre paywall, passez-les lors de la création de la vue de paywall :
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
AdaptyUI.createPaywallView(
paywall = paywall,
customTags = customTags
).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
val nativeView = AdaptyUI.createNativePaywallView(
context = context,
viewModelStoreOwner = activity,
paywall = paywall,
observer = myPaywallObserver,
customTags = customTags,
)
```
```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)"
val customTags = mapOf(
"USERNAME" to "John",
"DAY_OF_WEEK" to "Thursday"
)
val nativeView = AdaptyUI.createNativePaywallView(
paywall = paywall,
observer = myPaywallObserver,
customTags = customTags,
)
```
## Minuteries personnalisées \{#custom-timers\}
La minuterie de paywall est un excellent outil pour promouvoir des offres spéciales et saisonnières avec une limite de temps. Notez cependant que cette minuterie n'est pas liée à la validité de l'offre ni à la durée de la campagne. Il s'agit simplement d'un compte à rebours autonome qui démarre à partir de la valeur que vous définissez et diminue jusqu'à zéro. Lorsque la minuterie atteint zéro, rien ne se passe — elle reste simplement à zéro.
Vous pouvez personnaliser le texte avant et après la minuterie pour créer le message souhaité, par exemple : « Offre se termine dans : 10:00 sec. »
Pour utiliser des minuteries personnalisées dans votre paywall, passez-les lors de la création de la vue de paywall :
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
AdaptyUI.createPaywallView(
paywall = paywall,
customTimers = customTimers
).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
val nativeView = AdaptyUI.createNativePaywallView(
context = context,
viewModelStoreOwner = activity,
paywall = paywall,
observer = myPaywallObserver,
customTimers = customTimers,
)
```
```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)"
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0),
"CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59)
)
val nativeView = AdaptyUI.createNativePaywallView(
paywall = paywall,
observer = myPaywallObserver,
customTimers = customTimers,
)
```
---
# File: kmp-handle-paywall-actions
---
---
title: "Répondre aux actions des flows - Kotlin Multiplatform"
description: "Gérez les actions des boutons des flows et paywalls dans votre app Kotlin Multiplatform."
---
Si vous créez des flows ou des paywalls avec l'Adapty Flow Builder ou le Paywall Builder, il est essentiel de configurer correctement les boutons :
1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé.
2. Écrivez le code dans votre app pour gérer chaque action assignée.
Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code.
:::warning
**Seuls les achats, les restaurations, la fermeture des flows/paywalls et l'ouverture de liens sont gérés automatiquement.** Toutes les autres actions de boutons, comme les actions personnalisées, nécessitent une implémentation adaptée dans le code de l'app.
:::
## Configurer l'AdaptyUIFlowsEventsObserver \{#set-up-the-adaptyuiflowseventsobserver\}
Pour gérer les actions des flows, vous devez implémenter l'interface `AdaptyUIFlowsEventsObserver` et la configurer avec `AdaptyUI.setFlowsEventsObserver()`. Cette étape doit être effectuée tôt dans le cycle de vie de votre app, généralement dans votre activité principale ou lors de l'initialisation de l'app.
```kotlin
// In your app initialization
AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver())
```
Toutes les actions de boutons arrivent dans le callback `flowViewDidPerformAction(view, action)` sous forme de classe scellée `AdaptyUIAction` : `CloseAction`, `AndroidSystemBackAction`, `OpenUrlAction` ou `CustomAction`.
:::warning
Surcharger `flowViewDidPerformAction` remplace la gestion par défaut de **toutes** les actions, pas uniquement celle qui vous intéresse. Conservez les branches par défaut pour `CloseAction` (fermer le flow) et `OpenUrlAction` (ouvrir l'URL) sauf si vous souhaitez les modifier, comme illustré dans les exemples ci-dessous.
:::
## Fermer les flows et les paywalls \{#close-flows-and-paywalls\}
Pour ajouter un bouton qui fermera votre flow ou votre paywall :
1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**.
2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le flow.
:::info
Dans le SDK Kotlin Multiplatform, `CloseAction` déclenche la fermeture du flow ou du paywall par défaut. Vous pouvez toutefois surcharger ce comportement dans votre code si nécessaire. Par exemple, fermer un flow pourrait déclencher l'ouverture d'un autre.
:::
```kotlin
class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction ->
mainUiScope.launch { view.dismiss() } // default behavior
is AdaptyUIAction.OpenUrlAction ->
AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior
else -> Unit
}
}
}
// Set up the observer
AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver())
```
Si vous utilisez [`createNativeFlowView`](kmp-present-paywalls#without-compose-multiplatform), appeler `view.dismiss()` n'a aucun effet — la vue est intégrée dans votre layout et non présentée via la pile KMP. Retirez la vue de votre layout et appelez `dispose()` dessus à la place.
## Gérer le bouton retour système Android \{#handle-the-android-system-back-button\}
Appuyer sur le bouton retour système Android (ou utiliser le geste retour) émet `AdaptyUIAction.AndroidSystemBackAction`. Par défaut, cette action est ignorée — le flow reste ouvert et l'utilisateur en sort par le chemin que vous définissez, comme un bouton **Close** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même :
```kotlin
class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction ->
mainUiScope.launch { view.dismiss() } // default behavior
is AdaptyUIAction.AndroidSystemBackAction ->
mainUiScope.launch { view.dismiss() } // not handled by default
is AdaptyUIAction.OpenUrlAction ->
AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior
else -> Unit
}
}
}
```
## Ouvrir des URLs depuis des flows et des paywalls \{#open-urls-from-flows-and-paywalls\}
:::tip
Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**.
:::
Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Conditions d'utilisation** ou **Politique de confidentialité**), dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir.
Par défaut, le SDK ouvre l'URL reçue de façon native — dans un navigateur externe ou intégré à l'app, selon `action.openIn` — aucun code n'est donc nécessaire. Ne surchargez le gestionnaire que si vous souhaitez une logique personnalisée, par exemple afficher une boîte de dialogue de confirmation au préalable :
```kotlin
class MyAdaptyUIFlowsEventsObserver(
private val uriHandler: UriHandler
) : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.OpenUrlAction -> {
// Show confirmation dialog before opening URL
mainUiScope.launch {
val selectedAction = view.showDialog(
title = "Open URL?",
content = action.url,
primaryActionTitle = "Cancel",
secondaryActionTitle = "Open"
).getOrNull()
when (selectedAction) {
AdaptyUIDialogActionType.PRIMARY -> {
// User cancelled
}
AdaptyUIDialogActionType.SECONDARY -> {
// User confirmed - open URL
uriHandler.openUri(action.url)
}
else -> Unit
}
}
}
else -> Unit
}
}
}
// Set up the observer with UriHandler
AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver(uriHandler))
```
## Se connecter à l'app \{#log-into-the-app\}
Pour ajouter un bouton qui connecte les utilisateurs à votre app :
1. Dans le builder, ajoutez un bouton et assignez-lui une action **Custom** avec l'ID "login".
2. Dans le code de votre app, implémentez un gestionnaire pour l'action personnalisée qui identifie votre utilisateur.
```kotlin
class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CustomAction -> {
if (action.action == "login") {
// Handle login action - navigate to login screen
// This depends on your app's navigation system
// For example, in Compose Multiplatform:
// navController.navigate("login")
}
}
else -> Unit
}
}
}
```
## Gérer les actions personnalisées \{#handle-custom-actions\}
Pour ajouter un bouton qui gère d'autres actions :
1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID.
2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé.
Par exemple, si vous disposez d'un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre flow ou paywall :
```kotlin
class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver {
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CustomAction -> {
when (action.action) {
"openNewFlow" -> {
// Display another flow or paywall
}
}
}
else -> Unit
}
}
}
// Set up the observer
AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver())
```
:::warning
**Seuls les achats et les restaurations sont gérés automatiquement.** Toutes les autres actions de boutons, comme la fermeture des paywalls ou l'ouverture de liens, nécessitent une implémentation adaptée dans le code de l'app.
:::
Si vous créez des paywalls avec le Adapty paywall builder, il est essentiel de configurer correctement les boutons :
1. Ajoutez un [bouton dans le paywall builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé.
2. Écrivez le code dans votre app pour gérer chaque action assignée.
Ce guide explique comment gérer les actions personnalisées et prédéfinies dans votre code.
## Configurer l'AdaptyUIPaywallsEventsObserver \{#set-up-the-adaptyuipaywallseventsobserver\}
Pour gérer les actions des paywalls, vous devez implémenter l'interface `AdaptyUIPaywallsEventsObserver` et la configurer avec `AdaptyUI.setPaywallsEventsObserver()`. Cette étape doit être effectuée tôt dans le cycle de vie de votre app, généralement dans votre activité principale ou lors de l'initialisation de l'app.
```kotlin
// In your app initialization
AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver())
```
## Fermer les paywalls \{#close-paywalls\}
Pour ajouter un bouton qui fermera votre paywall :
1. Dans le paywall builder, ajoutez un bouton et assignez-lui l'action **Close**.
2. Dans le code de votre app, implémentez un gestionnaire pour l'action `close` qui ferme le paywall.
:::info
Dans le SDK Kotlin Multiplatform, `CloseAction` et `AndroidSystemBackAction` déclenchent la fermeture du paywall par défaut. Vous pouvez toutefois surcharger ce comportement dans votre code si nécessaire. Par exemple, fermer un paywall pourrait déclencher l'ouverture d'un autre.
:::
```kotlin
class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver {
override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) {
when (action) {
AdaptyUIAction.CloseAction, AdaptyUIAction.AndroidSystemBackAction -> view.dismiss()
}
}
}
// Set up the observer
AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver())
```
Si vous utilisez [`createNativePaywallView`](kmp-present-paywalls#without-compose-multiplatform), appeler `view.dismiss()` n'a aucun effet — la vue est intégrée dans votre layout et non présentée via la pile KMP. Retirez la vue de votre layout et appelez `dispose()` dessus à la place.
## Ouvrir des URLs depuis des paywalls \{#open-urls-from-paywalls\}
:::tip
Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le paywall builder et gérez-le de la même façon que les boutons avec l'action **Open URL**.
:::
Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Conditions d'utilisation** ou **Politique de confidentialité**) :
1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir.
2. Dans le code de votre app, implémentez un gestionnaire pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur.
:::info
Dans le SDK Kotlin Multiplatform, `OpenUrlAction` fournit l'URL à ouvrir. Vous pouvez implémenter une logique personnalisée pour gérer l'ouverture des URLs, par exemple en affichant une boîte de dialogue de confirmation ou en utilisant la méthode de gestion des URLs préférée de votre app.
:::
```kotlin
class MyAdaptyUIPaywallsEventsObserver(
private val uriHandler: UriHandler
) : AdaptyUIPaywallsEventsObserver {
override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.OpenUrlAction -> {
// Show confirmation dialog before opening URL
mainUiScope.launch {
val selectedAction = view.showDialog(
title = "Open URL?",
content = action.url,
primaryActionTitle = "Cancel",
secondaryActionTitle = "Open"
).getOrNull()
when (selectedAction) {
AdaptyUIDialogActionType.PRIMARY -> {
// User cancelled
}
AdaptyUIDialogActionType.SECONDARY -> {
// User confirmed - open URL
uriHandler.openUri(action.url)
}
else -> Unit
}
}
}
}
}
}
// Set up the observer with UriHandler
AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver(uriHandler))
```
## Se connecter à l'app \{#log-into-the-app\}
Pour ajouter un bouton qui connecte les utilisateurs à votre app :
1. Dans le paywall builder, ajoutez un bouton et assignez-lui une action **Custom** avec l'ID "login".
2. Dans le code de votre app, implémentez un gestionnaire pour l'action personnalisée qui identifie votre utilisateur.
```kotlin
class MyAdaptyUIObserver : AdaptyUIObserver {
override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CustomAction -> {
if (action.action == "login") {
// Handle login action - navigate to login screen
// This depends on your app's navigation system
// For example, in Compose Multiplatform:
// navController.navigate("login")
}
}
}
}
}
```
## Gérer les actions personnalisées \{#handle-custom-actions\}
Pour ajouter un bouton qui gère d'autres actions :
1. Dans le paywall builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID.
2. Dans le code de votre app, implémentez un gestionnaire pour l'ID d'action que vous avez créé.
Par exemple, si vous disposez d'un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affichera un autre paywall :
```kotlin
class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver {
override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CustomAction -> {
when (action.action) {
"login" -> {
// Handle login action - navigate to login screen
// This depends on your app's navigation system
// For example, in Compose Multiplatform:
// navController.navigate("login")
}
}
}
}
}
}
// Set up the observer
AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver())
```
---
# File: kmp-handling-events
---
---
title: "Gérer les événements de flow et de paywall - Kotlin Multiplatform"
description: "Gérez les événements de flow et de paywall dans votre application Kotlin Multiplatform."
---
:::important
Ce guide couvre la gestion des événements liés aux achats, aux restaurations, à la sélection de produits et au rendu des flows. Vous devez également implémenter la gestion des boutons (fermeture du flow, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de flow](kmp-handle-paywall-actions) pour plus de détails.
:::
Les flows et paywalls configurés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut réagir. Ces événements comprennent les pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez comment répondre à ces événements ci-dessous.
Pour contrôler ou surveiller les processus qui se déroulent sur l'écran de flow dans votre application mobile, implémentez les méthodes de l'interface `AdaptyUIFlowsEventsObserver` et enregistrez votre observateur avec `AdaptyUI.setFlowsEventsObserver()`. Certaines méthodes ont des implémentations par défaut qui gèrent automatiquement les scénarios courants, donc ne surchargez que les méthodes que vous souhaitez modifier :
```kotlin showLineNumbers title="Kotlin"
AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
// override only the methods you want to change
})
```
:::note
Ces méthodes sont l'endroit où vous ajoutez votre logique personnalisée pour répondre aux événements de flow. Vous pouvez utiliser `view.dismiss()` pour fermer le flow, ou implémenter tout autre comportement personnalisé dont vous avez besoin. Notez que `dismiss()` est une fonction suspend — à l'intérieur d'un callback, lancez-la sur le `mainUiScope` de l'observateur : `mainUiScope.launch { view.dismiss() }`.
:::
### Événements générés par l'utilisateur \{#user-generated-events\}
#### Apparition et disparition du flow \{#flow-appearance-and-disappearance\}
Lorsqu'un flow apparaît ou disparaît, ces méthodes seront invoquées :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidAppear(view: AdaptyUIFlowView) {
// Handle flow appearance
// You can track analytics or update UI here
}
override fun flowViewDidDisappear(view: AdaptyUIFlowView) {
// Handle flow disappearance
// You can track analytics or update UI here
}
```
:::note
- Sur iOS, `flowViewDidAppear` est également invoqué quand un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un flow, et qu'un paywall web s'ouvre dans un navigateur intégré.
- Sur iOS, `flowViewDidDisappear` est également invoqué quand un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un flow dans un navigateur intégré disparaît de l'écran.
:::
Exemples d'événements (cliquez pour développer)
```javascript
// Flow appeared
{
// No additional data
}
// Flow disappeared
{
// No additional data
}
```
#### Sélection de produit \{#product-selection\}
Si un utilisateur sélectionne un produit à acheter, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidSelectProduct(view: AdaptyUIFlowView, productId: String) {
// Handle product selection
// You can update UI or track analytics here
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"productId": "premium_monthly"
}
```
#### Achat démarré \{#started-purchase\}
Si un utilisateur initie le processus d'achat, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidStartPurchase(view: AdaptyUIFlowView, product: AdaptyPaywallProduct) {
// Handle purchase start
// You can show loading indicators or track analytics here
}
```
:::note
En [mode Observateur](kmp-present-flows-in-observer-mode), les achats démarrés depuis un flow sont transmis à votre `AdaptyUIObserverModeResolver` à la place.
:::
Exemple d'événement (cliquez pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
#### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\}
Si un achat se termine, cette méthode sera invoquée. Par défaut, elle ne fait rien — le flow reste ouvert après l'achat jusqu'à ce que vous le fermiez, alors appelez `view.dismiss()` vous-même dès que l'utilisateur obtient l'accès :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFinishPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
// Check if user has access to premium features
if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) {
mainUiScope.launch { view.dismiss() }
}
}
AdaptyPurchaseResult.Pending -> {
// Handle pending purchase (e.g., user will pay offline with cash)
}
AdaptyPurchaseResult.UserCanceled -> {
// Handle user cancellation
}
}
}
```
Exemples d'événements (cliquez pour développer)
```javascript
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
}
// User canceled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCanceled"
}
}
```
Nous recommandons de fermer l'écran du flow en cas d'achat réussi.
#### Achat échoué \{#failed-purchase\}
Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `flowViewDidFinishPurchase` avec un résultat annulé à la place, et les paiements en attente ne déclenchent pas cette méthode.
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFailPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
error: AdaptyError
) {
// Add your purchase failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
}
```
#### Restauration démarrée \{#started-restore\}
Si un utilisateur initie le processus de restauration, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidStartRestore(view: AdaptyUIFlowView) {
// Handle restore start
// You can show loading indicators or track analytics here
}
```
#### Restauration réussie \{#successful-restore\}
Si la restauration d'un achat réussit, cette méthode sera invoquée. Par défaut, elle ne fait rien — le flow reste ouvert après la restauration jusqu'à ce que vous le fermiez :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFinishRestore(view: AdaptyUIFlowView, profile: AdaptyProfile) {
// Add your successful restore handling logic here
// For example: show success message, update UI, or dismiss the flow
// Check if user has access to premium features
if (profile.accessLevels["premium"]?.isActive == true) {
mainUiScope.launch { view.dismiss() }
}
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}
```
Nous recommandons de fermer l'écran si l'utilisateur dispose du `accessLevel` requis. Consultez la rubrique [Statut d'abonnement](subscription-status) pour savoir comment le vérifier.
#### Restauration échouée \{#failed-restore\}
Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFailRestore(view: AdaptyUIFlowView, error: AdaptyError) {
// Add your restore failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}
```
#### Fin de la navigation de paiement web \{#web-payment-navigation-completion\}
Si un utilisateur initie le processus d'achat via un [paywall web](web-paywall), cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFinishWebPaymentNavigation(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct?,
error: AdaptyError?
) {
if (error != null) {
// Handle web payment navigation error
} else {
// Handle successful web payment navigation
}
}
```
Exemples d'événements (cliquez pour développer)
```javascript
// Successful web payment navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed web payment navigation
{
"product": null,
"error": {
"code": "web_payment_failed",
"message": "Web payment navigation failed",
"details": {
"underlyingError": "Network connection error"
}
}
}
```
### Chargement des données et rendu \{#data-fetching-and-rendering\}
#### Erreurs de chargement des produits \{#product-loading-errors\}
Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur. Si cette opération échoue, AdaptyUI signalera l'erreur en appelant cette méthode :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidFailLoadingProducts(view: AdaptyUIFlowView, error: AdaptyError) {
// Add your product loading failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}
```
#### Erreurs de rendu et d'exécution \{#rendering-and-runtime-errors\}
Si une erreur survient pendant le rendu de l'interface, ou si une autre erreur d'exécution non liée à un achat se produit, elle sera signalée par cette méthode. Par défaut, le flow est fermé en cas d'erreur — surchargez la méthode pour le maintenir ouvert ou ajouter votre propre gestion :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {
// Handle the error
// The default implementation dismisses the flow;
// once you override this method, dismissal is up to you
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "rendering_failed",
"message": "Failed to render flow interface",
"details": {
"underlyingError": "Invalid flow configuration"
}
}
}
```
Dans une situation normale, de telles erreurs ne devraient pas se produire. Si vous en rencontrez une, merci de nous en informer.
#### Événements d'analyse \{#analytics-events\}
Le callback `flowViewDidReceiveAnalyticEvent` est réservé aux événements d'analyse personnalisés d'un flow. Les flows n'émettent pas encore ces événements vers votre code, vous n'avez donc pas besoin de l'implémenter :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidReceiveAnalyticEvent(
view: AdaptyUIFlowView,
name: String,
paramsJsonString: String
) {
// Reserved for custom analytic events from a flow
}
```
### Navigation \{#navigation\}
#### Bouton retour système Android \{#android-system-back-button\}
Par défaut, un flow ne peut pas être fermé avec le bouton retour système Android ou le geste de retour — l'implémentation par défaut de `flowViewDidPerformAction` ferme le flow uniquement sur `CloseAction` et ignore `AndroidSystemBackAction`, de sorte que l'utilisateur quitte le flow via un chemin que vous définissez, comme un bouton **Fermer** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, gérez l'action vous-même :
```kotlin showLineNumbers title="Kotlin"
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction ->
mainUiScope.launch { view.dismiss() } // default behavior
is AdaptyUIAction.AndroidSystemBackAction ->
mainUiScope.launch { view.dismiss() } // not handled by default
is AdaptyUIAction.OpenUrlAction ->
AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior
else -> Unit
}
}
```
Consultez le [guide sur la gestion des actions de flow](kmp-handle-paywall-actions) pour la liste complète des actions.
Les paywalls configurés avec le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut réagir. Ces événements comprennent les pressions sur des boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats effectuées sur le paywall. Découvrez comment répondre à ces événements ci-dessous.
:::warning
Ce guide est réservé aux paywalls **du nouveau Paywall Builder** uniquement.
:::
Pour contrôler ou surveiller les processus qui se déroulent sur l'écran de paywall dans votre application mobile, implémentez les méthodes de l'interface `AdaptyUIPaywallsEventsObserver`. Certaines méthodes ont des implémentations par défaut qui gèrent automatiquement les scénarios courants.
:::note
Ces méthodes sont l'endroit où vous ajoutez votre logique personnalisée pour répondre aux événements de paywall. Vous pouvez utiliser `view.dismiss()` pour fermer le paywall, ou implémenter tout autre comportement personnalisé dont vous avez besoin.
:::
## Événements générés par l'utilisateur \{#user-generated-events\}
### Apparition et disparition du paywall \{#paywall-appearance-and-disappearance\}
Lorsqu'un paywall apparaît ou disparaît, ces méthodes seront invoquées :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidAppear(view: AdaptyUIPaywallView) {
// Handle paywall appearance
// You can track analytics or update UI here
}
override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) {
// Handle paywall disappearance
// You can track analytics or update UI here
}
```
:::note
- Sur iOS, `paywallViewDidAppear` est également invoqué quand un utilisateur appuie sur le [bouton de paywall web](web-paywall#step-2a-add-a-web-purchase-button) dans un paywall, et qu'un paywall web s'ouvre dans un navigateur intégré.
- Sur iOS, `paywallViewDidDisappear` est également invoqué quand un [paywall web](web-paywall#step-2a-add-a-web-purchase-button) ouvert depuis un paywall dans un navigateur intégré disparaît de l'écran.
:::
Exemples d'événements (cliquez pour développer)
```javascript
// Paywall appeared
{
// No additional data
}
// Paywall disappeared
{
// No additional data
}
```
### Sélection de produit \{#product-selection\}
Si un utilisateur sélectionne un produit à acheter, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) {
// Handle product selection
// You can update UI or track analytics here
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"productId": "premium_monthly"
}
```
### Achat démarré \{#started-purchase\}
Si un utilisateur initie le processus d'achat, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) {
// Handle purchase start
// You can show loading indicators or track analytics here
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\}
Si un achat réussit, cette méthode sera invoquée. Par défaut, elle ferme automatiquement le paywall sauf si l'achat a été annulé par l'utilisateur :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFinishPurchase(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
// Check if user has access to premium features
if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) {
view.dismiss()
}
}
AdaptyPurchaseResult.Pending -> {
// Handle pending purchase (e.g., user will pay offline with cash)
}
AdaptyPurchaseResult.UserCanceled -> {
// Handle user cancellation
}
}
}
```
Exemples d'événements (cliquez pour développer)
```javascript
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
}
// User canceled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCanceled"
}
}
```
Nous recommandons de fermer l'écran du paywall en cas d'achat réussi.
### Achat échoué \{#failed-purchase\}
Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs StoreKit/Google Play Billing (restrictions de paiement, produits invalides, échecs réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `paywallViewDidFinishPurchase` avec un résultat annulé à la place, et les paiements en attente ne déclenchent pas cette méthode.
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFailPurchase(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct,
error: AdaptyError
) {
// Add your purchase failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
}
```
### Restauration démarrée \{#started-restore\}
Si un utilisateur initie le processus de restauration, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidStartRestore(view: AdaptyUIPaywallView) {
// Handle restore start
// You can show loading indicators or track analytics here
}
```
### Restauration réussie \{#successful-restore\}
Si la restauration d'un achat réussit, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) {
// Add your successful restore handling logic here
// For example: show success message, update UI, or dismiss paywall
// Check if user has access to premium features
if (profile.accessLevels["premium"]?.isActive == true) {
view.dismiss()
}
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}
```
Nous recommandons de fermer l'écran si l'utilisateur dispose du `accessLevel` requis. Consultez la rubrique [Statut d'abonnement](subscription-status) pour savoir comment le vérifier.
### Restauration échouée \{#failed-restore\}
Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your restore failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}
```
### Fin de la navigation de paiement web \{#web-payment-navigation-completion\}
Si un utilisateur initie le processus d'achat via un [paywall web](web-paywall), cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFinishWebPaymentNavigation(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct?,
error: AdaptyError?
) {
if (error != null) {
// Handle web payment navigation error
} else {
// Handle successful web payment navigation
}
}
```
Exemples d'événements (cliquez pour développer)
```javascript
// Successful web payment navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed web payment navigation
{
"product": null,
"error": {
"code": "web_payment_failed",
"message": "Web payment navigation failed",
"details": {
"underlyingError": "Network connection error"
}
}
}
```
## Chargement des données et rendu \{#data-fetching-and-rendering\}
### Erreurs de chargement des produits \{#product-loading-errors\}
Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera lui-même les objets nécessaires depuis le serveur. Si cette opération échoue, AdaptyUI signalera l'erreur en appelant cette méthode :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your product loading failure handling logic here
// For example: show error message, retry option, or custom error handling
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}
```
### Erreurs de rendu \{#rendering-errors\}
Si une erreur survient pendant le rendu de l'interface, elle sera signalée par cette méthode :
```kotlin showLineNumbers title="Kotlin"
override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {
// Handle rendering error
// In a normal situation, such errors should not occur
// If you come across one, please let us know
}
```
Exemple d'événement (cliquez pour développer)
```javascript
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
}
```
Dans une situation normale, de telles erreurs ne devraient pas se produire. Si vous en rencontrez une, merci de nous en informer.
---
# File: kmp-use-fallback-paywalls
---
---
title: "Kotlin Multiplatform - Use fallback paywalls"
description: "Gérer les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles"
---
To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection.
* **If the application cannot access Adapty servers:**
It will be able to display a fallback flow or paywall, and access the local onboarding configuration.
* **If the application cannot access the internet:**
It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function.
:::important
Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty.
:::
## Configuration \{#configuration\}
1. Ajoutez le fichier de configuration de secours à votre application.
* Si votre plateforme cible est Android, déplacez le fichier de configuration de secours dans le dossier `android/app/src/main/assets/`.
* Si votre plateforme cible est iOS, ajoutez le fichier JSON de secours au bundle de votre projet. (**File** -> **Add Files to YourProjectName**)
2. Appelez la méthode `.setFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible.
3. Définissez le paramètre `assetId` en fonction de votre plateforme cible.
* Android : utilisez le chemin du fichier relatif au répertoire `assets`.
* iOS : utilisez le nom de fichier complet.
```kotlin showLineNumbers
Adapty.setFallback(assetId = "fallback.json")
.onSuccess {
// Fallback paywalls loaded successfully
}
.onError { error ->
// Handle the error
}
```
:::important
`setFallback` doit être exécuté avant que le SDK ne récupère le flow, le paywall ou l'onboarding cible.
:::
Paramètres :
| Paramètre | Description |
| :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **assetId** | Nom du fichier de configuration de secours (iOS).
Chemin du fichier de configuration de secours, relatif au répertoire `assets` (Android). |
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
---
# File: kmp-localizations-and-locale-codes
---
---
title: "Utiliser les localisations et les codes de langue dans le SDK Kotlin Multiplatform"
description: "Gérez les localisations et les codes de langue de votre application pour toucher un public mondial dans votre app Kotlin Multiplatform."
---
## 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. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prédire quelle localisation un utilisateur recevra.
## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\}
Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-étiquettes en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel).
## Correspondance des codes de langue \{#locale-code-matching\}
Dans le SDK v4, les flows et les onboardings correspondent aux 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é sous forme de 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 underscores (`_`) par des tirets (`-`), et ne revient pas au 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 [langue par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) — le SDK ne retourne pas d'erreur et ne journalise pas d'avertissement.
Lorsque le code correspond, Adapty fusionne la localisation avec la localisation par défaut : les chaînes et les ressources non définies dans la localisation correspondante sont récupérées depuis 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 se replie sur `de` que s'il n'en a pas.
:::warning
Transmettez 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 transmettez pas un identifiant de locale de plateforme tel quel : sur Android, `Locale.getDefault().toLanguageTag()` retourne `pt-BR` ; sur iOS, `NSLocale.currentLocale.localeIdentifier` retourne `pt_BR`. Les deux basculent vers la localisation par défaut. Convertissez la valeur dans votre application avant de la transmettre.
:::
### 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`](kmp-get-onboardings) :
1. La chaîne locale est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`)
2. Adapty recherche la localisation dont le code correspond exactement à la locale
3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante
4. Si aucune correspondance n'est à nouveau 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émentation des localisations \{#implementing-localizations\}
Dans le SDK v4, vous ne passez pas de code de langue lors de la récupération d'un flow — `getFlow` renvoie le flow avec toutes ses localisations, et Adapty en applique une lors de la construction de la vue du flow.
- **Flows créés dans le builder** : le SDK ne lit pas la langue de l'appareil, vous devez donc la résoudre dans votre application et la passer en tant que paramètre `locale` de `createFlowView`. Ce paramètre est facultatif — si vous l'omettez, le flow s'affiche en `en`, ou dans sa [langue par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow ne possède pas de localisation `en`.
```kotlin showLineNumbers
import com.adapty.kmp.AdaptyUI
AdaptyUI.createFlowView(flow = flow, locale = "es")
.onSuccess { view ->
view.present()
}
.onError { error ->
// handle the error
}
```
`createNativeFlowView` et le composable `AdaptyUIFlowPlatformView` acceptent le même paramètre optionnel `locale`. `view.locale` indique la localisation avec laquelle la vue a été construite. Le paramètre `locale` et `view.locale` nécessitent le SDK Kotlin Multiplatform 4.0.1-beta.1 ou une version ultérieure.
- **Paywalls personnalisés (Remote Config)** : `getFlow` renvoie toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée est un `AdaptyRemoteConfig` avec un code `locale` et un `dataMap`. Sélectionnez l'entrée correspondant à l'utilisateur, avec votre propre mécanisme de secours :
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID")
.onSuccess { flow ->
val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
?: flow.remoteConfigs.firstOrNull()
// read your values from config?.dataMap
}
.onError { error ->
// handle the error
}
```
Adapty stocke ces codes `locale` dans le format décrit dans [Standard des codes de locale chez Adapty](#locale-code-standard-at-adapty). Le SDK ne fait pas correspondre les Remote Configs à une locale, c'est donc à votre application de déterminer quelle entrée appliquer.
## Pourquoi c'est important \{#why-this-is-important\}
Les codes de locale entrent en jeu dans plusieurs situations — par exemple, lorsque vous souhaitez récupérer le bon paywall pour la localisation actuelle de votre application.
Les codes de locale sont complexes et peuvent varier d'une plateforme à l'autre. C'est pourquoi nous nous appuyons sur un standard interne pour toutes les plateformes que nous supportons. Mais justement parce que ces codes sont complexes, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin de toujours recevoir ce que vous attendez.
## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\}
Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-balises en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel).
## Correspondance des codes de langue \{#locale-code-matching\}
Lorsqu'Adapty reçoit un appel du SDK avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe :
1. La chaîne de langue reçue est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`)
2. On recherche ensuite la localisation dont le code de langue correspond exactement
3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante
4. Si aucune correspondance n'est encore trouvée, on renvoie le contenu dans la langue par défaut du paywall
De cette façon, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat.
## Mise en œuvre des localisations : méthode recommandée \{#implementing-localizations-recommended-way\}
Si vous vous posez des questions sur les localisations, il y a de bonnes chances que vous gériez déjà des ressources de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de ressources. Vous n'aurez alors qu'à extraire la valeur de cette clé lors de l'appel au SDK, comme ceci :
```kotlin showLineNumbers
// 1. Add the Adapty locale code to your Compose Multiplatform resources
/*
composeResources/values/strings.xml (default — English)
*/
en
/*
composeResources/values-es/strings.xml (Spanish)
*/
es
/*
composeResources/values-pt-rBR/strings.xml (Portuguese — Brazil)
*/
pt-br
// 2. Extract and use the locale code
suspend fun fetchPaywall() {
val locale = getString(Res.string.adapty_paywalls_locale)
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = locale
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
}
```
De cette façon, vous gardez un contrôle total sur la localisation récupérée pour chaque utilisateur de votre application.
Si vous n'utilisez pas les ressources Compose Multiplatform, la même idée s'applique à toute bibliothèque de localisation que vous utilisez (par exemple, [moko-resources](https://github.com/icerockdev/moko-resources)) — stockez le code de locale Adapty sous forme de chaîne dans le bundle de ressources de chaque locale et lisez-le avant d'appeler le SDK.
## Implémenter les localisations : l'autre approche \{#implementing-localizations-the-other-way\}
Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de langue pour chaque localisation. Cela revient à extraire un code de langue directement depuis l'appareil — ce qui nécessite des déclarations `expect`/`actual`, puisqu'il n'existe pas d'API de locale partagée dans `commonMain` :
```kotlin showLineNumbers
// commonMain
expect fun currentLocaleTag(): String
// androidMain
actual fun currentLocaleTag(): String = Locale.getDefault().toLanguageTag()
// iosMain
actual fun currentLocaleTag(): String = NSLocale.currentLocale.localeIdentifier
// commonMain — pass the locale code to Adapty
suspend fun fetchPaywall() {
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = currentLocaleTag()
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
}
```
Notez que nous ne recommandons pas cette approche pour plusieurs raisons :
1. Sur iOS, la langue préférée de l'utilisateur et la langue régionale de l'appareil ne sont pas identiques. `NSLocale.currentLocale.localeIdentifier` renvoie la langue régionale, qui peut différer de la langue dans laquelle les utilisateurs lisent réellement votre application. Les apps iOS qui utilisent des fichiers de chaînes localisées s'appuient sur la logique de résolution d'Apple pour combiner les deux — ce qui fonctionne directement avec l'approche recommandée ci-dessus.
2. Il est difficile de prédire exactement ce que renverra l'appareil et si cela correspond à une localisation Adapty. La langue régionale de l'appareil peut inclure des extensions ou des codes régionaux que vous n'avez pas configurés dans Adapty, auquel cas le SDK revient à la correspondance sur le premier sous-tag ou, en dernier recours, à `en`.
Should you decide to use this approach anyway — make sure you've covered all the relevant use cases.
---
# File: kmp-web-paywalls
---
---
title: "Implémenter des web paywalls dans le SDK Kotlin Multiplatform"
description: "Configurez un web paywall pour être payé sans les frais et les audits du store."
---
:::important
Avant de commencer, assurez-vous d'avoir [configuré votre web paywall dans le tableau de bord](web-paywall) et d'avoir installé la version 3.15 ou ultérieure du SDK Adapty.
:::
## Ouvrir des web paywalls \{#open-web-paywalls\}
Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les web paywalls via la méthode SDK. La méthode `openWebPaywall` :
1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé.
2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `getProfile` à intervalles courts pour déterminer si les droits d'accès du profil ont été mis à jour.
Ainsi, si le paiement a été effectué avec succès et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement.
:::note
Après que les utilisateurs reviennent dans l'application, actualisez l'interface pour refléter les mises à jour du profil. Adapty recevra et traitera les événements de mise à jour du profil.
:::
```kotlin showLineNumbers
viewModelScope.launch {
Adapty.openWebPaywall(product = product).onSuccess {
// the web paywall was opened successfully
}.onError { error ->
// handle the error
}
}
```
:::note
Il existe deux versions de la méthode `openWebPaywall` :
1. `openWebPaywall(product = product)` qui génère des URL par paywall et ajoute également les données du produit aux URL.
2. `openWebPaywall(paywall = paywall)` qui génère des URL par paywall sans ajouter les données du produit aux URL. Utilisez-la lorsque vos produits dans le paywall Adapty diffèrent de ceux du web paywall.
Dans le SDK v4, le paramètre `paywall` est remplacé par un paramètre `flowPaywall` qui prend un `AdaptyFlowPaywall` — l'une des variantes de paywall dans `flow.paywalls`. Consultez le [guide de migration](migration-to-kmp-sdk-v4).
:::
## Ouvrir des web paywalls dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\}
Par défaut, les web paywalls s'ouvrent dans le navigateur externe.
Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les web paywalls dans un navigateur intégré à l'application. Cela affiche la page d'achat web au sein de votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application.
Pour activer cela, définissez le paramètre `openIn` sur `AdaptyWebPresentation.IN_APP_BROWSER` :
```kotlin showLineNumbers
viewModelScope.launch {
Adapty.openWebPaywall(
product = product,
openIn = AdaptyWebPresentation.IN_APP_BROWSER // default – EXTERNAL_BROWSER
).onSuccess {
// the web paywall was opened successfully
}.onError { error ->
// handle the error
}
}
```
---
# File: kmp-present-flows-in-observer-mode
---
---
title: "Présenter les flows en mode Observer - Kotlin Multiplatform"
description: "Présentez des flows et des paywalls Paywall Builder en mode Observer dans votre application Kotlin Multiplatform tout en gérant les achats avec votre propre code."
---
Si vous avez personnalisé un flow ou un paywall avec le builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment il doit l'être.
:::warning
Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez la rubrique [Afficher les flows et paywalls](kmp-present-paywalls).
:::
:::info
Cette fonctionnalité nécessite le SDK Adapty Kotlin Multiplatform 4.0 (beta) ou une version ultérieure — elle n'était auparavant disponible que dans les SDK natifs iOS et Android. Consultez le [guide de migration](migration-to-kmp-sdk-v4) pour effectuer la mise à niveau.
:::
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 d'appeler `withObserverMode(true)` dans le builder de configuration. Consultez le [guide d'installation du SDK Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk).
3. [Créez des produits](create-product) dans l'Adapty Dashboard.
4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et associez-leur des produits.
5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement).
6. [Récupérez les flows et leur configuration](kmp-get-pb-paywalls) dans le code de votre application.
En mode Observer, le SDK n'effectue pas les achats à votre place. Lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration dans un flow ou paywall rendu par Adapty, le SDK appelle votre `AdaptyUIObserverModeResolver` à la place — effectuez l'achat ou la restauration avec votre propre code à cet endroit.
1. Implémentez l'interface `AdaptyUIObserverModeResolver` :
```kotlin showLineNumbers
import com.adapty.kmp.AdaptyUIObserverModeResolver
import com.adapty.kmp.models.AdaptyPaywallProduct
import com.adapty.kmp.models.AdaptyUIFlowView
class MyObserverModeResolver : AdaptyUIObserverModeResolver {
override fun observerModeDidInitiatePurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
onStartPurchase: () -> Unit,
onFinishPurchase: () -> Unit
) {
onStartPurchase() // the view shows its loading indicator
// make the purchase with your own code,
// then report the transaction to Adapty and call:
onFinishPurchase() // the view hides the loading indicator
}
override fun observerModeDidInitiateRestore(
view: AdaptyUIFlowView,
onStartRestore: () -> Unit,
onFinishRestore: () -> Unit
) {
onStartRestore()
// restore purchases with your own code, then:
onFinishRestore()
}
}
```
La méthode `observerModeDidInitiatePurchase` vous informe que l'utilisateur a initié un achat, et `observerModeDidInitiateRestore` — que l'utilisateur a initié une restauration. Déclenchez votre flow d'achat ou de restauration personnalisé en réponse.
N'oubliez pas non plus d'invoquer les callbacks suivants pour notifier AdaptyUI de l'avancement de l'achat ou de la restauration. Cela est nécessaire pour le bon fonctionnement du flow, notamment l'affichage du chargement :
| Callback | Description |
| :----------------- | :--------------------------------------------------------------------------------------------- |
| onStartPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. |
| onFinishPurchase() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. |
| onStartRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration a démarré. |
| onFinishRestore() | Ce callback doit être invoqué pour notifier AdaptyUI que la restauration est terminée. |
Le flow reste ouvert pendant l'exécution de votre code — fermez-le vous-même après un achat ou une restauration réussi.
2. Enregistrez le resolver avant d'afficher un écran :
```kotlin showLineNumbers
import com.adapty.kmp.AdaptyUI
AdaptyUI.setObserverModeResolver(MyObserverModeResolver())
```
Sans resolver enregistré, la vue du flow n'a aucun moyen de transmettre l'achat à votre code, et rien ne se passe lorsque l'utilisateur appuie sur le bouton d'achat.
3. Créez et présentez la vue du flow comme d'habitude : [récupérez le flow et créez sa vue](kmp-get-pb-paywalls), puis [présentez-la](kmp-present-paywalls). Aucun paramètre supplémentaire n'est nécessaire — une fois le resolver enregistré, chaque flow ou paywall rendu par Adapty achemine les achats et les restaurations à travers lui.
:::warning
N'oubliez pas de [signaler la transaction et de l'associer au paywall](report-transactions-observer-mode-kmp). Sinon, Adapty ne reconnaîtra pas la transaction et ne pourra pas déterminer le paywall source de l'achat.
:::
---
# File: kmp-troubleshoot-paywall-builder
---
---
title: "Résoudre les problèmes du Paywall Builder dans le SDK Kotlin Multiplatform"
description: "Résoudre les problèmes du Paywall Builder dans le SDK Kotlin Multiplatform"
---
Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK Kotlin Multiplatform.
## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\}
**Problème** : La méthode `createPaywallView` ne parvient pas à créer une vue de paywall, ou le paywall n'a pas de configuration de vue.
**Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder.
**Solution** : Activez le bouton **Show on device** dans le Paywall Builder. Vous pouvez également vérifier si un paywall possède une configuration de vue en utilisant la propriété `hasViewConfiguration` sur l'objet `AdaptyPaywall`.
## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\}
**Problème** : Le nombre de vues du paywall affiche le double du nombre attendu.
**Cause** : Vous appelez peut-être `logShowFlow` (SDK v4+) / `logShowPaywall` dans votre code, ce qui duplique le nombre de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls créés avec ces outils, les statistiques sont suivies automatiquement, vous n'avez donc pas besoin d'utiliser cette méthode.
**Solution** : Assurez-vous de ne pas appeler `logShowFlow` (SDK v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder.
---
# File: kmp-implement-paywalls-manually
---
---
title: "Implémenter les paywalls manuellement dans le SDK Kotlin Multiplatform"
description: "Découvrez comment implémenter les paywalls manuellement dans votre application Kotlin Multiplatform avec le SDK Adapty."
---
## Accepter les achats \{#accept-purchases\}
Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty via la méthode `makePurchase`. Ainsi, nous gérons tous les scénarios utilisateur et vous n'avez qu'à traiter les résultats des achats.
:::important
`makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Veillez à configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart).
:::
## Mode observateur \{#observer-mode\}
Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, tout en profitant de l'analytique avancée d'Adapty, vous pouvez utiliser le mode observateur.
:::important
Consultez les limitations du mode observateur [ici](observer-vs-full-mode).
:::
---
# File: kmp-quickstart-manual
---
---
title: "Activer les achats dans votre paywall personnalisé avec le SDK Kotlin Multiplatform"
description: "Intégrez le SDK Adapty dans vos paywalls Kotlin Multiplatform personnalisés pour activer les achats intégrés."
---
Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, tandis que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les précédents. Ce guide utilise les APIs du SDK Adapty Kotlin Multiplatform v4 (bêta) — si vous utilisez la v3, consultez le [guide de migration](migration-to-kmp-sdk-v4) pour les noms de méthodes correspondants.
:::important
**Ce guide est destiné aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la méthode la plus simple pour activer les achats, utilisez l'[Adapty Flow Builder](kmp-quickstart-paywalls). Avec le Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différentes conceptions sans republier votre application.
:::
## Avant de commencer \{#before-you-start\}
### Configurer les produits \{#set-up-products\}
Pour activer les achats intégrés, vous devez comprendre trois concepts clés :
- [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie)
- [**Paywalls**](paywalls) – des configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application. Dans le SDK v4, les variations de paywall pour un placement sont portées par un objet **flow** — vous récupérez un flow et interrogez ses produits.
- [**Placements**](placements) – où et quand vous affichez des paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez des paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de paywalls différents à différents utilisateurs.
Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. En résumé, ce sont simplement votre façon de gérer les produits que vous vendez dans votre application.
Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart).
### Gérer les utilisateurs \{#manage-users\}
Vous pouvez travailler avec ou sans authentification backend de votre côté.
Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](kmp-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs.
## Étape 1. Obtenir les produits \{#step-1-get-products\}
Pour récupérer les produits de votre paywall personnalisé, vous devez :
1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`.
2. Obtenir le tableau de produits pour ce flow à l'aide de la méthode `getPaywallProducts`.
```kotlin showLineNumbers
fun loadPaywall() {
Adapty.getFlow(placementId = "YOUR_PLACEMENT_ID")
.onSuccess { flow ->
Adapty.getPaywallProducts(flow = flow)
.onSuccess { products ->
// Use products to build your custom paywall UI
}
.onError { error ->
// Handle the error
}
}
.onError { error ->
// Handle the error
}
}
```
## Étape 2. Accepter les achats \{#step-2-accept-purchases\}
Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour.
```kotlin showLineNumbers
fun purchaseProduct(product: AdaptyPaywallProduct) {
Adapty.makePurchase(product = product)
.onSuccess { purchaseResult ->
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
// Purchase successful, profile updated
}
is AdaptyPurchaseResult.UserCanceled -> {
// User canceled the purchase
}
is AdaptyPurchaseResult.Pending -> {
// Purchase is pending (e.g., user will pay offline with cash)
}
}
}
.onError { error ->
// Handle the error
}
}
```
## Étape 3. Restaurer les achats \{#step-3-restore-purchases\}
Les stores d'applications exigent que toutes les applications avec des abonnements fournissent un moyen aux utilisateurs de restaurer leurs achats.
Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera leur historique d'achats avec Adapty et retournera le profil mis à jour.
```kotlin showLineNumbers
fun restorePurchases() {
Adapty.restorePurchases()
.onSuccess { profile ->
// Restore successful, profile updated
}
.onError { error ->
// Handle the error
}
}
```
## Étape 4. Vérifier le statut de l'abonnement \{#step-4-check-the-subscription-status\}
Après un achat ou une restauration, vérifiez le [niveau d'accès](access-level) de l'utilisateur pour décider d'afficher le paywall ou de débloquer les fonctionnalités payantes. Les méthodes `makePurchase` et `restorePurchases` retournent déjà le profil mis à jour ; lorsque vous avez besoin du statut actuel ailleurs dans l'application, utilisez la méthode `getProfile` :
```kotlin showLineNumbers
fun checkPremiumAccess() {
Adapty.getProfile()
.onSuccess { profile ->
val hasPremiumAccess = profile.accessLevels["premium"]?.isActive == true
// Grant access to paid features if hasPremiumAccess is true
}
.onError { error ->
// Handle the error
}
}
```
Pour d'autres façons de vérifier et surveiller le statut de l'abonnement, notamment en écoutant les mises à jour en temps réel, consultez [Vérifier le statut de l'abonnement](kmp-check-subscription-status).
## Prochaines étapes \{#next-steps\}
:::tip
Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider !
:::
Votre paywall est prêt à être affiché dans l'application. Testez vos achats dans le [sandbox App Store](test-purchases-in-sandbox) ou dans le [Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez [AppViewModel.kt](https://github.com/adaptyteam/AdaptySDK-KMP/blob/main/example/composeMultiplatformApp/composeApp/src/commonMain/kotlin/com/adapty/exampleapp/AppViewModel.kt) dans notre exemple d'application, qui illustre la gestion des achats avec une gestion des erreurs et une gestion d'état appropriées.
---
# File: fetch-paywalls-and-products-kmp
---
---
title: "Récupérer les paywalls et produits pour les paywalls Remote Config dans le SDK Kotlin Multiplatform"
description: "Récupérez les paywalls et produits dans le SDK Adapty Kotlin Multiplatform pour améliorer la monétisation des utilisateurs."
---
Avant de présenter le Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique porte sur le Remote Config et les paywalls personnalisés. Pour savoir comment récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez-y votre flow ou paywall](create-placement) dans l'Adapty Dashboard.
4. [Installez le SDK Adapty](sdk-installation-kotlin-multiplatform) 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 cross-platform sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter à des emplacements spécifiques de votre application mobile.
Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) avec la méthode `getFlow`.
:::important
**Ne codez pas les IDs de produits en dur.** Le seul ID à coder en dur est l'ID de placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un flow renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code.
:::
```kotlin showLineNumbers
Adapty.getFlow(
placementId = "YOUR_PLACEMENT_ID",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { flow ->
// the requested flow
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. |
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | 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 `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne disposeront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou d'un nettoyage manuel.
Le SDK Adapty stocke les flows et les paywalls sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](kmp-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant au cas où le CDN serait inaccessible. Ce système est conçu pour garantir que vous disposez toujours de la dernière version de vos flows et paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **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 indiqué dans `loadTimeout`, car l'opération peut comprendre différentes requêtes en arrière-plan.
|
Ne codez pas en dur les identifiants de produits ! Étant donné que les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios.
Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modifications du code. La seule chose que vous devez coder en dur est l'identifiant du placement.
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Flow | Un objet `AdaptyFlow` contenant : l'identifiant du flow, les variantes de paywall (`paywalls` — chacune avec ses propres identifiants de produits), une liste `remoteConfigs` (une entrée par locale configurée), ainsi que plusieurs autres propriétés. Pour récupérer les produits du flow, appelez `getPaywallProducts(flow)`. |
:::note
Dans la v4, `getFlow` n'a pas de paramètre `locale`. Lorsque vous affichez un flow avec `createFlowView`, la localisation est résolue automatiquement. Pour les paywalls personnalisés, toutes les localisations disponibles sont retournées ensemble dans `flow.remoteConfigs` — choisissez celle qui correspond à la langue de l'appareil ou aux paramètres de votre application. Consultez [Localisations et codes de langue](kmp-localizations-and-locale-codes) pour plus de détails.
:::
## Récupérer les produits \{#fetch-products\}
Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond :
```kotlin showLineNumbers
Adapty.getPaywallProducts(flow).onSuccess { products ->
// the requested products
}.onError { error ->
// handle the error
}
```
Paramètres de la réponse :
| Paramètre | Description |
| :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Products | Liste d'objets [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) contenant : identifiant du produit, nom du produit, prix, devise, durée de l'abonnement et plusieurs autres propriétés. |
Lorsque vous implémentez votre propre design de flow, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles.
| Propriété | Description |
|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. |
| **Price** | Pour afficher le prix dans un format localisé, utilisez `product.price.localizedString`. Cette localisation est basée sur la locale de l'appareil. Vous pouvez également accéder au prix sous forme numérique via `product.price.amount`. La valeur est fournie dans la devise locale. Pour obtenir le symbole de devise correspondant, utilisez `product.price.currencySymbol`. |
| **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement de manière programmatique, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. |
| **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.
• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, la 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 d'offre avec cette propriété. Son fonctionnement est identique à celui décrit dans la section précédente pour les abonnements.
• `localizedSubscriptionPeriod` : la période d'abonnement de la remise formatée pour la locale de l'utilisateur. |
## Accélérer la récupération du flow avec un flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\}
En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous inquiéter de cette étape. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout.
Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-kmp#fetch-flow-information) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getFlow`
La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs :
- **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (version actuelle et futures), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version rencontrent des problèmes avec des flows non rendus.
- **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon le pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur la méthode `getFlow` décrite [ci-dessus](fetch-paywalls-and-products-kmp#fetch-flow-information).
:::
```kotlin showLineNumbers
Adapty.getFlowForDefaultAudience(
placementId = "YOUR_PLACEMENT_ID",
fetchPolicy = AdaptyPaywallFetchPolicy.Default
).onSuccess { flow ->
// the requested flow
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs ne bénéficieront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc tout à fait sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau inutiles.
Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.
|
Avant de présenter les Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que ce sujet concerne les Remote Config et les paywalls personnalisés. Pour obtenir des instructions sur la récupération des paywalls créés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](kmp-get-pb-paywalls).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
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-kotlin-multiplatform) 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 cross-platform sont intégrés dans des paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile.
Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`.
:::important
**N'inscrivez pas les IDs de produits en dur dans le code.** Le seul ID à coder en dur est l'ID de placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code.
:::
```kotlin showLineNumbers
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **locale** | 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.
|
| **fetchPolicy** | par défaut : `AdaptyPaywallFetchPolicy.Default` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs ne bénéficieront peut-être pas des toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session afin d'éviter des requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](kmp-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système est conçu pour garantir que vous recevez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan.
|
Ne codez pas les identifiants de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer au fil du temps. Assurez-vous que votre code gère ces scénarios.
Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à coder en dur est l'identifiant de placement.
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Paywall | Un objet [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) contenant : une liste d'identifiants de produit, l'identifiant du paywall, le Remote Config, et plusieurs autres propriétés. |
## Récupérer les produits \{#fetch-products\}
Une fois que vous avez le paywall, vous pouvez interroger le tableau de produits qui lui correspond :
```kotlin showLineNumbers
Adapty.getPaywallProducts(paywall).onSuccess { products ->
// the requested products
}.onError { error ->
// handle the error
}
```
Paramètres de la réponse :
| Paramètre | Description |
| :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Products | Liste d'objets [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) contenant : l'identifiant du produit, son nom, son prix, la devise, la durée de l'abonnement et plusieurs autres propriétés. |
Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés depuis l'objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont présentées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles.
| Propriété | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil lui-même. |
| **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. Cette localisation est basée sur les informations de locale de l'appareil. Vous pouvez aussi accéder au prix sous forme numérique via `product.price.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de la devise associée, utilisez `product.price.currencySymbol`. |
| **Subscription Period** | Pour afficher la période (par exemple : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. Cette localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement de manière programmatique, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (c'est-à-dire DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donne le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. |
| **Introductory Offer** | Pour afficher un badge ou tout autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits sont du type `FREE_TRIAL`.
• `price` : le prix remisé sous forme numérique. Pour les essais gratuits, la 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 d'offre grâce à cette propriété. Elle fonctionne de la même façon pour les offres que ce qui est décrit dans la section précédente.
• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la locale de l'utilisateur. |
## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\}
En général, les paywalls sont récupérés presque instantanément, donc vous n'avez pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de n'afficher aucun paywall.
Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme expliqué dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-kmp#fetch-paywall-information) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getPaywall`
La méthode `getPaywallForDefaultAudience` présente quelques inconvénients importants :
- **Problèmes potentiels de compatibilité ascendante** : si vous avez besoin d'afficher des paywalls différents selon les versions de l'application (version actuelle et versions futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés.
- **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous êtes prêt à accepter ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur la méthode `getPaywall` décrite [plus haut](fetch-paywalls-and-products-kmp#fetch-paywall-information).
:::
```kotlin showLineNumbers
Adapty.getPaywallForDefaultAudience(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **locale** | 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 désigne la langue, le second la région.
Exemple : `en` correspond à l'anglais, `pt-br` représente le portugais brésilien.
|
| **fetchPolicy** | défaut : `AdaptyPaywallFetchPolicy.Default` | 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 vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser sans risque durant la session pour éviter les requêtes réseau.
Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.
|
---
# File: present-remote-config-paywalls-kmp
---
---
title: "Afficher un paywall conçu via Remote Config dans le SDK Kotlin Multiplatform"
description: "Découvrez comment présenter les paywalls Remote Config dans le SDK Adapty Kotlin Multiplatform pour personnaliser l'expérience utilisateur."
---
Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé.
## Récupérer le Remote Config d'un flow et l'afficher \{#get-flow-remote-config-and-present-it\}
Dans la v4, un flow contient une entrée `AdaptyRemoteConfig` par locale configurée dans la liste `remoteConfigs`. Sélectionnez la locale correspondant à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin.
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID")
.onSuccess { flow ->
val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
?: flow.remoteConfigs.firstOrNull()
val headerText = config?.dataMap?.get("header_text") as? String
// use the remote config values
}
.onError { error ->
// handle the error
}
```
À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler pour créer une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils.
:::warning
Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-kmp#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B.
:::
Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](kmp-making-purchases).
Nous recommandons de [créer un paywall de secours appelé fallback paywall](kmp-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion Internet ou de cache disponible, garantissant une expérience fluide même dans ces situations.
## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\}
Adapty vous aide à mesurer les performances de vos flows et paywalls. Si nous collectons automatiquement les données sur les achats, l'enregistrement des vues nécessite votre intervention, car vous seul savez quand un utilisateur voit un flow.
Pour enregistrer un événement de vue, appelez simplement `.logShowFlow(flow)` : il apparaîtra dans vos métriques dans les entonnoirs et les tests A/B.
:::important
Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les vues automatiquement dans ces cas.
:::
```kotlin showLineNumbers
Adapty.logShowFlow(flow)
.onSuccess {
// flow view logged successfully
}
.onError { error ->
// handle the error
}
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :-------- | :-------- |:-----------------------------------------------------------------|
| **flow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. |
Si vous avez personnalisé un paywall via Remote Config, vous devrez implémenter son rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, c'est vous qui décidez de ce qui est inclus et de l'apparence de votre paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous laissant toute liberté pour présenter votre paywall personnalisé configuré via Remote Config.
## Récupérer le Remote Config d'un paywall et l'afficher \{#get-paywall-remote-config-and-present-it\}
Pour obtenir le Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires.
```kotlin showLineNumbers
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { paywall ->
val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String
// use the remote config values
}.onError { error ->
// handle the error
}
```
À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler pour créer une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des téléphones mobiles, afin d'offrir une expérience fluide et agréable sur tous les appareils.
:::warning
Pensez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-kmp#track-paywall-view-events-1) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les entonnoirs et les tests A/B.
:::
Une fois l'affichage du paywall terminé, passez à la configuration du flux d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour en savoir plus sur la méthode `.makePurchase()`, consultez [Effectuer des achats](kmp-making-purchases).
Nous recommandons de [créer un paywall de secours appelé fallback paywall](kmp-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion Internet ou de cache disponible, garantissant une expérience fluide même dans ces situations.
## Suivre les événements d'affichage du paywall \{#track-paywall-view-events-1\}
Adapty vous aide à mesurer les performances de vos paywalls. Si nous collectons automatiquement les données sur les achats, l'enregistrement des vues de paywall nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall.
Pour enregistrer un événement de vue de paywall, appelez simplement `.logShowPaywall(paywall)` : il apparaîtra dans vos métriques de paywall dans les entonnoirs et les tests A/B.
:::important
Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder).
:::
```kotlin showLineNumbers
Adapty.logShowPaywall(paywall = paywall)
.onSuccess {
// paywall view logged successfully
}
.onError { error ->
// handle the error
}
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :---------- | :-------- |:-------------------------------------------------------------------------------------------------------|
| **paywall** | requis | Un objet [`AdaptyPaywall`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). |
---
# File: kmp-making-purchases
---
---
title: "Effectuer des achats dans une application mobile avec le SDK Kotlin Multiplatform"
description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty."
---
Afficher des paywalls dans votre application mobile est une étape essentielle pour proposer aux utilisateurs l'accès à des contenus ou services premium. Cependant, les présenter suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour personnaliser vos paywalls.
Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode distincte appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode constitue le point d'entrée pour que les utilisateurs interagissent avec les paywalls et procèdent à leurs transactions.
Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat.
:::warning
Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder.
Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de la publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs éligibles à une offre de lancement.
:::
Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans cela, nous ne pouvons pas valider les achats.
## Effectuer un achat \{#make-purchase\}
:::note
**Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape.
**Vous cherchez des instructions pas à pas ?** Consultez le [guide de démarrage rapide](kmp-implement-paywalls-manually) pour une implémentation complète avec tout le contexte nécessaire.
:::
```kotlin showLineNumbers
Adapty.makePurchase(product = product).onSuccess { purchaseResult ->
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
// Grant access to the paid features
}
}
is AdaptyPurchaseResult.UserCanceled -> {
// Handle the case where the user canceled the purchase
}
is AdaptyPurchaseResult.Pending -> {
// Handle deferred purchases (e.g., the user will pay offline with cash)
}
}
}.onError { error ->
// Handle the error
}
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :---------- | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------|
| **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) récupéré depuis le paywall. |
Paramètres de la réponse :
| Paramètre | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Profile** | Si la requête a abouti, la réponse contient cet objet. Un objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur au sein de l'application.
Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose des droits d'accès requis.
|
:::warning
**Remarque :** si vous utilisez encore la version StoreKit d'Apple inférieure à la v2.0 et une version du SDK Adapty inférieure à la v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple.
:::
## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\}
Lorsqu'un utilisateur opte pour un nouvel abonnement plutôt que de renouveler son abonnement actuel, le comportement dépend du store. Sur Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous.
Pour remplacer l'abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire :
```kotlin showLineNumbers
val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters(
oldSubVendorProductId = "old_subscription_product_id",
replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE
)
val purchaseParams = AdaptyPurchaseParameters.Builder()
.setSubscriptionUpdateParams(subscriptionUpdateParams)
.build()
Adapty.makePurchase(
product = product,
parameters = purchaseParams
).onSuccess { purchaseResult ->
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
// successful cross-grade
}
is AdaptyPurchaseResult.UserCanceled -> {
// user canceled the purchase flow
}
is AdaptyPurchaseResult.Pending -> {
// the purchase has not been finished yet, e.g. user will pay offline by cash
}
}
}.onError { error ->
// Handle the error
}
```
Paramètre de requête supplémentaire :
| Paramètre | Présence | Description |
|:---------------|:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **parameters** | optionnel | un objet [`AdaptyAndroidSubscriptionUpdateParameters`](https://kmp.adapty.io/////adapty/com.adapty.kmp.models/-adapty-android-subscription-update-parameters/) transmis via [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). |
Vous pouvez en savoir plus sur les abonnements et les modes de remplacement dans la documentation Google Developer :
- [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes)
- [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations)
- Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge.
- Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation de l'abonnement actuel.
## Utiliser des codes promotionnels sur iOS \{#redeem-offer-codes-in-ios\}
À 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 dans votre application :
```kotlin showLineNumbers
Adapty.presentCodeRedemptionSheet()
.onSuccess {
// code redemption sheet presented successfully
}
.onError { error ->
// handle the error
}
```
:::danger
D'après nos observations, la feuille de saisie de code promotionnel peut ne pas fonctionner de manière fiable dans certaines applications. Nous recommandons de rediriger l'utilisateur directement vers l'App Store.
Pour ce faire, vous devez ouvrir une URL au format suivant :
`https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}`
:::
## Gérer les forfaits prépayés (Android) \{#manage-prepaid-plans-android\}
Si les utilisateurs de votre application peuvent acheter des [forfaits prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, acheter un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour ces forfaits.
```kotlin showLineNumbers
Adapty.activate(
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withGoogleEnablePendingPrepaidPlans(true)
.build()
).onSuccess {
// successful activation
}.onError { error ->
// handle the error
}
```
---
# File: kmp-restore-purchase
---
---
title: "Restaurer les achats dans une application mobile avec le SDK Kotlin Multiplatform"
description: "Découvrez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide."
---
La restauration des achats est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés, comme des abonnements ou des achats intégrés, sans être facturés à nouveau. Cette fonctionnalité est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent accéder à leurs achats antérieurs sans payer à nouveau.
:::note
Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape.
:::
Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder) pour personnaliser le paywall, appelez la méthode `.restorePurchases()` :
```kotlin showLineNumbers
Adapty.restorePurchases().onSuccess { profile ->
if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
// successful access restore
}
}.onError { error ->
// handle the error
}
```
Paramètres de réponse :
| Paramètre | Description |
|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Profile** | Un objet [`AdaptyProfile`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-profile/). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.
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-kmp
---
---
title: "Implémenter le mode Observateur dans le SDK Kotlin Multiplatform"
description: "Implémentez le mode Observateur dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Kotlin Multiplatform."
---
Si vous disposez déjà de votre propre infrastructure d'achats et que vous n'êtes pas prêt à basculer complètement vers Adapty, vous pouvez explorer le [mode Observateur](observer-vs-full-mode). Dans sa forme de base, le mode Observateur offre des analyses avancées et une intégration fluide avec les systèmes d'attribution et d'analytique.
Si cela répond à vos besoins, il vous suffit de :
1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` à `true`. Suivez les instructions de configuration pour [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform).
2. [Signaler les transactions](report-transactions-observer-mode-kmp) depuis votre infrastructure d'achats existante à Adapty.
:::tip
Dans la version 4 du SDK, vous pouvez également présenter des flows et des paywalls rendus par Adapty en mode Observateur : lorsqu'un utilisateur appuie sur le bouton d'achat ou de restauration, le SDK transmet l'action à votre code afin que vous puissiez effectuer l'achat ou la restauration vous-même. Consultez [Présenter des flows en mode Observateur](kmp-present-flows-in-observer-mode).
:::
## Configuration du mode Observateur \{#observer-mode-setup\}
Activez le mode Observateur si vous gérez vous-même les achats et le statut des abonnements, et que vous utilisez Adapty pour envoyer les événements d'abonnement et les données analytiques.
:::important
En mode Observateur, le SDK Adapty ne fermera aucune transaction — assurez-vous de les gérer de votre côté.
:::
```kotlin showLineNumbers
val config = AdaptyConfig
.Builder("PUBLIC_SDK_KEY")
.withObserverMode(true) // default false
.build()
Adapty.activate(configuration = config)
.onSuccess {
Log.d("Adapty", "SDK initialised in observer mode")
}
.onError { error ->
Log.e("Adapty", "Adapty init error: ${error.message}")
}
```
Paramètres :
| Paramètre | Description |
| --------------------------- | ------------------------------------------------------------ |
| observerMode | Une valeur booléenne qui contrôle le [mode Observateur](observer-vs-full-mode). La valeur par défaut est `false`. |
## Utiliser les paywalls Adapty en mode Observateur \{#using-adapty-paywalls-in-observer-mode\}
Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observateur. Voici ce que vous devrez faire en plus des étapes ci-dessus :
1. Affichez les paywalls normalement pour les [paywalls avec Remote Config](present-remote-config-paywalls-kmp).
3. [Associez les paywalls](report-transactions-observer-mode-kmp) aux transactions d'achat.
---
# File: report-transactions-observer-mode-kmp
---
---
title: "Déclarer les transactions en mode Observateur dans le SDK Kotlin Multiplatform"
description: "Déclarez les transactions d'achat en mode Observateur d'Adapty pour les insights utilisateurs et le suivi des revenus dans le SDK Kotlin Multiplatform."
---
En mode Observateur, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez déclarer les transactions depuis votre store. Il est essentiel de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses.
Utilisez `reportTransaction` pour déclarer explicitement chaque transaction afin qu'Adapty la reconnaisse.
:::warning
**Ne sautez pas la déclaration des transactions !**
Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations.
:::
Si vous utilisez les paywalls Adapty, incluez le `variationId` lors de la déclaration d'une transaction. Cela associe l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises.
```kotlin showLineNumbers
Adapty.reportTransaction(
transactionId = "your_transaction_id",
variationId = paywall.variationId
).onSuccess { profile ->
// Transaction reported successfully
// profile contains updated user data
}.onError { error ->
// handle the error
}
```
Paramètres :
| Paramètre | Présence | Description |
| --------------- | ---------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| transactionId | obligatoire | L'identifiant de transaction de votre achat dans le store. Il s'agit généralement du token d'achat ou de l'identifiant de transaction renvoyé par le store. |
| variationId | optionnel | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). |
---
# File: kmp-troubleshoot-purchases
---
---
title: "Résoudre les problèmes d'achats dans le SDK Kotlin Multiplatform"
description: "Résoudre les problèmes d'achats dans le SDK Kotlin Multiplatform"
---
Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Kotlin Multiplatform.
## makePurchase s'exécute avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\}
**Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et le statut d'abonnement ne sont pas mis à jour dans Adapty.
**Cause** : Cela indique généralement une configuration incomplète du Google Play Store ou des problèmes de configuration.
**Solution** : Assurez-vous d'avoir complété toutes les [étapes de configuration Google Play](initial-android).
## makePurchase est appelée deux fois \{#makepurchase-is-invoked-twice\}
**Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat.
**Cause** : Cela se produit généralement lorsque le flow d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur.
**Solution** : Assurez-vous d'avoir complété toutes les [étapes de configuration Google Play](initial-android).
## AdaptyError.cantMakePayments en mode observateur \{#adaptyerror-cantmakepayments-in-observer-mode\}
**Problème** : Vous obtenez `AdaptyError.cantMakePayments` lors de l'utilisation de `makePurchase` en mode observateur.
**Cause** : En mode observateur, vous devez gérer les achats de votre côté, et non utiliser la méthode `makePurchase` d'Adapty.
**Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observateur. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observateur. Consultez [Implémenter le mode observateur](implement-observer-mode-kmp) pour plus de détails.
## Erreur Adapty : (code : 103, message : Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\}
**Problème** : Vous recevez une erreur de facturation indisponible depuis le Google Play Store.
**Cause** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil.
**Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers.
## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\}
**Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui ne peut pas être trouvé.
**Cause** : Cela est généralement lié à des problèmes de test en sandbox.
**Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de fin d'achat liés au sandbox.
---
# File: kmp-user
---
---
title: "Utilisateurs & accès dans le SDK Kotlin Multiplatform"
description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application Kotlin Multiplatform avec le SDK Adapty."
---
Cette page regroupe tous les guides pour travailler avec les utilisateurs et les niveaux d'accès dans votre application Kotlin Multiplatform. Choisissez le sujet dont vous avez besoin :
- **[Identifier les utilisateurs](kmp-identifying-users)** - Apprenez à identifier les utilisateurs dans votre application
- **[Mettre à jour les données utilisateur](kmp-setting-user-attributes)** - Définir les attributs utilisateur et les données de profil
- **[Écouter les changements de statut d'abonnement](kmp-listen-subscription-changes)** - Surveiller les changements d'abonnement en temps réel
- **[Mode Enfants](kids-mode-kmp)** - Implémenter le mode Enfants pour votre application
---
# File: kmp-identifying-users
---
---
title: "Identifier les utilisateurs dans le SDK Kotlin Multiplatform"
description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées."
---
Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera envoyé à toutes les intégrations.
### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\}
Si vous disposez d'un identifiant utilisateur au moment de la configuration, passez-le simplement comme paramètre `customerUserId` à la méthode `.activate()` :
```kotlin showLineNumbers
Adapty.activate(
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("YOUR_USER_ID")
.build()
).onSuccess {
// successful activation
}.onError { error ->
// handle the error
}
}
```
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\}
Si vous n'avez pas d'identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'usage les plus courants sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié.
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID").onSuccess {
// successful identify
}.onError { error ->
// handle the error
}
```
Paramètres de la requête :
- **Customer User ID** (obligatoire) : un identifiant utilisateur sous forme de chaîne de caractères.
:::warning
Nouvelle soumission des données utilisateur importantes
Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces situations, le SDK Adapty bascule automatiquement vers le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, comme des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez soumettre à nouveau ces données pour l'utilisateur identifié.
Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes.
:::
### Déconnexion et reconnexion \{#logging-out-and-logging-in\}
Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` :
```kotlin showLineNumbers
Adapty.logout().onSuccess {
// successful logout
}.onError { error ->
// handle the error
}
```
Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`.
## Associer un `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\}
[`iosAppAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) est un **UUID** qui vous permet de relier les transactions App Store à l'identité interne de vos utilisateurs.
StoreKit associe ce token à chaque transaction, ce qui permet à votre backend de faire correspondre les données App Store à vos utilisateurs.
Utilisez un UUID stable généré par utilisateur et réutilisez-le pour le même compte sur tous les appareils.
Cela garantit que les achats et les notifications App Store restent correctement associés.
Vous pouvez définir le token de deux façons : lors de l'activation du SDK ou lors de l'identification de l'utilisateur.
:::important
Vous devez toujours passer `iosAppAccountToken` avec `customerUserId`.
Si vous ne passez que le token, il ne sera pas inclus dans la transaction.
:::
```kotlin showLineNumbers
// During configuration:
Adapty.activate(
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId(
id = "YOUR_USER_ID",
iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN"
)
.build()
).onSuccess {
// successful activation
}.onError { error ->
// handle the error
}
// Or when identifying users
Adapty.identify(
customerUserId = "YOUR_USER_ID",
iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN"
).onSuccess {
// successful identify
}.onError { error ->
// handle the error
}
```
## Définir des identifiants de compte obscurcis (Android) \{#set-obfuscated-account-ids-android\}
Google Play exige des identifiants de compte obscurcis dans certains cas d'usage pour renforcer la confidentialité et la sécurité des utilisateurs. Ces identifiants aident Google Play à identifier les achats tout en préservant l'anonymat des informations utilisateur, ce qui est particulièrement important pour la prévention des fraudes et l'analyse.
Vous aurez peut-être besoin de définir ces identifiants si votre application traite des données utilisateur sensibles ou si vous devez vous conformer à des réglementations spécifiques en matière de confidentialité. Les identifiants obscurcis permettent à Google Play de suivre les achats sans exposer les identifiants réels des utilisateurs.
:::important
Vous devez toujours passer `androidObfuscatedAccountId` avec `customerUserId`.
Si vous ne passez que l'identifiant de compte obscurcis, il ne sera pas inclus dans la transaction.
:::
```kotlin showLineNumbers
// During configuration:
Adapty.activate(
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId(
id = "YOUR_USER_ID",
androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID"
)
.build()
).onSuccess {
// successful activation
}.onError { error ->
// handle the error
}
// Or when identifying users
Adapty.identify(
customerUserId = "YOUR_USER_ID",
androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID"
).onSuccess {
// successful identify
}.onError { error ->
// handle the error
}
```
## Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\}
Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`.
Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID.
**Ce qu'Adapty peut détecter entre les appareils**
| Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire |
| --- | --- | --- |
| Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. |
| Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. |
| Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. |
| Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. |
**Restaurer les achats sur un nouvel appareil**
Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK.
Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`.
---
# File: kmp-setting-user-attributes
---
---
title: "Définir les attributs utilisateur dans le SDK Kotlin Multiplatform"
description: "Découvrez comment définir les attributs utilisateur dans Adapty pour améliorer la segmentation des audiences."
---
Vous pouvez définir des attributs optionnels tels que l'adresse e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM.
### Définir les attributs utilisateur \{#setting-user-attributes\}
Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` :
```kotlin showLineNumbers
val builder = AdaptyProfileParameters.Builder()
.withEmail("email@email.com")
.withPhoneNumber("+18888888888")
.withFirstName("John")
.withLastName("Appleseed")
.withGender(AdaptyProfile.Gender.FEMALE)
.withBirthday(AdaptyProfile.Date(1970, 1, 3))
Adapty.updateProfile(builder.build())
.onSuccess {
// profile updated successfully
}
.onError { error ->
// handle the error
}
```
Notez que les attributs précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
### Liste des clés autorisées \{#the-allowed-keys-list\}
Les clés `` autorisées de `AdaptyProfileParameters.Builder` et les valeurs `` correspondantes sont listées ci-dessous :
| Clé | Valeur |
|---|-----|
| email
phoneNumber
firstName
lastName
| String |
| gender | Enum, les valeurs autorisées sont : `AdaptyProfile.Gender.FEMALE`, `AdaptyProfile.Gender.MALE`, `AdaptyProfile.Gender.OTHER` |
| birthday | Date |
### Attributs utilisateur personnalisés \{#custom-user-attributes\}
Vous pouvez définir vos propres attributs personnalisés. Ils sont généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblés, et les exploiter dans vos analyses pour identifier quelles métriques produit influencent le plus les revenus.
```kotlin showLineNumbers
val builder = AdaptyProfileParameters.Builder()
builder.withCustomAttribute("key1", "value1")
```
Pour supprimer une clé existante, utilisez la méthode `.withRemovedCustomAttribute()` :
```kotlin showLineNumbers
val builder = AdaptyProfileParameters.Builder()
builder.withRemovedCustomAttribute("key2")
```
Il peut parfois être utile de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`.
:::warning
Gardez à l'esprit que la valeur de `customAttributes` peut ne pas être à jour, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment. Les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation.
:::
### Limites \{#limits\}
- Jusqu'à 30 attributs personnalisés par utilisateur
- Les noms de clés peuvent contenir jusqu'à 30 caractères. Ils peuvent inclure des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.`
- La valeur peut être une chaîne de caractères ou un nombre à virgule flottante, sans dépasser 50 caractères.
---
# File: kmp-listen-subscription-changes
---
---
title: "Vérifier le statut d'abonnement dans le SDK Kotlin Multiplatform"
description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Kotlin Multiplatform."
---
Avec Adapty, suivre le statut d'abonnement est simple. Vous n'avez pas besoin d'insérer manuellement des identifiants de produits dans votre code. Vous pouvez vérifier le statut d'abonnement d'un utilisateur en contrôlant l'existence d'un [niveau d'accès](access-level) actif.
Avant de commencer à vérifier le statut d'abonnement, configurez les [notifications développeur en temps réel (RTDN)](enable-real-time-developer-notifications-rtdn).
## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\}
Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). Nous vous recommandons de récupérer le profil au démarrage de votre application, par exemple lorsque vous [identifiez un utilisateur](android-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour dès qu'une modification survient. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander à chaque fois.
Pour être notifié des mises à jour du profil, écoutez les changements de profil comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](android-listen-subscription-changes) ci-dessous.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\}
Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` :
```kotlin showLineNumbers
Adapty.getProfile().onSuccess { profile ->
// check the access
}.onError { error ->
// handle the error
}
```
Paramètres de la réponse :
| Paramètre | Description |
| --------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Profile | Un objet [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.
La méthode `.getProfile` fournit le résultat le plus récent car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données du cache sont renvoyées. Il est également important de noter que le SDK Adapty met à jour le cache `AdaptyProfile` régulièrement, afin de maintenir ces informations aussi à jour que possible.
|
La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Vous pouvez avoir plusieurs niveaux d'accès par application. Par exemple, si vous avez une application de presse et vendez des abonnements à différents sujets indépendamment, vous pouvez créer des niveaux d'accès « sports » et « science ». Mais la plupart du temps, vous n'aurez besoin que d'un seul niveau d'accès ; dans ce cas, vous pouvez simplement utiliser le niveau d'accès « premium » par défaut.
Voici un exemple de vérification du niveau d'accès « premium » par défaut :
```kotlin showLineNumbers
Adapty.getProfile().onSuccess { profile ->
if (profile.accessLevels["premium"]?.isActive == true) {
// grant access to premium features
}
}.onError { error ->
// handle the error
}
```
### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\}
Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement.
Pour recevoir les messages d'Adapty, vous devez effectuer quelques configurations supplémentaires :
```kotlin showLineNumbers
Adapty.setOnProfileUpdatedListener { profile ->
// handle any changes to subscription state
}
```
Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis.
### Cache du statut d'abonnement \{#subscription-status-cache\}
Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil.
Il est toutefois important de noter qu'il n'est pas possible d'interroger directement le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier les mises à jour ou modifications liées au profil. Si des modifications sont détectées, comme de nouvelles transactions ou d'autres mises à jour, elles sont transmises aux données en cache afin de les maintenir synchronisées avec le serveur.
---
# File: kmp-deal-with-att
---
---
title: "Gérer l'ATT dans le SDK Kotlin Multiplatform"
description: "Démarrez avec Adapty sur Kotlin Multiplatform pour simplifier la configuration et la gestion des abonnements."
---
Si votre application utilise le framework AppTrackingTransparency et présente une demande d'autorisation de suivi à l'utilisateur, vous devez envoyer le [statut d'autorisation](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) à Adapty.
```kotlin showLineNumbers
val profileParameters = AdaptyProfileParameters.Builder()
.withAttStatus(3) // 3 = ATTrackingManagerAuthorizationStatusAuthorized
.build()
Adapty.updateProfile(profileParameters)
.onSuccess {
// ATT status updated successfully
}
.onError { error ->
// handle AdaptyError
}
```
:::warning
Nous vous recommandons vivement d'envoyer cette valeur le plus tôt possible dès qu'elle change — c'est la seule façon de transmettre les données en temps voulu aux intégrations que vous avez configurées.
:::
---
# File: kids-mode-kmp
---
---
title: "Mode Enfants dans le SDK Kotlin Multiplatform"
description: "Activez facilement le Mode Enfants pour respecter les politiques Google. Aucune collecte de GAID ou de données publicitaires dans le SDK Kotlin Multiplatform."
---
Si votre application Kotlin Multiplatform est destinée aux enfants, vous devez respecter les politiques de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour satisfaire ces politiques et passer les revues des stores.
## Ce qui est requis \{#whats-required\}
Vous devez configurer le SDK Adapty pour désactiver la collecte de :
- [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS)
- [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android)
- [Adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf)
De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `` sera très probablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'une adresse e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité.
## Activation du Mode Enfants \{#enabling-kids-mode\}
### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\}
Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, accédez aux [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**.
### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\}
Pour respecter les politiques, vous devez désactiver la collecte de l'Android Advertising ID (AAID/GAID) et de l'adresse IP lors de l'initialisation du SDK Adapty :
```kotlin showLineNumbers
override fun onCreate() {
super.onCreate()
val config = AdaptyConfig
.Builder("PUBLIC_SDK_KEY")
// highlight-start
.withGoogleAdvertisingIdCollectionDisabled(true) // set to `true`
.withIpAddressCollectionDisabled(true) // set to `true`
// highlight-end
.build()
Adapty.activate(configuration = config)
.onSuccess {
Log.d("Adapty", "SDK initialised with privacy settings")
}
.onError { error ->
Log.e("Adapty", "Adapty init error: ${error.message}")
}
}
```
---
# File: kmp-onboardings
---
---
title: "Onboardings dans le SDK Kotlin Multiplatform"
description: "Découvrez comment travailler avec les onboardings dans votre application Kotlin Multiplatform avec le SDK Adapty."
---
:::warning
**Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une version future.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — ce qui offre des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls) et [Afficher des flows et des paywalls](kmp-present-paywalls) pour commencer.
:::
---
# File: kmp-get-onboardings
---
---
title: "Récupérer les onboardings dans le SDK Kotlin Multiplatform"
description: "Découvrez comment récupérer les onboardings dans Adapty pour Kotlin Multiplatform."
---
:::warning
**Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement plus rapides et aucune dépendance à un environnement WebView. Consultez [Obtenir des flows et des paywalls](kmp-get-pb-paywalls) et [Afficher des flows et des paywalls](kmp-present-paywalls) pour commencer.
:::
Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Kotlin Multiplatform. La première étape consiste à récupérer l'onboarding associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous.
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) en version 3.15.0 ou supérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
## Récupérer un onboarding \{#fetch-onboarding\}
Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'expérience complète — quel contenu apparaît, comment il est présenté et comment les interactions utilisateur (comme les réponses à des quiz ou les saisies de formulaires) sont traitées. Le conteneur assure également le suivi automatique des événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi des vues séparément.
Pour de meilleures performances, récupérez la configuration de l'onboarding suffisamment tôt pour que les images aient le temps de se télécharger avant d'être affichées aux utilisateurs.
Pour obtenir un onboarding, utilisez la méthode `getOnboarding` :
```kotlin showLineNumbers
Adapty.getOnboarding(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
loadTimeout = 5.seconds
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tentera de charger les données depuis le serveur et retournera les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser durant la session pour éviter les requêtes réseau.
Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé qu'à la réinstallation de l'application ou lors d'un nettoyage manuel.
Le SDK Adapty stocke les onboardings localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront 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 plusieurs requêtes en interne.
|
Paramètres de la réponse :
| Paramètre | Description |
|:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Onboarding | Un objet [`AdaptyOnboarding`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-onboarding/) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config, et plusieurs autres propriétés. |
## Accélérer la récupération des onboardings avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\}
En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pourriez vouloir afficher un onboarding par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout.
Pour y remédier, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer l'onboarding via la méthode `getOnboarding`, comme détaillé dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus.
:::warning
Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes :
- **Problèmes de compatibilité** : peut créer des problèmes lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions puissent s'afficher incorrectement.
- **Pas de personnalisation** : affiche uniquement le contenu pour l'audience « All Users », sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés.
Si une récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding).
:::
```kotlin showLineNumbers
Adapty.getOnboardingForDefaultAudience(
placementId = "YOUR_PLACEMENT_ID",
locale = "en",
fetchPolicy = AdaptyPaywallFetchPolicy.Default,
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. Il s'agit de la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag désigne la langue, le second la région.
Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien. |
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tentera de charger les données depuis le serveur et retournera les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser durant la session pour éviter les requêtes réseau.
Notez que le cache reste intact lors du redémarrage de l'application et n'est effacé qu'à la réinstallation de l'application ou lors d'un nettoyage manuel.
Le SDK Adapty stocke les onboardings localement en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos onboardings tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
---
# File: kmp-present-onboardings
---
---
title: "Présenter les onboardings dans le SDK Kotlin Multiplatform"
description: "Découvrez comment présenter efficacement les onboardings pour augmenter vos conversions."
---
:::warning
**Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement plus rapides et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows & paywalls](kmp-get-pb-paywalls) et [Afficher des flows & paywalls](kmp-present-paywalls) pour commencer.
:::
Si vous avez personnalisé un onboarding via le builder, vous n'avez pas besoin de vous soucier de son rendu dans le code de votre application Kotlin Multiplatform pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et comment cela doit l'être.
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) 3.16.1 ou une version ultérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
Le SDK Adapty Kotlin Multiplatform offre deux façons de présenter les onboardings :
- **Avec Compose Multiplatform**
- **Sans Compose Multiplatform**
## Avec Compose Multiplatform \{#with-compose-multiplatform\}
Pour afficher un onboarding, utilisez la méthode `view.present()` sur la `view` créée par la méthode `createOnboardingView`. Chaque `view` ne peut être utilisée qu'une seule fois. Si vous devez afficher l'onboarding à nouveau, appelez `createOnboardingView` une nouvelle fois pour créer une nouvelle instance de `view`.
:::warning
Réutiliser la même `view` sans la recréer peut entraîner une erreur.
:::
```kotlin showLineNumbers title="Kotlin Multiplatform"
viewModelScope.launch {
AdaptyUI.createOnboardingView(onboarding = onboarding).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
### Configurer le style de présentation iOS \{#configure-ios-presentation-style\}
Configurez la façon dont l'onboarding est présenté sur iOS en passant le paramètre `iosPresentationStyle` à la méthode `present()`. Le paramètre accepte les valeurs `AdaptyUIIOSPresentationStyle.FULLSCREEN` (par défaut) ou `AdaptyUIIOSPresentationStyle.PAGESHEET`.
```kotlin showLineNumbers
viewModelScope.launch {
val view = AdaptyUI.createOnboardingView(onboarding = onboarding).getOrNull()
view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET)
}
```
### Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\}
Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web directement dans votre application, permettant aux utilisateurs de les consulter sans changer d'app.
Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `AdaptyWebPresentation.EXTERNAL_BROWSER` :
```kotlin showLineNumbers
viewModelScope.launch {
AdaptyUI.createOnboardingView(
onboarding = onboarding,
externalUrlsPresentation = AdaptyWebPresentation.EXTERNAL_BROWSER // default – IN_APP_BROWSER
).onSuccess { view ->
view.present()
}.onError { error ->
// handle the error
}
}
```
## Sans Compose Multiplatform \{#without-compose-multiplatform\}
:::note
`createNativeOnboardingView` fait partie du module principal `io.adapty:adapty-kmp`. Si votre projet n'utilise pas Compose Multiplatform, vous n'avez pas besoin de la dépendance `io.adapty:adapty-kmp-ui`.
:::
Pour intégrer un onboarding sans Compose Multiplatform, appelez `createNativeOnboardingView`. Cette méthode retourne un `AdaptyNativeOnboardingView` que vous ajoutez à votre layout :
```kotlin showLineNumbers title="Kotlin Multiplatform (Android)"
val nativeView = AdaptyUI.createNativeOnboardingView(
context = context,
viewModelStoreOwner = activity,
onboarding = onboarding,
observer = myOnboardingObserver,
)
// Embed in your Compose layout:
AndroidView(
factory = { nativeView.view },
modifier = Modifier.fillMaxSize()
)
```
Les méthodes par défaut de l'interface KMP devenant `@required` en Swift, vous ne pouvez pas implémenter `AdaptyUIOnboardingsEventsObserver` directement depuis Swift. Déclarez d'abord une classe de base ouverte dans `iosMain` :
```kotlin showLineNumbers title="iosMain (Kotlin)"
open class BaseOnboardingObserver : AdaptyUIOnboardingsEventsObserver
```
Puis sous-classez-la en Swift, en ne redéfinissant que ce dont vous avez besoin :
```swift showLineNumbers title="Swift"
class MyOnboardingObserver: BaseOnboardingObserver {
override func onboardingViewOnCloseAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
// remove nativeView from your view hierarchy
}
}
let nativeView = AdaptyUI.shared.createNativeOnboardingView(
onboarding: onboarding,
observer: MyOnboardingObserver()
)
// nativeView.viewController is a UIViewController.
// Add it to your SwiftUI view or UIKit hierarchy.
```
### Supprimer la vue \{#dispose-the-view\}
Appelez `dispose()` lors de la suppression de la vue de votre layout. Cela désenregistre le listener d'événements et libère les ressources internes.
```kotlin showLineNumbers title="Kotlin Multiplatform"
nativeView.dispose()
```
---
# File: kmp-handling-onboarding-events
---
---
title: "Gérer les événements d'onboarding dans le SDK Kotlin Multiplatform"
description: "Gérez les événements liés à l'onboarding dans Kotlin Multiplatform avec Adapty."
---
:::warning
**Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une future version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu natif cohérent, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Récupérer les flows et paywalls](kmp-get-pb-paywalls) et [Afficher les flows et paywalls](kmp-present-paywalls) pour commencer.
:::
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) 3.15.0 ou une version ultérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Découvrez comment y répondre ci-dessous.
## Configurer l'observateur d'événements d'onboarding \{#set-up-the-onboarding-event-observer\}
Pour gérer les événements d'onboarding, vous devez implémenter l'interface `AdaptyUIOnboardingsEventsObserver` et la configurer via `AdaptyUI.setOnboardingsEventsObserver()`. Cette opération doit être effectuée tôt dans le cycle de vie de votre application, généralement dans votre activité principale ou lors de l'initialisation de l'application.
```kotlin
// In your app initialization
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
## Actions personnalisées \{#custom-actions\}
Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un identifiant. Vous pouvez ensuite utiliser cet identifiant dans votre code et le traiter comme une action personnalisée.
Par exemple, si un utilisateur appuie sur un bouton personnalisé comme **Login** ou **Allow notifications**, la méthode déléguée `onCustomAction` sera déclenchée avec l'identifiant d'action défini dans le builder. Vous pouvez créer vos propres identifiants, par exemple « allowNotifications ».
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnCustomAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
when (actionId) {
"openPaywall" -> {
// Display paywall from onboarding
// You would typically fetch and present a new paywall here
mainUiScope.launch {
// Example: Get paywall by placement ID
// val paywallResult = Adapty.getPaywall("your_placement_id")
// paywallResult.onSuccess { paywall ->
// val paywallViewResult = AdaptyUI.createPaywallView(paywall)
// paywallViewResult.onSuccess { paywallView ->
// paywallView.present()
// }
// }
}
}
"allowNotifications" -> {
// Handle notification permissions
}
else -> {
// Handle other custom actions
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
Exemple d'événement (cliquer pour développer)
```json
{
"actionId": "allowNotifications",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
}
}
```
## Fermeture de l'onboarding \{#closing-onboarding\}
L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton avec l'action **Close** assignée. Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple :
:::important
Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter l'affichage de l'onboarding lui-même.
:::
Si vous utilisez [`createNativeOnboardingView`](kmp-present-onboardings#without-compose-multiplatform), `view.isStandaloneView` est `false` — l'implémentation par défaut n'appelle pas `view.dismiss()`. Retirez la vue de votre layout et appelez `dispose()` sur elle dans ce callback à la place.
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnCloseAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
// Dismiss the onboarding screen
mainUiScope.launch {
view.dismiss()
}
// Additional cleanup or navigation logic can be added here
// For example, navigate back or show main app content
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
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 à l'intérieur de l'onboarding. Si vous souhaitez ouvrir un paywall après la fermeture de l'onboarding, il existe une approche plus directe — gérez [`onboardingViewOnCloseAction`](#closing-onboarding) et ouvrez un paywall sans vous appuyer sur les données de l'événement.
:::
La façon la plus simple de travailler avec les paywalls dans les onboardings est de définir l'identifiant d'action égal à l'identifiant de placement du paywall. Ainsi, vous pouvez utiliser l'identifiant de placement pour récupérer et ouvrir le paywall directement :
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnPaywallAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
// Get the paywall using the placement ID from the action
mainUiScope.launch {
val paywallResult = Adapty.getPaywall(placementId = actionId)
paywallResult.onSuccess { paywall ->
val paywallViewResult = AdaptyUI.createPaywallView(paywall)
paywallViewResult.onSuccess { paywallView ->
paywallView.present()
}.onError { error ->
// handle the error
}
}.onError { error ->
// handle the error
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
Exemple d'événement (cliquer pour développer)
```json
{
"action_id": "premium_offer_1",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "pricing_screen",
"screen_index": 2,
"total_screens": 4
}
}
```
## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\}
Lorsqu'un onboarding finit de se charger, cette méthode est invoquée :
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewDidFinishLoading(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta
) {
// Handle loading completion
// You can add any initialization logic here
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
Exemple d'événement (cliquer pour développer)
```json
{
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "welcome_screen",
"screen_index": 0,
"total_screens": 4
}
}
```
## Événements de navigation \{#navigation-events\}
La méthode `onboardingViewOnAnalyticsEvent` est appelée lors de divers événements analytiques survenant pendant le flow d'onboarding.
L'objet `event` peut être de l'un des types suivants :
|Type | Description |
|------------|-------------|
| `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | Lorsque l'onboarding a été chargé |
| `AdaptyOnboardingsAnalyticsEventScreenPresented` | Lorsqu'un écran est affiché |
| `AdaptyOnboardingsAnalyticsEventScreenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque l'utilisateur effectue une action pour quitter l'écran. |
| `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | Lorsque le deuxième écran est affiché |
| `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | Déclenché lorsque l'adresse e-mail de l'utilisateur est collectée via le champ de saisie |
| `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'identifiant `final`. Si vous avez besoin de cet événement, attribuez l'identifiant `final` au dernier écran. |
| `AdaptyOnboardingsAnalyticsEventUnknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) |
Chaque événement inclut des informations `meta` contenant :
| Champ | Description |
|------------|-------------|
| `onboardingId` | Identifiant unique du flow d'onboarding |
| `screenClientId` | Identifiant de l'écran actuel |
| `screenIndex` | Position de l'écran actuel dans le flow |
| `screensTotal` | Nombre total d'écrans dans le flow |
Voici un exemple d'utilisation des événements analytiques pour le suivi :
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnAnalyticsEvent(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
event: AdaptyOnboardingsAnalyticsEvent
) {
when (event) {
is AdaptyOnboardingsAnalyticsEventOnboardingStarted -> {
// Track onboarding start
trackEvent("onboarding_started", event.meta)
}
is AdaptyOnboardingsAnalyticsEventScreenPresented -> {
// Track screen presentation
trackEvent("screen_presented", event.meta)
}
is AdaptyOnboardingsAnalyticsEventScreenCompleted -> {
// Track screen completion with user response
trackEvent("screen_completed", event.meta, event.elementId, event.reply)
}
is AdaptyOnboardingsAnalyticsEventOnboardingCompleted -> {
// Track successful onboarding completion
trackEvent("onboarding_completed", event.meta)
}
is AdaptyOnboardingsAnalyticsEventUnknown -> {
// Handle unknown events
trackEvent(event.name, event.meta)
}
// Handle other cases as needed
}
}
private fun trackEvent(eventName: String, meta: AdaptyUIOnboardingMeta, elementId: String? = null, reply: String? = null) {
// Implement your analytics tracking here
// For example, send to your analytics service
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
Exemples d'événements (cliquer pour développer)
```javascript
// OnboardingStarted
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "welcome_screen",
"screenIndex": 0,
"screensTotal": 4
}
}
// ScreenPresented
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "interests_screen",
"screenIndex": 2,
"screensTotal": 4
}
}
// ScreenCompleted
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 1,
"screensTotal": 4
},
"elementId": "profile_form",
"reply": "success"
}
// SecondScreenPresented
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 1,
"screensTotal": 4
}
}
// UserEmailCollected
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 1,
"screensTotal": 4
}
}
// OnboardingCompleted
{
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "final_screen",
"screenIndex": 3,
"screensTotal": 4
}
}
```
---
# File: kmp-onboarding-input
---
---
title: "Traiter les données des onboardings dans le SDK Kotlin Multiplatform"
description: "Enregistrez et utilisez les données des onboardings dans votre application Kotlin Multiplatform avec le SDK Adapty."
---
:::warning
**Les onboardings sont dépréciés dans le SDK v4 et seront supprimés dans une prochaine version.** Ils ne reçoivent plus de correctifs ni d'améliorations. Utilisez les [flows](kmp-get-pb-paywalls) à la place : contrairement aux onboardings, qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — vous offrant des animations plus fluides, un aspect natif cohérent, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Obtenir des flows & paywalls](kmp-get-pb-paywalls) et [Afficher des flows & paywalls](kmp-present-paywalls) pour commencer.
:::
Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onboardingViewOnStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code.
Par exemple :
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnStateUpdatedAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
elementId: String,
params: AdaptyOnboardingsStateUpdatedParams
) {
// Store user preferences or responses
when (params) {
is AdaptyOnboardingsSelectParams -> {
// Handle single selection
val id = params.id
val value = params.value
val label = params.label
AppLogger.d("Selected option: $label (id: $id, value: $value)")
}
is AdaptyOnboardingsMultiSelectParams -> {
// Handle multiple selections
}
is AdaptyOnboardingsInputParams -> {
// Handle text input
}
is AdaptyOnboardingsDatePickerParams -> {
// Handle date selection
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
Exemples de données enregistrées (le format peut différer dans votre implémentation)
```javascript
// Example of a saved select action
{
"id": "onboarding_on_state_updated_action",
"view": { /* AdaptyUI.OnboardingView object */ },
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "preferences_screen",
"screen_index": 1,
"total_screens": 3
},
"action": {
"element_id": "preference_selector",
"element_type": "select",
"value": {
"id": "option_1",
"value": "premium",
"label": "Premium Plan"
}
}
}
// Example of a saved multi-select action
{
"id": "onboarding_on_state_updated_action",
"view": { /* AdaptyUI.OnboardingView object */ },
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "interests_screen",
"screen_index": 2,
"total_screens": 3
},
"action": {
"element_id": "interests_selector",
"element_type": "multi_select",
"value": [
{
"id": "interest_1",
"value": "sports",
"label": "Sports"
},
{
"id": "interest_2",
"value": "music",
"label": "Music"
}
]
}
}
// Example of a saved input action
{
"id": "onboarding_on_state_updated_action",
"view": { /* AdaptyUI.OnboardingView object */ },
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 0,
"total_screens": 3
},
"action": {
"element_id": "name_input",
"element_type": "input",
"value": {
"type": "text",
"value": "John Doe"
}
}
}
// Example of a saved date picker action
{
"id": "onboarding_on_state_updated_action",
"view": { /* AdaptyUI.OnboardingView object */ },
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 0,
"total_screens": 3
},
"action": {
"element_id": "birthday_picker",
"element_type": "date_picker",
"value": {
"day": 15,
"month": 6,
"year": 1990
}
}
}
```
## Cas d'utilisation \{#use-cases\}
### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\}
Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois la même information, vous devez [mettre à jour le profil utilisateur](kmp-setting-user-attributes) avec les données saisies lors du traitement de l'action.
Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans le code de votre application, cela peut ressembler à ceci :
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnStateUpdatedAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
elementId: String,
params: AdaptyOnboardingsStateUpdatedParams
) {
// Store user preferences or responses
when (params) {
is AdaptyOnboardingsInputParams -> {
// Handle text input
val builder = AdaptyProfileParameters.Builder()
// Map elementId to appropriate profile field
when (elementId) {
"name" -> {
when (val input = params.input) {
is AdaptyOnboardingsTextInput -> {
builder.withFirstName(input.value)
}
}
}
"email" -> {
when (val input = params.input) {
is AdaptyOnboardingsEmailInput -> {
builder.withEmail(input.value)
}
}
}
}
// Update profile asynchronously
mainUiScope.launch {
val profileParams = builder.build()
val result = Adapty.updateProfile(profileParams)
result.onSuccess { profile ->
// Profile updated successfully
AppLogger.d("Profile updated: ${profile.email}")
}.onError { error ->
// Handle the error
AppLogger.e("Failed to update profile: ${error.message}")
}
}
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\}
En utilisant des quiz dans les onboardings, vous pouvez également personnaliser les paywalls que vous affichez aux utilisateurs après qu'ils ont terminé l'onboarding.
Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs.
1. [Ajoutez un quiz](onboarding-quizzes) dans le générateur d'onboarding et attribuez des IDs significatifs à ses options.
2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](kmp-setting-user-attributes) pour les utilisateurs.
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnStateUpdatedAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
elementId: String,
params: AdaptyOnboardingsStateUpdatedParams
) {
// Handle quiz responses and set custom attributes
when (params) {
is AdaptyOnboardingsSelectParams -> {
// Handle quiz selection
val builder = AdaptyProfileParameters.Builder()
// Map quiz responses to custom attributes
when (elementId) {
"experience" -> {
// Set custom attribute 'experience' with the selected value (beginner, amateur, pro)
builder.withCustomAttribute("experience", params.value)
}
}
// Update profile asynchronously
mainUiScope.launch {
val profileParams = builder.build()
val result = Adapty.updateProfile(profileParams)
result.onSuccess { profile ->
// Profile updated successfully
AppLogger.d("Custom attribute 'experience' set to: ${params.value}")
}.onError { error ->
// Handle the error
AppLogger.e("Failed to update profile: ${error.message}")
}
}
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé.
4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé.
5. [Affichez un paywall](kmp-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall en tant que [réponse à l'action de ce bouton](kmp-handling-onboarding-events#opening-a-paywall).
---
# File: kmp-best-practices
---
---
title: "Meilleures pratiques avec le SDK Kotlin Multiplatform"
description: "Modèles de référence pour intégrer le SDK Adapty sur Kotlin Multiplatform — ordre d'appel, gestion des erreurs et autres règles pour une utilisation en production."
---
---
# File: kmp-sdk-call-order
---
---
title: "Ordre d'appel dans le SDK Kotlin Multiplatform"
description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs d'activation intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre."
---
`Adapty.activate()` doit se terminer avant tout autre appel de méthode du SDK Adapty. Tant qu'il n'est pas terminé, le SDK n'a aucun état. Tout appel émis avant ou en parallèle d'`activate()` échoue avec une erreur d'activation. Voir [Gestion des erreurs dans le SDK Kotlin Multiplatform](kmp-handle-errors).
Si votre application authentifie les utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty.identify()` à ce moment-là. N'appelez pas les méthodes liées aux actions utilisateur tant qu'`identify` n'est pas terminé. Les appels qui entrent en concurrence avec lui renvoient soit une erreur, soit atterrissent sur le profil anonyme créé lors de l'activation. Dans ce cas, l'attribution, les identifiants MMP comme `appsflyer_id` et la propriété d'installation ne sont pas toujours transférés au profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme.
Les SDK MMP et analytics (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré au profil identifié. Pour les spécificités d'AppsFlyer, voir [AppsFlyer](appsflyer).
## L'ordre correct \{#the-correct-order\}
Votre chemin dépend de deux choses : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou analytics.
- **Étapes 2 et 5** : Obligatoires pour toutes les applications. Activez le SDK, puis appelez les méthodes du SDK.
- **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou analytics (AppsFlyer, Adjust, Branch, PostHog).
- **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et récupère l'identifiant utilisateur client après le lancement.
Si vous avez l'identifiant utilisateur client au lancement de l'application, passez-le dans `AdaptyConfig.Builder` avant d'appeler `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, l'étape 4 est donc inutile.
| Étape | Appel | Quand | Remarques |
|------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| 1 | Initialisez votre SDK MMP ou analytics (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'application, en premier | Attendez le callback d'UID du MMP, par exemple `getAppsFlyerUID`. |
| 2a | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | Lancement de l'application, après l'étape 1, si vous avez l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. |
| 2b | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").build())` sans `withCustomerUserId` | Lancement de l'application, après l'étape 1, si vous n'avez pas l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. |
| 3 | `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` pour chaque MMP | Après l'étape 2, avant tout appel d'action utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. |
| 4 | `Adapty.identify("YOUR_USER_ID").onSuccess { ... }.onError { ... }` | Après l'étape 3 (ou l'étape 2 sans MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Attendez `onSuccess` avant tout appel d'action utilisateur. Les appels concurrents pendant `identify` peuvent atterrir sur le profil anonyme. |
| 5 | `getPaywall` (`getFlow` dans SDK v4), `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 sans MMP) | Ces appels nécessitent un profil stable. |
:::important
Ignorer ces étapes entraîne la perte d'accès premium pour les utilisateurs existants, l'absence d'`appsflyer_id` sur les profils, et des paywalls renvoyés pour la mauvaise audience.
:::
## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\}
Si des utilisateurs achètent via un paiement web (Stripe, Paddle) puis installent l'application native, le premier `activate()` sur l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flux d'authentification ou le referrer d'installation), passez-le directement dans `AdaptyConfig.Builder`. Sinon, l'achat web est invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`.
Pour les métadonnées à envoyer avec chaque paiement web, voir :
- [Stripe](stripe)
- [Paddle](paddle)
---
# File: kmp-optimize-paywall-fetching
---
---
title: "Optimiser la récupération des paywalls dans le SDK Kotlin Multiplatform"
description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour Kotlin Multiplatform."
---
Une récupération fiable de paywall sur Kotlin Multiplatform repose sur trois points : un affichage rapide, le retour du paywall ciblé par audience, et un repli gracieux en cas de réseau lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir.
:::tip
Ces règles supposent que `Adapty.activate()` et `Adapty.identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK Kotlin Multiplatform](kmp-sdk-call-order).
:::
Les conseils ci-dessous utilisent les noms de méthodes de la v3. Dans le SDK v4, `getPaywall` est renommé en `getFlow` (voir le [guide de migration](migration-to-kmp-sdk-v4)) — chaque règle s'applique sans changement.
## Règles et pièges \{#rules-and-pitfalls\}
| À faire | À éviter | Pourquoi |
|---|---|---|
| Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements simultanément au démarrage. | Le pré-chargement en masse bloque le thread principal et provoque un écran noir pendant la rafale. |
| Appelez `getPaywall` une fois que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `setOnProfileUpdatedListener`. | Appeler `getPaywall` au démarrage de l'application. | L'attribution n'est pas encore arrivée. Le paywall se résout sur l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. |
| Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment sur `getPaywall`. | Sans délai d'expiration, les utilisateurs avec une mauvaise connectivité voient un écran blanc jusqu'à ce que le réseau réponde — ou ferment l'application. |
Voir [Récupérer les paywalls et les produits](fetch-paywalls-and-products-kmp) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement.
## Optimiser pour une mauvaise connectivité \{#tune-for-poor-connectivity\}
Pour les marchés avec une connectivité constamment faible (zones rurales, transports, régions affectées par le routage) :
- Définissez `fetchPolicy = AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` sur chaque récupération sauf la toute première.
- Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard.
- Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le délai expire.
- Ne conditionnez pas l'affichage du paywall à `Adapty.getProfile()`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface.
---
# File: kmp-test
---
---
title: "Test & release in Kotlin Multiplatform SDK"
description: "Apprenez à vérifier le statut d'abonnement dans votre application Kotlin Multiplatform avec Adapty."
---
Si vous avez déjà intégré le SDK Adapty dans votre application Kotlin Multiplatform, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox.
## Tester votre application \{#test-your-app\}
Pour tester en profondeur vos achats intégrés, consultez nos guides de test spécifiques à chaque plateforme : [guide de test iOS](test-purchases-in-sandbox) et [guide de test Android](testing-on-android).
## Se préparer pour la mise en production \{#prepare-for-release\}
Avant de soumettre votre application au store, suivez la [liste de contrôle de mise en production](release-checklist) pour confirmer que :
- La connexion au store et les notifications serveur sont configurées
- Les achats sont effectués et remontés à Adapty
- L'accès se déverrouille et se restaure correctement
- Les exigences en matière de confidentialité et de révision sont respectées
---
# File: kmp-reference
---
---
title: "Référence pour le SDK Kotlin Multiplatform"
description: "Documentation de référence pour le SDK Adapty Kotlin Multiplatform."
---
Cette page contient la documentation de référence pour le SDK Adapty Kotlin Multiplatform. Choisissez le sujet dont vous avez besoin :
- **[Modèles SDK](https://kmp.adapty.io/adapty/)** - Modèles de données et structures utilisés par le SDK
- **[Gérer les erreurs](kmp-handle-errors)** - Gestion des erreurs et résolution des problèmes
---
# File: kmp-handle-errors
---
---
title: "Gérer les erreurs dans le SDK Kotlin Multiplatform"
description: "Découvrez comment gérer les erreurs dans votre application Kotlin Multiplatform avec Adapty."
---
Cette page couvre la gestion des erreurs dans le SDK Adapty Kotlin Multiplatform.
## Bases de la gestion des erreurs \{#error-handling-basics\}
Toutes les méthodes du SDK Adapty renvoient des résultats qui peuvent être soit un succès, soit une erreur. Gérez toujours les deux cas :
```kotlin showLineNumbers
Adapty.getProfile { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
// Handle success
}
is AdaptyResult.Error -> {
val error = result.error
// Handle error
Log.e("Adapty", "Error: ${error.message}")
}
}
}
```
```java showLineNumbers
Adapty.getProfile(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
// Handle success
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle error
Log.e("Adapty", "Error: " + error.getMessage());
}
});
```
## Codes d'erreur courants \{#common-error-codes\}
| Code d'erreur | Description | Solution |
|---------------|-------------|----------|
| 1000 | Aucun identifiant de produit trouvé | Vérifiez la configuration des produits dans le tableau de bord |
| 1001 | Erreur réseau | Vérifiez la connexion internet |
| 1002 | Clé SDK invalide | Vérifiez votre clé SDK |
| 1003 | Impossible d'effectuer des paiements | L'appareil ne prend pas en charge les paiements |
| 1004 | Produit non disponible | Produit non configuré dans le store |
## Gérer des erreurs spécifiques \{#handle-specific-errors\}
### Erreurs réseau \{#network-errors\}
```kotlin showLineNumbers
Adapty.getPaywall("main") { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// Use paywall
}
is AdaptyResult.Error -> {
val error = result.error
when (error.code) {
1001 -> {
// Network error - show offline message
showOfflineMessage()
}
else -> {
// Other errors
showErrorMessage(error.message)
}
}
}
}
}
```
```java showLineNumbers
Adapty.getPaywall("main", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// Use paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
switch (error.getCode()) {
case 1001:
// Network error - show offline message
showOfflineMessage();
break;
default:
// Other errors
showErrorMessage(error.getMessage());
break;
}
}
});
```
### Erreurs d'achat \{#purchase-errors\}
```kotlin showLineNumbers
product.makePurchase { result ->
when (result) {
is AdaptyResult.Success -> {
val purchase = result.value
// Purchase successful
showSuccessMessage()
}
is AdaptyResult.Error -> {
val error = result.error
when (error.code) {
1003 -> {
// Can't make payments
showPaymentNotAvailableMessage()
}
1004 -> {
// Product not available
showProductNotAvailableMessage()
}
else -> {
// Other purchase errors
showPurchaseErrorMessage(error.message)
}
}
}
}
}
```
```java showLineNumbers
product.makePurchase(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPurchase purchase = ((AdaptyResult.Success) result).getValue();
// Purchase successful
showSuccessMessage();
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
switch (error.getCode()) {
case 1003:
// Can't make payments
showPaymentNotAvailableMessage();
break;
case 1004:
// Product not available
showProductNotAvailableMessage();
break;
default:
// Other purchase errors
showPurchaseErrorMessage(error.getMessage());
break;
}
}
});
```
## Stratégies de récupération après erreur \{#error-recovery-strategies\}
### Réessayer en cas d'erreur réseau \{#retry-on-network-errors\}
```kotlin showLineNumbers
fun getPaywallWithRetry(placementId: String, maxRetries: Int = 3) {
var retryCount = 0
fun attemptGetPaywall() {
Adapty.getPaywall(placementId) { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// Use paywall
}
is AdaptyResult.Error -> {
val error = result.error
if (error.code == 1001 && retryCount < maxRetries) {
// Network error - retry
retryCount++
Handler(Looper.getMainLooper()).postDelayed({
attemptGetPaywall()
}, 1000 * retryCount) // Exponential backoff
} else {
// Max retries reached or other error
showErrorMessage(error.message)
}
}
}
}
}
attemptGetPaywall()
}
```
```java showLineNumbers
public void getPaywallWithRetry(String placementId, int maxRetries) {
AtomicInteger retryCount = new AtomicInteger(0);
Runnable attemptGetPaywall = new Runnable() {
@Override
public void run() {
Adapty.getPaywall(placementId, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// Use paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
if (error.getCode() == 1001 && retryCount.get() < maxRetries) {
// Network error - retry
retryCount.incrementAndGet();
new Handler(Looper.getMainLooper()).postDelayed(this, 1000 * retryCount.get());
} else {
// Max retries reached or other error
showErrorMessage(error.getMessage());
}
}
});
}
};
attemptGetPaywall.run();
}
```
### Utiliser les données en cache en secours \{#fallback-to-cached-data\}
```kotlin showLineNumbers
class PaywallManager {
private var cachedPaywall: AdaptyPaywall? = null
fun getPaywall(placementId: String) {
Adapty.getPaywall(placementId) { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
cachedPaywall = paywall
showPaywall(paywall)
}
is AdaptyResult.Error -> {
val error = result.error
if (error.code == 1001 && cachedPaywall != null) {
// Network error - use cached paywall
showPaywall(cachedPaywall!!)
showOfflineIndicator()
} else {
// No cache available or other error
showErrorMessage(error.message)
}
}
}
}
}
}
```
```java showLineNumbers
public class PaywallManager {
private AdaptyPaywall cachedPaywall;
public void getPaywall(String placementId) {
Adapty.getPaywall(placementId, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
cachedPaywall = paywall;
showPaywall(paywall);
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
if (error.getCode() == 1001 && cachedPaywall != null) {
// Network error - use cached paywall
showPaywall(cachedPaywall);
showOfflineIndicator();
} else {
// No cache available or other error
showErrorMessage(error.getMessage());
}
}
});
}
}
```
## Étapes suivantes \{#next-steps\}
- [Correction de l'erreur Code-1000 noProductIDsFound](InvalidProductIdentifiers-kmp)
- [Correction de l'erreur Code-1003 cantMakePayments](cantMakePayments-kmp)
- [Référence complète de l'API](https://android.adapty.io) - Documentation complète du SDK
---
# File: InvalidProductIdentifiers-kmp
---
---
title: "Correction de l'erreur Code-1000 noProductIDsFound dans le SDK Kotlin Multiplatform"
description: "Résolvez les erreurs d'identifiants de produit invalides lors de la gestion des abonnements dans Adapty."
---
L'erreur avec le code 1000, `noProductIDsFound`, indique qu'aucun des produits demandés sur le paywall n'est disponible à l'achat dans l'App Store, même s'ils y sont bien répertoriés. Cette erreur peut parfois s'accompagner d'un avertissement `InvalidProductIdentifiers`. Si l'avertissement apparaît sans erreur, vous pouvez l'ignorer.
Si vous rencontrez l'erreur `noProductIDsFound`, suivez ces étapes pour la résoudre :
## Étape 1. Vérifier le bundle ID \{#step-2-check-bundle-id\}
1. Ouvrez [App Store Connect](https://appstoreconnect.apple.com/apps). Sélectionnez votre application et accédez à la section **General** → **App Information**.
2. Copiez le **Bundle ID** dans la sous-section **General Information**.
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 accédez à [**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**. Si ce n'est pas le cas, suivez les instructions de la page [Produit dans l'App Store](app-store-products).
4. Comparez l'identifiant du produit dans le tableau avec celui de l'onglet [**Products**](https://app.adapty.io/products) dans l'Adapty Dashboard. Si les identifiants ne correspondent pas, copiez l'identifiant du produit depuis le tableau et [créez un produit](create-product) avec cet identifiant dans l'Adapty Dashboard.
## É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 figurent.
## É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. Vérifiez que tous les prix requis sont bien listés.
## Étape 5. Vérifier le statut de paiement de l'app, le compte bancaire et les formulaires fiscaux \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. Sur la page d'accueil d'[**App Store Connect**](https://appstoreconnect.apple.com/), cliquez sur **Business**.
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 mettre vos produits en ligne dans le store.
## Étape 6. Recréer le produit s'il est bloqué \{#step-6-recreate-the-product-if-its-stuck\}
Les étapes 1 à 5 peuvent toutes être validées — statut `Approved`, Bundle ID correspondant, clé API valide — et pourtant le SDK continue de renvoyer `1000 noProductIDsFound`. Dans ce cas, le produit est peut-être bloqué dans le registre d'Apple. Il arrive que le registre de produits d'Apple entre dans un état où un produit existe dans l'interface d'App Store Connect mais n'est pas exposé au chemin de recherche StoreKit.
Supprimez le produit dans App Store Connect et recréez-le avec le même identifiant de produit. Attendez jusqu'à 24 heures après la recréation pour que la propagation s'effectue.
---
# File: cantMakePayments-kmp
---
---
title: "Correction de l'erreur Code-1003 cantMakePayment dans le SDK Kotlin Multiplatform"
description: "Résolvez l'erreur de paiement lors de la gestion des abonnements dans Adapty."
---
L'erreur 1003, `cantMakePayments`, indique que les achats intégrés ne peuvent pas être effectués sur cet appareil.
Si vous rencontrez l'erreur `cantMakePayments`, cela est généralement dû à l'une des raisons suivantes :
- Restrictions de l'appareil : L'erreur n'est pas liée à Adapty. Consultez les solutions ci-dessous.
- Configuration du mode Observateur : La méthode `makePurchase` et le mode Observateur ne peuvent pas être utilisés simultanément. Consultez la section ci-dessous.
## Problème : Restrictions de l'appareil \{#issue-device-restrictions\}
| Problème | Solution |
|--------------------------------|-------------------------------------------------------------------------------------------------------------|
| Restrictions Screen Time | Désactivez les restrictions d'achat intégré dans [Screen Time](https://support.apple.com/en-us/102470) |
| Compte suspendu | Contactez le support Apple pour résoudre les problèmes de compte |
| Restrictions régionales | Utilisez un compte App Store d'une région prise en charge |
## Problème : Utilisation simultanée du mode Observateur et de makePurchase \{#issue-using-both-observer-mode-and-makepurchase\}
Si vous utilisez `makePurchases` pour gérer les achats, vous n'avez pas besoin d'utiliser le mode Observateur. Le [mode Observateur](observer-vs-full-mode) n'est nécessaire que si vous implémentez vous-même la logique d'achat.
Ainsi, si vous utilisez `makePurchase`, vous pouvez supprimer en toute sécurité l'activation du mode Observateur dans le code d'initialisation du SDK.
---
# File: kmp-sdk-migration-guides
---
---
title: "Guides de migration du SDK Kotlin Multiplatform"
description: "Guides de migration pour les versions du SDK Adapty Kotlin Multiplatform."
---
Cette page contient tous les guides de migration pour le SDK Adapty Kotlin Multiplatform. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir des instructions détaillées :
- **[Migrer vers la v4.0 (beta)](migration-to-kmp-sdk-v4)**
- **[Migrer vers la v3.15](migration-to-kmp-315)**
---
# File: migration-to-kmp-sdk-v4
---
---
title: "Migrer le SDK Kotlin Multiplatform Adapty vers la v4.0"
description: "Migrez vers le SDK Kotlin Multiplatform Adapty v4.0 (bêta) en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder."
---
Le SDK Kotlin Multiplatform Adapty 4.0 (bêta) introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent à la fois avec le nouveau Flow Builder et le Paywall Builder existant — aucune modification de configuration n'est requise côté Adapty Dashboard.
## Référence rapide \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` |
| `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` |
| `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` |
| `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` |
| `AdaptyPaywall` | `AdaptyFlow` |
| `AdaptyUI.createPaywallView(paywall, ...)` | `AdaptyUI.createFlowView(flow, ...)` |
| `AdaptyUI.createNativePaywallView(...)` → `AdaptyNativePaywallView` | `AdaptyUI.createNativeFlowView(...)` → `AdaptyNativeFlowView` |
| `AdaptyUIPaywallView` | `AdaptyUIFlowView` |
| `AdaptyUI.presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI.presentFlowView(view)` / `dismissFlowView(view)` |
| `AdaptyUI.setPaywallsEventsObserver(observer)` | `AdaptyUI.setFlowsEventsObserver(observer)` |
| `AdaptyUI.registerPaywallEventsListener` / `unregisterPaywallEventsListener` | `AdaptyUI.registerFlowEventsListener` / `unregisterFlowEventsListener` |
| `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` |
| `AdaptyUIPaywallPlatformView(paywall, ...)` | `AdaptyUIFlowPlatformView(flow, ...)` |
| `paywallViewDidPerformAction`, `paywallViewDidAppear` et autres callbacks `paywallView...` | `flowViewDidPerformAction`, `flowViewDidAppear` et autres callbacks `flowView...` |
| `paywallViewDidFailRendering` | `flowViewDidReceiveError` |
`AdaptyPaywallProduct` conserve son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` conserve également son nom, en prenant désormais un `AdaptyFlow`. Les méthodes `getFlow` et `getFlowForDefaultAudience` n'acceptent plus de paramètre `locale` — passez-le plutôt à `createFlowView`. Les APIs d'achat et de profil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) ainsi que `setFallback` conservent les mêmes signatures, mais le fichier de secours lui-même doit être retéléchargé — voir [Fichiers de secours](#fallback-files). Les méthodes d'onboarding fonctionnent toujours mais sont dépréciées — voir [Dépréciation de l'API d'onboarding](#onboarding-api-deprecation). Certains comportements par défaut ont changé — voir [Changements de comportement par défaut](#default-behavior-changes).
## Installation \{#installation\}
La v4.0 est une version préliminaire, donc épinglez la version exacte — Gradle ne sélectionne pas les versions préliminaires via les plages dynamiques :
```toml showLineNumbers title="libs.versions.toml"
[versions]
adapty-kmp = "4.0.1-beta.1"
[libraries]
adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" }
adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" }
```
Le module `adapty-kmp-ui` n'est nécessaire que si vous affichez des flows et des paywalls avec la couche Compose Multiplatform (`view.present()`). Consultez [Installer le SDK Adapty](sdk-installation-kotlin-multiplatform) pour la configuration complète.
Les SDK natifs Adapty sous-jacents sont mis à jour vers leurs versions 4.x sur les deux plateformes et sont résolus automatiquement — aucune modification de build n'est nécessaire. La cible de déploiement iOS reste **15.0**, inchangée dans cette version.
## Récupération des flows \{#fetching-flows\}
### getPaywall → getFlow
Le type retourné passe de `AdaptyPaywall` à `AdaptyFlow`, et le paramètre `locale` se déplace de l'appel de récupération vers `createFlowView` ; pour les paywalls personnalisés, toutes les locales sont retournées dans `flow.remoteConfigs` :
```diff showLineNumbers
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en")
- .onSuccess { paywall ->
- // use the paywall
+ Adapty.getFlow("YOUR_PLACEMENT_ID")
+ .onSuccess { flow ->
+ AdaptyUI.createFlowView(flow = flow, locale = "en")
}
.onError { error ->
// handle the error
}
```
`locale` reste optionnel sur `createFlowView` : omettez-le et la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne possède pas de version `en`. Voir [Localisations et codes de langue](kmp-localizations-and-locale-codes).
`getPaywallForDefaultAudience` est renommé de la même façon :
```diff showLineNumbers
- Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en")
+ Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID")
```
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` conserve son nom mais prend désormais un `AdaptyFlow` :
```diff showLineNumbers
- Adapty.getPaywallProducts(paywall)
+ Adapty.getPaywallProducts(flow)
.onSuccess { products ->
// use the products
}
```
### Fichiers de secours \{#fallback-files\}
Le format du fichier de secours [a changé dans le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le à votre application.
## Modèle de données \{#data-model\}
`getFlow` renvoie un `AdaptyFlow` à la place d'un `AdaptyPaywall`, et la structure de l'objet a changé :
| Propriété v3 `AdaptyPaywall` | Propriété v4 `AdaptyFlow` | Action |
|---|---|---|
| `remoteConfig: AdaptyRemoteConfig?` (unique) | `remoteConfigs: List` | Un flow contient une Remote Config par langue configurée. Lisez celle qui correspond à l'utilisateur : `flow.remoteConfigs.firstOrNull { it.locale == "en" }`. |
| _(nouveau)_ | `paywalls: List` | Chaque entrée est une variante de paywall dans le flow, avec son propre `name`, `variationId` et `productIdentifiers`. Les méthodes de paywall web prennent un `AdaptyFlowPaywall` — voir [Méthodes de paywall web](#web-paywall-methods). |
| `productIdentifiers` | déplacé | Les identifiants de produit se trouvent désormais sur chaque variante : `flow.paywalls[i].productIdentifiers`. Pour récupérer les produits, continuez d'appeler `getPaywallProducts(flow)`. |
| `hasViewConfiguration` | supprimé | Supprimez tout contrôle `hasViewConfiguration` de votre code — `createFlowView` renvoie une erreur à la place (voir [Affichage des flows](#displaying-flows)). |
`hasViewConfiguration` reste sur `AdaptyOnboarding` — seul le modèle de flow le supprime.
## Méthodes de paywall web \{#web-paywall-methods\}
`openWebPaywall` et `createWebPaywallUrl` conservent leurs noms, mais le paramètre `paywall` est remplacé par un paramètre `flowPaywall` qui prend un `AdaptyFlowPaywall` — l'une des variantes dans `flow.paywalls`. Vous pouvez toujours passer un `AdaptyPaywallProduct` à la place :
```diff showLineNumbers
- Adapty.openWebPaywall(paywall = paywall)
+ flow.paywalls.firstOrNull()?.let { flowPaywall ->
+ Adapty.openWebPaywall(flowPaywall = flowPaywall)
+ }
```
## Suivi des vues de flow \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` est renommé en `logShowFlow` et prend désormais un `AdaptyFlow`. L'événement est toujours enregistré pour la même variation, de sorte que les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord.
```diff showLineNumbers
- Adapty.logShowPaywall(paywall)
+ Adapty.logShowFlow(flow)
```
Comme en v3, vous n'avez pas besoin d'appeler cette méthode lors de l'affichage de flows ou de paywalls générés par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement.
## Affichage des flows \{#displaying-flows\}
### createPaywallView → createFlowView
Renommez la méthode factory et transmettez l'`AdaptyFlow`. Le type de vue renvoyé est renommé de `AdaptyUIPaywallView` en `AdaptyUIFlowView`, mais ses méthodes (`present`, `dismiss`) et les paramètres optionnels (`loadTimeout`, `preloadProducts`, `customTags`, `customTimers`, `customAssets`, `productPurchaseParams`) restent inchangés. Un paramètre optionnel est nouveau : `locale`, qui remplace le `locale` que vous passiez auparavant à `getPaywall` — voir [Récupérer les flows](#fetching-flows).
```diff showLineNumbers
- AdaptyUI.createPaywallView(paywall)
+ AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// handle the error
}
```
Si vous n'utilisez pas Compose Multiplatform, la méthode factory native est renommée de la même façon :
```diff showLineNumbers
- AdaptyUI.createNativePaywallView(paywall)
+ AdaptyUI.createNativeFlowView(flow)
```
`createFlowView` retourne un `AdaptyResult.Error` si le flow n'a pas de vue configurée — cela remplace la vérification `hasViewConfiguration` de la v3 :
```diff showLineNumbers
- if (paywall.hasViewConfiguration) {
- AdaptyUI.createPaywallView(paywall)
- .onSuccess { view -> view.present() }
- }
+ AdaptyUI.createFlowView(flow)
+ .onSuccess { view -> view.present() }
+ .onError { error ->
+ // the flow has no view configured, or view creation failed
+ }
```
:::note
Une vue de flow est à usage unique : après avoir appelé `dismiss()`, la vue est détruite. Appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois.
:::
## Gestion des événements \{#handling-events\}
L'observateur d'événements est renommé de `AdaptyUIPaywallsEventsObserver` en `AdaptyUIFlowsEventsObserver`, et ses callbacks remplacent le préfixe `paywallView` par `flowView`. Le contenu des handlers existants n'a pas besoin d'être modifié — il suffit de renommer le type et les overrides :
```diff showLineNumbers
- AdaptyUI.setPaywallsEventsObserver(object : AdaptyUIPaywallsEventsObserver {
- override fun paywallViewDidFinishPurchase(
- view: AdaptyUIPaywallView,
+ AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
+ override fun flowViewDidFinishPurchase(
+ view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
// custom logic after purchase
}
})
```
Un callback est également renommé : `paywallViewDidFailRendering` devient `flowViewDidReceiveError`. Il se déclenche pour les mêmes erreurs de rendu qu'auparavant, ainsi que pour d'autres erreurs d'exécution non liées aux achats :
```diff showLineNumbers
- override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {}
+ override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {}
```
Consultez [Gérer les événements flow et paywall](kmp-handling-events) pour la liste complète des callbacks.
### Vue de la plateforme Compose \{#compose-platform-view\}
Si vous intégrez des vues avec le composable Compose Multiplatform, `AdaptyUIPaywallPlatformView(paywall, ...)` est renommé en `AdaptyUIFlowPlatformView(flow, ...)`. Les callbacks d'événements conservent leurs noms `onDid...`, sauf `onDidFailRendering`, qui devient `onDidReceiveError` :
```diff showLineNumbers
- AdaptyUIPaywallPlatformView(
- paywall = paywall,
+ AdaptyUIFlowPlatformView(
+ flow = flow,
onDidFinishPurchase = { view, product, result -> /* ... */ },
)
```
Comme dans la v3, les callbacks que vous passez ici (et tout observateur enregistré via `registerFlowEventsListener`) s'exécutent **en plus** de l'observateur global, et non à sa place — votre callback observe un événement ; il ne remplace pas le comportement global par défaut. Gardez les [valeurs par défaut modifiées](#default-behavior-changes) à l'esprit : par exemple, le comportement global par défaut ne ferme plus la vue après un achat.
### Nouvelles API \{#new-apis\}
- `AdaptyUI.setObserverModeResolver(...)` avec un `AdaptyUIObserverModeResolver` — gère les achats et les restaurations initiés depuis les flows lorsque le SDK fonctionne en [mode Observateur](implement-observer-mode-kmp). Auparavant, cette fonctionnalité n'était disponible que dans les SDK natifs iOS et Android. Voir [Présenter des flows en mode Observateur](kmp-present-flows-in-observer-mode).
- `AdaptyUI.setSystemRequestsHandler(...)` avec un `AdaptyUISystemRequestsHandler` — réservé aux requêtes système d'un flow (invites de permissions OS et demandes d'évaluation de l'application). Les flows ne déclenchent pas encore ces requêtes, vous n'avez donc pas besoin d'enregistrer un handler.
- 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.
- `AdaptyUI.openWebUrl(url, openIn)` et `AdaptyUI.requestAppReview()` — ces méthodes servent la gestion par défaut de `OpenUrlAction` et le `handleAppReviewRequest` par défaut, afin que les URLs et les invites d'évaluation de l'application soient traitées nativement sans configuration supplémentaire. Appelez-les directement uniquement si vous remplacez ces comportements par défaut.
- `AdaptyUIFlowView.locale` — indique la localisation avec laquelle la vue a été construite, vous permettant de savoir quelle langue l'utilisateur voit réellement. Nécessite le SDK 4.0.1-beta.1 ou une version ultérieure.
- `AdaptyConfig.ServerCluster.CN` — une nouvelle option de cluster de serveurs aux côtés de `DEFAULT` et `EU`, pour connecter votre application aux [serveurs Adapty en Chine](china-cluster).
## Changements de comportement par défaut \{#default-behavior-changes\}
Ces changements ne génèrent pas d'erreurs de compilation, testez-les donc à l'exécution :
- **Finalisation d'achat** : En v3, le comportement par défaut de `paywallViewDidFinishPurchase` fermait la vue après tout résultat d'achat autre que `AdaptyPurchaseResult.UserCanceled`. En v4, le comportement par défaut de `flowViewDidFinishPurchase` ne fait rien, donc **un flow reste ouvert après un achat jusqu'à ce que vous le fermiez vous-même** — comme sur iOS. Si vous vous appuyiez sur cette fermeture automatique, appelez `view.dismiss()` une fois l'achat terminé.
- **Bouton retour Android** : En v3, le comportement par défaut de `paywallViewDidPerformAction` fermait la vue pour `CloseAction` et `AndroidSystemBackAction`. En v4, le comportement par défaut ne gère que `CloseAction` — **le bouton retour système ne ferme plus un flow automatiquement**, comme sur iOS où un flow ne peut pas être fermé par un geste système. Donnez aux utilisateurs un moyen explicite de sortir (un bouton **Close** ou une action `on_device_back`), ou fermez la vue vous-même dans `flowViewDidPerformAction`.
- **Erreurs de vue** : En v3, le comportement par défaut de `paywallViewDidFailRendering` ne faisait rien. En v4, le comportement par défaut de `flowViewDidReceiveError` **ferme la vue** — surchargez-le si vous souhaitez garder la vue ouverte ou gérer l'erreur différemment.
- **Les vues sont à usage unique** : Après `dismiss()`, la vue est détruite. Appelez à nouveau `createFlowView` pour afficher le flow une nouvelle fois.
## Dépréciation de l'API onboarding \{#onboarding-api-deprecation\}
L'ancienne API onboarding est dépréciée dans la v4.0 au profit du [Flow Builder](adapty-flow-builder). Elle fonctionne toujours, mais sera supprimée dans une prochaine version — prévoyez donc la migration de vos onboardings vers le Flow Builder.
Symboles dépréciés : `getOnboarding`, `getOnboardingForDefaultAudience`, `AdaptyUI.createOnboardingView`, `AdaptyUI.createNativeOnboardingView` et `AdaptyUIOnboardingsEventsObserver`.
---
# File: migration-to-kmp-315
---
---
title: "Guide de migration vers Adapty Kotlin Multiplatform SDK 3.15.0"
description: "Étapes de migration pour Adapty Kotlin Multiplatform SDK 3.15.0"
---
Adapty Kotlin Multiplatform SDK 3.15.0 est une version majeure qui apporte de nouvelles fonctionnalités et améliorations, mais qui peut nécessiter certaines étapes de migration de votre part.
1. Mettez à jour les noms de la classe et des méthodes de l'observer.
2. Mettez à jour le nom de la méthode des paywalls de secours.
3. Mettez à jour le nom de la classe de vue dans les méthodes de gestion des événements.
## Mettre à jour les noms de la classe 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
- import com.adapty.kmp.AdaptyUIObserver
+ import com.adapty.kmp.AdaptyUIPaywallsEventsObserver
- import com.adapty.kmp.models.AdaptyUIView
+ import com.adapty.kmp.models.AdaptyUIPaywallView
- class MyAdaptyUIObserver : AdaptyUIObserver {
- override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) {
+ class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver {
+ override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) {
// handle actions
}
}
// Set up the observer
- AdaptyUI.setObserver(MyAdaptyUIObserver())
+ AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver())
```
## Mise à jour du nom de méthode pour les paywalls de secours \{#update-fallback-paywalls-method-name\}
Le nom de la méthode pour définir les paywalls de secours a été modifié :
```diff showLineNumbers
- Adapty.setFallbackPaywalls(assetId = "fallback.json")
+ Adapty.setFallback(assetId = "fallback.json")
.onSuccess {
// Fallback paywalls loaded successfully
}
.onError { error ->
// Handle the error
}
```
## Mettre à jour le nom de classe de la vue dans les méthodes de gestion des événements \{#update-view-class-name-in-event-handling-methods\}
Toutes les méthodes de gestion des événements utilisent désormais la nouvelle classe `AdaptyUIPaywallView` au lieu de `AdaptyUIView` :
```diff
- override fun paywallViewDidAppear(view: AdaptyUIView) {
+ override fun paywallViewDidAppear(view: AdaptyUIPaywallView) {
// Handle paywall appearance
}
- override fun paywallViewDidDisappear(view: AdaptyUIView) {
+ override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) {
// Handle paywall disappearance
}
- override fun paywallViewDidSelectProduct(view: AdaptyUIView, productId: String) {
+ override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) {
// Handle product selection
}
- override fun paywallViewDidStartPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct) {
+ override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) {
// Handle purchase start
}
- override fun paywallViewDidFinishPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) {
+ override fun paywallViewDidFinishPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) {
// Handle purchase result
}
- override fun paywallViewDidFailPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, error: AdaptyError) {
+ override fun paywallViewDidFailPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, error: AdaptyError) {
// Add your purchase failure handling logic here
}
- override fun paywallViewDidFinishRestore(view: AdaptyUIView, profile: AdaptyProfile) {
+ override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) {
// Add your successful restore handling logic here
}
- override fun paywallViewDidFailRestore(view: AdaptyUIView, error: AdaptyError) {
+ override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your restore failure handling logic here
}
- override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIView, product: AdaptyPaywallProduct?, error: AdaptyError?) {
+ override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct?, error: AdaptyError?) {
// Handle web payment navigation result
}
- override fun paywallViewDidFailLoadingProducts(view: AdaptyUIView, error: AdaptyError) {
+ override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your product loading failure handling logic here
}
- override fun paywallViewDidFailRendering(view: AdaptyUIView, error: AdaptyError) {
+ override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {
// Handle rendering error
}
```
---
# End of Documentation
_Generated on: 2026-08-11T07:13:23.540Z_
_Successfully processed: 48/48 files_